summaryrefslogtreecommitdiff
path: root/java/src/IceUtil/Options.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/IceUtil/Options.java')
-rw-r--r--java/src/IceUtil/Options.java228
1 files changed, 225 insertions, 3 deletions
diff --git a/java/src/IceUtil/Options.java b/java/src/IceUtil/Options.java
index 39bb305db1a..7db0c20ed8d 100644
--- a/java/src/IceUtil/Options.java
+++ b/java/src/IceUtil/Options.java
@@ -27,6 +27,7 @@ public final class Options
final int NormalState = 1;
final int DoubleQuoteState = 2;
final int SingleQuoteState = 3;
+ final int ANSIQuoteState = 4;
line = line.trim();
@@ -48,12 +49,35 @@ public final class Options
{
//
// Ignore a backslash at the end of the string,
- // and strip backslash-newline pairs. Anything
- // else following a backslash is taken literally.
+ // and strip backslash-newline pairs. If a
+ // backslash is followed by a space, single quote,
+ // double quote, or dollar sign, we drop the backslash
+ // and write the space, single quote, double quote,
+ // or dollar sign. This is necessary to allow quotes
+ // to be escaped. Dropping the backslash preceding a
+ // space deviates from bash quoting rules, but is
+ // necessary so we don't drop backslashes from Windows
+ // path names.)
//
if(i < line.length() - 1 && line.charAt(++i) != '\n')
{
- arg.append(line.charAt(i));
+ switch(line.charAt(i))
+ {
+ case ' ':
+ case '$':
+ case '\\':
+ case '"':
+ {
+ arg.append(line.charAt(i));
+ break;
+ }
+ default:
+ {
+ arg.append('\\');
+ arg.append(line.charAt(i));
+ break;
+ }
+ }
}
break;
}
@@ -67,6 +91,19 @@ public final class Options
state = DoubleQuoteState;
break;
}
+ case '$':
+ {
+ if(i < line.length() - 1 && line.charAt(i + 1) == '\'')
+ {
+ state = ANSIQuoteState; // Bash uses $'<text>' to allow ANSI escape sequences within <text>.
+ ++i;
+ }
+ else
+ {
+ arg.append('$');
+ }
+ break;
+ }
default:
{
if(IFS.indexOf(line.charAt(i)) != -1)
@@ -138,6 +175,191 @@ public final class Options
}
break;
}
+ case ANSIQuoteState:
+ {
+ switch(c)
+ {
+ case '\\':
+ {
+ if(i == line.length() - 1)
+ {
+ break;
+ }
+ switch(c = line.charAt(++i))
+ {
+ //
+ // Single-letter escape sequences.
+ //
+ case 'a':
+ {
+ arg.append('\007');
+ break;
+ }
+ case 'b':
+ {
+ arg.append('\b');
+ break;
+ }
+ case 'f':
+ {
+ arg.append('\f');
+ break;
+ }
+ case 'n':
+ {
+ arg.append('\n');
+ break;
+ }
+ case 'r':
+ {
+ arg.append('\r');
+ break;
+ }
+ case 't':
+ {
+ arg.append('\t');
+ break;
+ }
+ case 'v':
+ {
+ arg.append('\013');
+ break;
+ }
+ case '\\':
+ {
+ arg.append('\\');
+ break;
+ }
+ case '\'':
+ {
+ arg.append('\'');
+ break;
+ }
+ case 'e': // Not ANSI-C, but used by bash.
+ {
+ arg.append('\033');
+ break;
+ }
+
+ //
+ // Process up to three octal digits.
+ //
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ final String octalDigits = "01234567";
+ short us = 0;
+ int j;
+ for(j = i;
+ j < i + 3 && j < line.length() && octalDigits.indexOf(c = line.charAt(j)) != -1;
+ ++j)
+ {
+ us = (short)(us * 8 + c - '0');
+ }
+ i = j - 1;
+ arg.append((char)us);
+ break;
+ }
+
+ //
+ // Process up to two hex digits.
+ //
+ case 'x':
+ {
+ final String hexDigits = "0123456789abcdefABCDEF";
+ if(i < line.length() - 1 && hexDigits.indexOf(line.charAt(i + 1)) == -1)
+ {
+ arg.append('\\');
+ arg.append('x');
+ break;
+ }
+
+ short s = 0;
+ int j;
+ for(j = i + 1;
+ j < i + 3 && j < line.length() && hexDigits.indexOf(c = line.charAt(j)) != -1;
+ ++j)
+ {
+ s *= 16;
+ if(Character.isDigit(c))
+ {
+ s += (short)(c - '0');
+ }
+ else if(Character.isLowerCase(c))
+ {
+ s += (short)(c - 'a' + 10);
+ }
+ else
+ {
+ s += (short)(c - 'A' + 10);
+ }
+ }
+ i = j - 1;
+ arg.append((char)s);
+ break;
+ }
+
+ //
+ // Process control-chars.
+ //
+ case 'c':
+ {
+ c = line.charAt(++i);
+ if((Character.toUpperCase(c) >= 'A' && Character.toUpperCase(c) <= 'Z') ||
+ c == '@' ||
+ (c >= '[' && c <= '_'))
+ {
+ arg.append((char)(Character.toUpperCase(c) - '@'));
+ }
+ else
+ {
+ //
+ // Bash does not define what should happen if a \c
+ // is not followed by a recognized control character.
+ // We simply treat this case like other unrecognized
+ // escape sequences, that is, we preserve the escape
+ // sequence unchanged.
+ //
+ arg.append('\\');
+ arg.append('c');
+ arg.append(c);
+ }
+ break;
+ }
+
+ //
+ // If inside an ANSI-quoted string, a backslash isn't followed by
+ // one of the recognized characters, both the backslash and the
+ // character are preserved.
+ //
+ default:
+ {
+ arg.append('\\');
+ arg.append(c);
+ break;
+ }
+ }
+ break;
+ }
+ case '\'': // End of ANSI-quote mode.
+ {
+ state = NormalState;
+ break;
+ }
+ default:
+ {
+ arg.append(c); // Everything else is taken literally.
+ break;
+ }
+ }
+ break;
+ }
default:
assert(false);
break;