File: Platform.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (160 lines) | stat: -rw-r--r-- 4,227 bytes parent folder | download
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
  }
}