Initial draft for porting this project to Gradle + Kotlin
This is one of my stupidest idea ever.
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.Arrays
|
||||
import java.util.StringTokenizer
|
||||
|
||||
/**
|
||||
* Commandline objects help handling command lines specifying processes to
|
||||
* execute.
|
||||
*
|
||||
* The class can be used to define a command line as nested elements or as a
|
||||
* helper to define a command line by an application.
|
||||
*
|
||||
*
|
||||
* `
|
||||
* <someelement><br></br>
|
||||
* <acommandline executable="/executable/to/run"><br></br>
|
||||
* <argument value="argument 1" /><br></br>
|
||||
* <argument line="argument_1 argument_2 argument_3" /><br></br>
|
||||
* <argument value="argument 4" /><br></br>
|
||||
* </acommandline><br></br>
|
||||
* </someelement><br></br>
|
||||
` *
|
||||
*
|
||||
* Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java
|
||||
*
|
||||
* Adds support for escape character '\'.
|
||||
*/
|
||||
object Commandline {
|
||||
|
||||
/**
|
||||
* Quote the parts of the given array in way that makes them
|
||||
* usable as command line arguments.
|
||||
* @param args the list of arguments to quote.
|
||||
* @return empty string for null or no command, else every argument split
|
||||
* by spaces and quoted by quoting rules.
|
||||
*/
|
||||
fun toString(args: Iterable<String>?): String {
|
||||
// empty path return empty string
|
||||
if (args == null) {
|
||||
return ""
|
||||
}
|
||||
// path containing one or more elements
|
||||
val result = StringBuilder()
|
||||
for (arg in args) {
|
||||
if (result.isNotEmpty()) result.append(' ')
|
||||
(0 until arg.length)
|
||||
.map { arg[it] }
|
||||
.forEach {
|
||||
when (it) {
|
||||
' ', '\\', '"', '\'' -> {
|
||||
result.append('\\') // intentionally no break
|
||||
result.append(it)
|
||||
}
|
||||
else -> result.append(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Quote the parts of the given array in way that makes them
|
||||
* usable as command line arguments.
|
||||
* @param args the list of arguments to quote.
|
||||
* @return empty string for null or no command, else every argument split
|
||||
* by spaces and quoted by quoting rules.
|
||||
*/
|
||||
fun toString(args: Array<String>): String {
|
||||
return toString(Arrays.asList(*args)) // thanks to Java, arrays aren't iterable
|
||||
}
|
||||
|
||||
/**
|
||||
* Crack a command line.
|
||||
* @param toProcess the command line to process.
|
||||
* @return the command line broken into strings.
|
||||
* An empty or null toProcess parameter results in a zero sized array.
|
||||
*/
|
||||
fun translateCommandline(toProcess: String?): Array<String> {
|
||||
if (toProcess == null || toProcess.isEmpty()) {
|
||||
//no command? no string
|
||||
return arrayOf()
|
||||
}
|
||||
// parse with a simple finite state machine
|
||||
|
||||
val normal = 0
|
||||
val inQuote = 1
|
||||
val inDoubleQuote = 2
|
||||
var state = normal
|
||||
val tok = StringTokenizer(toProcess, "\\\"\' ", true)
|
||||
val result = ArrayList<String>()
|
||||
val current = StringBuilder()
|
||||
var lastTokenHasBeenQuoted = false
|
||||
var lastTokenIsSlash = false
|
||||
|
||||
while (tok.hasMoreTokens()) {
|
||||
val nextTok = tok.nextToken()
|
||||
when (state) {
|
||||
inQuote -> if ("\'" == nextTok) {
|
||||
lastTokenHasBeenQuoted = true
|
||||
state = normal
|
||||
} else {
|
||||
current.append(nextTok)
|
||||
}
|
||||
inDoubleQuote -> if ("\"" == nextTok) {
|
||||
if (lastTokenIsSlash) {
|
||||
current.append(nextTok)
|
||||
lastTokenIsSlash = false
|
||||
} else {
|
||||
lastTokenHasBeenQuoted = true
|
||||
state = normal
|
||||
}
|
||||
} else if ("\\" == nextTok) {
|
||||
lastTokenIsSlash = if (lastTokenIsSlash) {
|
||||
current.append(nextTok)
|
||||
false
|
||||
} else
|
||||
true
|
||||
} else {
|
||||
if (lastTokenIsSlash) {
|
||||
current.append("\\") // unescaped
|
||||
lastTokenIsSlash = false
|
||||
}
|
||||
current.append(nextTok)
|
||||
}
|
||||
else -> {
|
||||
if (lastTokenIsSlash) {
|
||||
current.append(nextTok)
|
||||
lastTokenIsSlash = false
|
||||
} else if ("\\" == nextTok)
|
||||
lastTokenIsSlash = true
|
||||
else if ("\'" == nextTok) {
|
||||
state = inQuote
|
||||
} else if ("\"" == nextTok) {
|
||||
state = inDoubleQuote
|
||||
} else if (" " == nextTok) {
|
||||
if (lastTokenHasBeenQuoted || current.isNotEmpty()) {
|
||||
result.add(current.toString())
|
||||
current.setLength(0)
|
||||
}
|
||||
} else {
|
||||
current.append(nextTok)
|
||||
}
|
||||
lastTokenHasBeenQuoted = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastTokenHasBeenQuoted || current.isNotEmpty()) {
|
||||
result.add(current.toString())
|
||||
}
|
||||
if (state == inQuote || state == inDoubleQuote) {
|
||||
throw IllegalArgumentException("unbalanced quotes in " + toProcess)
|
||||
}
|
||||
if (lastTokenIsSlash) throw IllegalArgumentException("escape character following nothing in " + toProcess)
|
||||
return result.toTypedArray()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user