comparison src/main/kotlin/name/blackcap/passman/See.kt @ 5:ad997df1f560

Fix see() to be about as good as sccc.
author David Barts <n5jrn@me.com>
date Sun, 11 Sep 2022 21:29:20 -0700
parents 02b101422726
children 72619175004e
comparison
equal deleted inserted replaced
4:02b101422726 5:ad997df1f560
1 package name.blackcap.passman 1 package name.blackcap.passman
2
3 /* Would be nice if there was a more programmatic and comprehensive way of
4 doing this, but alas. Even the oft-recommended StringEscapeUtils does
5 something cruder than the below. Le sigh. */
6 2
7 import java.util.Formatter 3 import java.util.Formatter
8 4
9 private const val DELIM = '"' 5 private const val DELIM = '"'
10 private const val SHY = '\u00ad' 6 private val ALWAYS_ALLOW = setOf<Char>(' ')
11 7 private val ALWAYS_BAN = setOf<Char>(DELIM, '\\')
8 private val FORBIDDEN = setOf<Byte>(Character.CONTROL, Character.FORMAT,
9 Character.SURROGATE, Character.PRIVATE_USE, Character.UNASSIGNED,
10 Character.SPACE_SEPARATOR)
12 private val STD_ESC_MAP = mapOf<Char, Char>('\t' to 't', '\b' to 'b', '\n' to 'n', 11 private val STD_ESC_MAP = mapOf<Char, Char>('\t' to 't', '\b' to 'b', '\n' to 'n',
13 '\r' to 'r', '\u000c' to 'f', '"' to '"', '\\' to '\\') 12 '\r' to 'r', '\u000c' to 'f', '"' to '"', '\\' to '\\')
14 private val BANNED = setOf<Char>(DELIM, SHY, '\\')
15 private const val MIN_ASCII = ' '
16 private const val MAX_ASCII = '~'
17 private const val MIN_8859 = '\u00a1'
18 private const val MAX_8859 = '\u00ff'
19 13
20 fun see(input: String, simple: Boolean = false): String = 14 fun see(input: String): String {
21 if (simple) seeSimple(input) else seeAggressive(input)
22
23 private fun seeSimple(input: String): String = StringBuilder().run {
24 append(DELIM)
25 append(input)
26 append(DELIM)
27 toString()
28 }
29
30 private fun seeAggressive(input: String): String {
31 val accum = Formatter() 15 val accum = Formatter()
32 accum.format("%c", DELIM) 16 accum.format("%c", DELIM)
33 for (ch in input) { 17 for (ch in input) {
34 if ((ch !in BANNED) && ((ch in MIN_ASCII..MAX_ASCII) || (ch in MIN_8859 .. MAX_8859))) { 18 if (ch in ALWAYS_ALLOW) {
35 accum.format("%c", ch) 19 accum.format("%c", ch)
36 continue 20 continue
37 } 21 }
38 val mapped = STD_ESC_MAP[ch] 22 if (ch in ALWAYS_BAN || Character.getType(ch).toByte() in FORBIDDEN) {
39 if (mapped != null) { 23 val mapped = STD_ESC_MAP[ch]
40 accum.format("\\%c", mapped) 24 if (mapped != null) {
41 } else { 25 accum.format("\\%c", mapped)
42 accum.format("\\u%04x", ch.code) 26 } else {
27 accum.format("\\u%04x", ch.code)
28 }
29 continue
43 } 30 }
31 accum.format("%c", ch)
44 } 32 }
45 accum.format("%c", DELIM) 33 accum.format("%c", DELIM)
46 return accum.toString() 34 return accum.toString()
47 } 35 }