Files
swift-mirror/stdlib/core/OutputStream.swift
2013-06-28 02:31:01 +00:00

370 lines
8.8 KiB
Swift

//===----------------------------------------------------------------------===//
// OutputStream and Formatting logic
//===----------------------------------------------------------------------===//
extension Bool : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
alwaysTrap(kind == 'v')
return Format(layout).printToString(String(this))
}
}
extension Int8 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
return Int64(this).format(kind, layout)
}
}
extension UInt8 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
return UInt64(this).format(kind, layout)
}
}
extension Int16 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
return Int64(this).format(kind, layout)
}
}
extension UInt16 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
return UInt64(this).format(kind, layout)
}
}
extension Int32 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
return Int64(this).format(kind, layout)
}
}
extension UInt32 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
return UInt64(this).format(kind, layout)
}
}
extension Int64 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
var radix = 10
var uppercase = false
if kind == 'X' { uppercase = true; radix = 16 }
else if kind == 'x' { radix = 16 }
else if kind == 'o' { radix = 8 }
else if kind != 'v' { alwaysTrap() }
return Format(layout).printToString(
String(this, radix : radix, uppercase : uppercase))
}
}
extension UInt64 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
var radix = 10
var uppercase = false
if kind == 'X' { uppercase = true; radix = 16 }
else if kind == 'x' { radix = 16 }
else if kind == 'o' { radix = 8 }
else if kind != 'v' { alwaysTrap() }
return Format(layout).printToString(
String(this, radix : radix, uppercase : uppercase))
}
}
extension Int128 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
var radix = 10
var uppercase = false
if kind == 'X' { uppercase = true; radix = 16 }
else if kind == 'x' { radix = 16 }
else if kind == 'o' { radix = 8 }
else if kind != 'v' { alwaysTrap() }
return Format(layout).printToString(
String(this, radix : radix, uppercase : uppercase))
}
}
extension UInt128 : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
var radix = 10
var uppercase = false
if kind == 'X' { uppercase = true; radix = 16 }
else if kind == 'x' { radix = 16 }
else if kind == 'o' { radix = 8 }
else if kind != 'v' { alwaysTrap() }
return Format(layout).printToString(
String(this, radix : radix, uppercase : uppercase))
}
}
extension Float : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
alwaysTrap(kind == 'v')
return Format(layout).printToString(String(this))
}
}
extension Double : FormattedPrintable {
func format(kind : Char, layout : String) -> String {
alwaysTrap(kind == 'v')
return Format(layout).printToString(String(this))
}
}
//===----------------------------------------------------------------------===//
// Formatted Printing
//===----------------------------------------------------------------------===//
struct Format {
var width : Int
var isValid : Bool
var leftJustify : Bool
constructor(layout : String) {
isValid = true
leftJustify = false
width = 0
if !layout.isEmpty() {
if layout[0] == '-' {
leftJustify = true
layout = layout.substr(1)
}
if !layout.isEmpty() {
for c in layout.chars {
if !c.isDigit() {
isValid = false
break
}
width = width * 10 + Int(UInt32(c) - UInt32('0'))
}
}
}
}
func printString(s : String) {
/* Causes problems due to <rdar://problem/11529601>
if !isValid {
print(s)
return
}
*/
var padding = max(width - s.size(), 0)
if !leftJustify {
for i in 0..padding { print(' ') }
}
print(s)
if leftJustify {
for i in 0..padding { print(' ') }
}
}
func printToString(s : String) -> String {
if !isValid {
return s
}
var r : String
var padding = max(width - s.size(), 0)
if !leftJustify {
r = String(padding, ' ')
}
r = r + s
if leftJustify {
r = r + String(padding, ' ')
}
return r
}
func replPrint() {
print("valid = \(isValid), leftJustify = \(leftJustify), width=\(width)")
}
}
// Terminal input & output
class Console : Object {
func write(buf : UInt8[]) -> Int {
var r = posix_write(1, buf.base.value, buf.length)
alwaysTrap(r != -1)
return r
}
func write(buf : String) -> Int {
var r = posix_write(1, buf.str_value.base.value, buf.length)
alwaysTrap(r != -1)
return r
}
func write(c : UInt8) {
var buf = new UInt8[1]
buf[0] = c
var r = write(buf)
alwaysTrap(r == 1)
}
}
var con : Console = Console()
protocol FormattedPrintable {
func format(kind : Char, layout : String) -> String
}
func splitFormat(format : String) -> (String, String, Char, String) {
var (before, afterPercent, foundPercent) = format.splitFirst('%')
if !foundPercent {
return (before, "", Char(0), afterPercent)
}
var (layout, kind, after, found) = afterPercent.splitFirstIf({ $0.isAlpha() })
if !found {
return (before, "", Char(0), afterPercent)
}
return (before, layout, kind, after)
}
protocol OutputStreamable {
func write(buf : UInt8[]) -> Int
// FIXME: Add default implementation when language allows it:
func write(buf : String) -> Int
// {return write(buf.asUInt8())}
}
// FIXME: Remove the FormattedPrintable[] overload if/when we can forward
// variadic arguments.
// BLOCKED: <rdar://problem/12134482> Can't forward variadic arguments
func printf(out : OutputStreamable, format : String, args : FormattedPrintable[]) {
var index = 0
while !format.isEmpty() {
var (before, layout, kind, after) = splitFormat(format)
out.write(before)
if kind != Char(0) {
out.write(args[index++].format(kind, layout))
}
format = after
}
}
func printf(out : OutputStreamable, format : String, args : FormattedPrintable...) {
printf(out, format, args)
}
func printf(format : String, args : FormattedPrintable...) {
printf(con, format, args)
}
// NOTE: the repl has builtin knowledge of this protocol
protocol ReplPrintable {
func replPrint()
}
// FIXME: This function shouldn't be necessary!
func replPrint<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(s : E) {
print('[')
var first = true
var total = 0
for i in s {
if first {
first = false
} else {
print(", ")
}
i.replPrint()
total = total + 1
if total > 50 {
print(" ...]")
return
}
}
print(']')
}
func print<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(s : E) {
replPrint(s)
}
// Some very basic output functions.
func [asmname="_TSs5printFT3valSi_T_"] print(val : Int)
func [asmname="_TSs5printFT3valSu_T_"] print(val : UInt64)
func [asmname="_TSs5printFT3valSd_T_"] print(val : Double)
func print(val : String) {
var len = val.byteLength()
for var i = 0; i < len; ++i {
c_putchar(Int32(val.str_value[i]))
}
}
func print(val : Char) {
var wc = UInt32(val)
if wc < 0x000080 {
c_putchar(Int32(wc))
return
} else if wc < 0x000800 {
c_putchar(Int32(0xC0 | (wc >> 6)))
c_putchar(Int32(0x80 | (wc & 0x03F)))
return
} else if wc < 0x010000 {
if !(0x00D800 <= wc && wc < 0x00E000) {
c_putchar(Int32(0xE0 | (wc >> 12)))
c_putchar(Int32(0x80 | ((wc & 0x0FC0) >> 6)))
c_putchar(Int32(0x80 | (wc & 0x003F)))
return
}
} else if wc < 0x110000 {
c_putchar(Int32(0xF0 | (wc >> 18)))
c_putchar(Int32(0x80 | ((wc & 0x03F000) >> 12)))
c_putchar(Int32(0x80 | ((wc & 0x000FC0) >> 6)))
c_putchar(Int32(0x80 | (wc & 0x00003F)))
return
}
// print(Char(0xFFFD))
alwaysTrap()
}
func print(val : Bool) {
if val {
print("true")
} else {
print("false")
}
}
// Some derived output functions.
func println(val : Bool) {
print(val)
print('\n')
}
func println(val : Int) {
print(val)
print('\n')
}
func println(val : UInt8) {
print(UInt64(val))
print('\n')
}
func println(val : UInt16) {
print(UInt64(val))
print('\n')
}
func println(val : UInt32) {
print(UInt64(val))
print('\n')
}
func println(val : UInt64) {
print(val)
print('\n')
}
func println(val : Double) {
print(val)
print('\n')
}
func println(val : String) {
print(val)
print('\n')
}
func println(val : Char) {
print(val)
print('\n')
}