///|
fn ascii_upper(s : String) -> String {
let b = StringBuilder::new()
let mut i = 0
while i < s.length() {
b.write_char(s[i].unsafe_to_char().to_ascii_uppercase())
i += 1
}
b.to_string()
}
///|
fn trim_ascii(s : String) -> String {
let mut start = 0
let mut end = s.length()
while start < end && is_space_code(s[start]) {
start += 1
}
while end > start && is_space_code(s[end - 1]) {
end -= 1
}
s[start:end].to_owned()
}
///|
fn is_space_code(code : UInt16) -> Bool {
code == 32 || code == 9 || code == 10 || code == 13
}
///|
fn split_by_char(s : String, sep : UInt16) -> Array[String] {
let out : Array[String] = []
let mut start = 0
let mut i = 0
while i < s.length() {
if s[i] == sep {
out.push(s[start:i].to_owned())
start = i + 1
}
i += 1
}
out.push(s[start:s.length()].to_owned())
out
}
///|
/// Split a parameter head/value without treating separators inside quotes as
/// delimiters. Property values themselves intentionally use split_by_char.
fn split_quoted(s : String, sep : UInt16) -> Array[String] {
let out : Array[String] = []
let mut start = 0
let mut quoted = false
let mut escaped = false
let mut i = 0
while i < s.length() {
let code = s[i]
if escaped {
escaped = false
} else if code == 92 {
escaped = true
} else if code == 34 {
quoted = !quoted
} else if code == sep && !quoted {
out.push(s[start:i].to_owned())
start = i + 1
}
i += 1
}
out.push(s[start:s.length()].to_owned())
out
}
///|
fn index_of_char(s : String, sep : UInt16) -> Int {
let mut i = 0
while i < s.length() {
if s[i] == sep {
return i
}
i += 1
}
-1
}
///|
fn valid_token(s : String) -> Bool {
if s.length() == 0 {
return false
}
let mut i = 0
while i < s.length() {
let c = s[i]
let upper = c >= 65 && c <= 90
let lower = c >= 97 && c <= 122
let digit = c >= 48 && c <= 57
if !(upper || lower || digit || c == 45) {
return false
}
i += 1
}
true
}
///|
fn split_physical_lines(input : String) -> Array[String] {
let lines : Array[String] = []
let mut start = 0
let mut i = 0
while i < input.length() {
if input[i] == 10 {
let mut end = i
if end > start && input[end - 1] == 13 {
end -= 1
}
lines.push(input[start:end].to_owned())
start = i + 1
}
i += 1
}
if start < input.length() {
let mut end = input.length()
if end > start && input[end - 1] == 13 {
end -= 1
}
lines.push(input[start:end].to_owned())
}
lines
}
///|
fn unfold_lines(input : String) -> Array[String] raise CalError {
let physical = split_physical_lines(input)
let logical : Array[String] = []
let mut physical_line = 1
for line in physical {
if line.length() > 0 && (line[0] == 32 || line[0] == 9) {
if logical.length() == 0 {
raise BadPropertyName(physical_line, line)
} else {
let last = logical.length() - 1
logical[last] = logical[last] + line[1:line.length()].to_owned()
}
} else if line.length() > 0 {
logical.push(line)
}
physical_line += 1
}
logical
}
///|
fn escape_text(s : String) -> String {
let b = StringBuilder::new()
let mut i = 0
while i < s.length() {
let c = s[i]
if c == 92 {
b.write_string("\\\\")
} else if c == 44 {
b.write_string("\\,")
} else if c == 59 {
b.write_string("\\;")
} else if c == 10 {
b.write_string("\\n")
} else {
b.write_char(c.unsafe_to_char())
}
i += 1
}
b.to_string()
}
///|
fn unescape_text(s : String) -> String {
let b = StringBuilder::new()
let mut i = 0
while i < s.length() {
if s[i] == 92 && i + 1 < s.length() {
let n = s[i + 1]
if n == 110 || n == 78 {
b.write_char('\n')
} else {
b.write_char(n.unsafe_to_char())
}
i += 2
} else {
b.write_char(s[i].unsafe_to_char())
i += 1
}
}
b.to_string()
}