1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift Argument Parser open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
#if canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Darwin)
import Darwin
#elseif canImport(CRT)
import CRT
#elseif canImport(WASILibc)
import WASILibc
#endif
enum Platform {}
// MARK: Shell
extension Platform {
/// The name of the user's preferred shell, if detectable from the
/// environment.
static var shellName: String? {
#if os(Windows)
return nil
#else
// FIXME: This retrieves the user's preferred shell, not necessarily the one currently in use.
guard let shellVar = getenv("SHELL") else { return nil }
let shellParts = String(cString: shellVar).split(separator: "/")
return shellParts.last.map(String.init)
#endif
}
}
// MARK: Exit codes
#if os(Windows)
import func WinSDK.GetStdHandle
import func WinSDK.GetConsoleScreenBufferInfo
import let WinSDK.ERROR_BAD_ARGUMENTS
import let WinSDK.STD_OUTPUT_HANDLE
import struct WinSDK.CONSOLE_SCREEN_BUFFER_INFO
#endif
extension Platform {
/// The code for successful exit.
static var exitCodeSuccess: Int32 {
EXIT_SUCCESS
}
/// The code for exit with a general failure.
static var exitCodeFailure: Int32 {
EXIT_FAILURE
}
/// The code for exit with a validation failure.
static var exitCodeValidationFailure: Int32 {
#if os(Windows)
return ERROR_BAD_ARGUMENTS
#elseif os(WASI)
return EXIT_FAILURE
#else
return EX_USAGE
#endif
}
}
// MARK: Exit function
extension Platform {
/// Complete execution with the given exit code.
static func exit(_ code: Int32) -> Never {
#if canImport(Glibc)
Glibc.exit(code)
#elseif canImport(Musl)
Musl.exit(code)
#elseif canImport(Darwin)
Darwin.exit(code)
#elseif canImport(CRT)
ucrt._exit(code)
#elseif canImport(WASILibc)
WASILibc.exit(code)
#endif
}
}
// MARK: Standard error
extension Platform {
/// A type that represents the `stderr` output stream.
struct StandardError: TextOutputStream {
mutating func write(_ string: String) {
for byte in string.utf8 { putc(numericCast(byte), stderr) }
}
}
/// The `stderr` output stream.
static var standardError = StandardError()
}
// MARK: Terminal size
#if canImport(Glibc)
func ioctl(_ a: Int32, _ b: Int32, _ p: UnsafeMutableRawPointer) -> Int32 {
ioctl(CInt(a), UInt(b), p)
}
#endif
extension Platform {
/// The default terminal size.
static var defaultTerminalSize: (width: Int, height: Int) {
(80, 25)
}
/// Returns the current terminal size, or the default if the size is
/// unavailable.
static func terminalSize() -> (width: Int, height: Int) {
#if os(WASI)
// WASI doesn't yet support terminal size
return defaultTerminalSize
#elseif os(Windows)
var csbi: CONSOLE_SCREEN_BUFFER_INFO = CONSOLE_SCREEN_BUFFER_INFO()
guard GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) else {
return defaultTerminalSize
}
return (width: Int(csbi.srWindow.Right - csbi.srWindow.Left) + 1,
height: Int(csbi.srWindow.Bottom - csbi.srWindow.Top) + 1)
#else
var w = winsize()
#if os(OpenBSD)
// TIOCGWINSZ is a complex macro, so we need the flattened value.
let tiocgwinsz = Int32(0x40087468)
let err = ioctl(STDOUT_FILENO, tiocgwinsz, &w)
#elseif canImport(Musl)
let err = ioctl(STDOUT_FILENO, UInt(TIOCGWINSZ), &w)
#else
let err = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w)
#endif
let width = Int(w.ws_col)
let height = Int(w.ws_row)
guard err == 0 else { return defaultTerminalSize }
return (width: width > 0 ? width : defaultTerminalSize.width,
height: height > 0 ? height : defaultTerminalSize.height)
#endif
}
/// The current terminal size, or the default if the width is unavailable.
static var terminalWidth: Int {
terminalSize().width
}
}
|