Category talk:Wren-ioutil: Difference between revisions

→‎Source code: Added Input.readHexBytes method.
(Added source code for new 'Wren-ioutil' module.)
 
(→‎Source code: Added Input.readHexBytes method.)
 
(9 intermediate revisions by the same user not shown)
Line 1:
===Source code===
 
<langsyntaxhighlight ecmascriptlang="wren">/* Module "ioutil.wren" */
 
import "io" for File, FileFlags, Stdin, Stdout
Line 23:
// The files must exist and not be the same file.
// Use only if the entire contents of both files can be held temporarily in memory.
static areDuplicates(path1, path2) { !areSamefileareSameFile(path1, path2) && read(path1) == read(path2) }
 
// Private worker method for copying files.
Line 280:
/* Input supplements Stdin with some additional methods for reading user input. */
class Input {
// Gets or sets the string to be used to quit input - null by default.
static quit { __quit }
static quit=(q) { __quit = (q is String) ? q : q.toString }
 
// Prompts the user to enter some text and returns it.
static text(prompt) {
Line 294 ⟶ 298:
while (true) {
Output.fwrite(prompt)
var text = Stdin.readlinereadLine()
if (text == __quit) return text
if (text.count < minLen) {
System.print("Must have a minimum length of %(minLen) characters, try again.")
Line 311 ⟶ 316:
while (true) {
Output.fwrite(prompt)
var text = Stdin.readlinereadLine()
if (text == __quit) return text
if (text.count < minLen || text.count > maxLen) {
if (maxLen > minLen) {
Line 326 ⟶ 332:
while (true) {
Output.fwrite(prompt)
var numbertext = Num.fromString(Stdin.readLine())
if (text == __quit) return text
var number = Num.fromString(text.trim())
if (!number) {
System.print("Must be a number, try again.")
Line 338 ⟶ 346:
while (true) {
Output.fwrite(prompt)
var numbertext = Num.fromString(Stdin.readLine())
if (text == __quit) return text
var number = Num.fromString(text.trim())
if (!number || number < min) {
System.print("Must be a number no less than %(min), try again.")
Line 353 ⟶ 363:
while (true) {
Output.fwrite(prompt)
var numbertext = Num.fromString(Stdin.readLine())
if (text == __quit) return text
var number = Num.fromString(text.trim())
if (!number || number < min || number > max) {
System.print("Must be a number between %(min) and %(max), try again.")
Line 364 ⟶ 376:
while (true) {
Output.fwrite(prompt)
var integertext = Num.fromString(Stdin.readLine())
if (text == __quit) return text
var integer = Num.fromString(text.trim())
if (!integer || !integer.isInteger) {
System.print("Must be an integer, try again.")
Line 376 ⟶ 390:
while (true) {
Output.fwrite(prompt)
var integertext = Num.fromString(Stdin.readLine())
if (text == __quit) return text
var integer = Num.fromString(text.trim())
if (!integer || !integer.isInteger || integer < min) {
System.print("Must be an integer no less than %(min), try again.")
Line 391 ⟶ 407:
while (true) {
Output.fwrite(prompt)
var integertext = Num.fromString(Stdin.readLine())
if (text == __quit) return text
var integer = Num.fromString(text.trim())
if (!integer || !integer.isInteger || integer < min || integer > max) {
System.print("Must be an integer between %(min) and %(max), try again.")
Line 408 ⟶ 426:
Output.fwrite(prompt)
var option = Stdin.readLine()
if (option == __quit) return option
if (option.count == 0) {
System.print("Option must have (at least) one character, try again")
Line 427 ⟶ 446:
while (true) {
Output.fwrite(prompt)
var option = Stdin.readLine().trim()
if (option == __quit) return option
option = option.trim()
if (!options.contains(option)) {
System.print("Must be one of %(options), try again.")
Line 442 ⟶ 463:
while (true) {
Output.fwrite(prompt)
var option = Num.fromString(Stdin.readLine())
if (option == __quit) return option
option = Num.fromString(option.trim())
if (!option || !options.contains(option)) {
System.print("Must be one of %(options), try again.")
Line 457 ⟶ 480:
while (true) {
Output.fwrite(prompt)
var option = Num.fromString(Stdin.readLine())
if (option == __quit) return option
option = Num.fromString(option.trim())
if (!option || !option.isInteger || !options.contains(option)) {
System.print("Must be one of %(options), try again.")
Line 463 ⟶ 488:
}
}
 
// Prompts the user to enter a password with a minimum/maximum length and returns it.
// Only printable ASCII characters other than space are valid or if 'allowSymbols' is
// false, only ASCII alphanumeric characters. Other characters, except
// ENTER, BACKSPACE, CTRL-C and CTRL-D which behave normally, are ignored.
// Valid characters are replaced with bullets as they are typed though any attempt
// to type characters beyond the maximum length is ignored.
static password(prompt, minLen, maxLen, allowSymbols) {
if (minLen.type != Num || !minLen.isInteger || minLen < 0) {
Fiber.abort("Minimum length must be a non-negative integer.")
}
if (maxLen.type != Num || !maxLen.isInteger || maxLen < minLen) {
Fiber.abort("Maximum length must not be less than minimum length.")
}
Stdin.isRaw = true
var alphanum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var pwd = ""
Output.fwrite(prompt)
while (true) {
var byte = Stdin.readByte()
if (byte > 32 && byte < 127) {
if (pwd.count < maxLen) {
var char = String.fromByte(byte)
if (allowSymbols || alphanum.indexOf(char) != -1) {
Output.fwrite("•")
pwd = pwd + char
}
}
} else if (byte == 8 || byte == 127) {
if (pwd.count > 0) {
Output.fwrite("\b \b")
pwd = pwd[0...-1]
}
} else if (byte == 10 || byte == 13) {
if (pwd != __quit && pwd.count < minLen) {
System.print("\nMinimum length is %(minLen) characters, try again.")
pwd = ""
Output.fwrite(prompt)
} else {
Stdin.isRaw = false
System.print()
return pwd
}
} else if (byte == 3 || byte == 4) {
Stdin.isRaw = false
if (byte == 3) {
System.print("^C")
} else {
System.print("Stdin was closed.")
}
Fiber.abort("")
}
}
}
 
// Convenience version of the above method which always allows symbols.
static password(prompt, minLen, maxLen) { password(prompt, minLen, maxLen, true) }
 
// Reads 1, 2, 3 or 4 hex bytes (2 digits per byte, upper/lower case a-f, big endian)
// entered at the terminal and returns the decimal value of the byte group entered.
// Returns -1 if the return key is pressed after a byte group to signify end of input.
// Returns -2 if the space or tab key is pressed afer a byte group which enables
// calling code to skip intervening whitespace.
// Pressing these keys in the middle of byte groups or entering other non-hex
// characters is an error.
static readHexBytes(nBytes) {
if (!(1..4).contains(nBytes)) {
Fiber.abort("Invalid value for nBytes, must be 1, 2, 3 or 4.")
}
var nDigits = nBytes * 2
var hl = List.filled(nDigits, 0)
for (i in 0...nDigits) {
var h = Stdin.readByte()
if (h == 10) {
if (i == 0) return -1
Fiber.abort("Invalid hex digit entered.")
}
if (h == 32 || h == 9) {
if (i == 0) return -2
Fiber.abort("Invalid hex digit entered.")
}
if (h >= 48 && h <= 57) {
h = h - 48
} else if (h >= 97 && h <= 102) {
h = h - 87
} else if (h >= 65 && h <= 70) {
h = h - 55
} else {
Fiber.abort("Invalid hex digit entered.")
}
hl[i] = h
}
var sum = hl[0]
for (i in 1...hl.count) sum = sum * 16 + hl[i]
return sum
}
 
// Convenience version of readHexBytes method which reads a single hex byte.
static readHexByte() { readHexBytes(1) }
}
 
Line 480 ⟶ 604:
Stdout.flush()
}
}</syntaxhighlight>
}
 
// Type aliases for classes in case of any name clashes with other modules.
var IOutil_FileUtil = FileUtil
var IOutil_Input = Input
var IOutil_Output = Output
var IOutil_File = File // in case imported indirectly
var IOUtil_FileFlags = FileFlags // ditto
var IOUtil_Stdin = Stdin // ditto
var IOUtil_Stdout = Stdout // ditto
var IOUtil_Platform = Platform // ditto</lang>
9,479

edits