diff --git a/Package.swift b/Package.swift index e16ef2f..f78c7d5 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,5 @@ let package = Package( targets: [ .target(name: "CTermios"), .target(name: "Termios", dependencies: ["CTermios"]), - - .testTarget(name: "TermiosTests", dependencies: ["Termios"]), ] ) diff --git a/README.md b/README.md index a8c22fc..26c9558 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,5 @@ -# Terminal +# Termios -This package aims to aid in the making of Command-Line Applications by providing an API to wrap -ANSI commands. - -The package contains a few modules: `Termios`, `ControlSequence`, `Prompt` and `Terminal`. The last one re-exports all previous ones. +Swift wrapper around `termios.h` *Any help, comments or suggestions would be welcome!* - -## Termios - -A swift termios wrapper, with documentation from the man pages. - -## ControlSequence - -Wraps ANSI sequences, string styling shortcuts, terminal query sequences and parsing, etc. - -## Prompt - -Alternative to readline, provides a plugin architecture to customize your prompt - -## Terminal - -Provides convenience APIs for terminal-related things diff --git a/Sources/Termios/Control+.swift b/Sources/Termios/Control+.swift deleted file mode 100644 index 6beb919..0000000 --- a/Sources/Termios/Control+.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2023-05-11. -// - -import Darwin.POSIX.termios - -extension Termios { - - /// Specifies the byte size in bits for both transmission and reception. - /// - /// This size does not include the parity bit, if any. If ``isTwoStopBitsUsed`` is set, two stop bits are used, otherwise one stop bit. - /// For example, at 110 baud, two stop bits are normally used. - @inlinable public var size: CharacterSize { - get { CharacterSize(rawValue: rawValue.csize) } - set { rawValue.csize = newValue.rawValue } - } - - /// Two stop bits are used instead of one stop bit. - /// - /// For example, at 110 baud, two stop bits are normally used. - @inlinable public var isTwoStopBitsUsed: Bool { - get { rawValue.cstopb } - set { rawValue.cstopb = newValue } - } - - /// Wether parity generation and detection are enabled - /// - /// If parity is enabled, ``parity-swift.property``controls wether even or odd parity is used. - @inlinable public var isParityEnabled: Bool { - get { rawValue.parenb } - set { rawValue.parenb = newValue } - } - - /// Specifies wether parity is even or odd - @inlinable public var parity: ParityChecking { - get { ParityChecking(booleanLiteral: rawValue.parodd) } - set { rawValue.parodd = newValue.rawValue } - } - - /// Wether to receive characters. - /// - /// Not all hardware supports this bit. In fact, this flag is pretty silly and if it were not part of the termios specification it would be omitted. - @inlinable public var isReadEnabled: Bool { - get { rawValue.cread } - set { rawValue.cread = newValue } - } - - /// Wether to hang up on the last close - /// - /// The modem control lines for the port are lowered when the last process with the port open closes the port or the process terminates. - /// The modem connection is broken. - @inlinable public var willHangUpOnLastClose: Bool { - get { rawValue.hupcl } - set { rawValue.hupcl = newValue } - } - - /// Wether to monitor or ignore modem status lines. - /// - /// When enabled the connection does not depend on the state of the modem status lines. - /// When disabled the modem status lines are monitored. - @inlinable public var isModemStatusLineMonitoringEnabled: Bool { - get { rawValue.clocal } - set { rawValue.clocal = newValue } - } - - /// Wether the output flow control is controlled by the state of Carrier Detect. - @inlinable public var isFlowControlledByCarrier: Bool { - get { rawValue.mdmbuf } - set { rawValue.mdmbuf = newValue } - } - - /// The total number of bits used per transmission and reception - @inlinable public var bitsPerCharacter: Int { - size.bits + (isTwoStopBitsUsed ? 2 : 1) + (isParityEnabled ? 1 : 0) - } - -} diff --git a/Sources/Termios/Control.swift b/Sources/Termios/Control.swift index ee0e5f3..51070c5 100644 --- a/Sources/Termios/Control.swift +++ b/Sources/Termios/Control.swift @@ -9,61 +9,46 @@ import Darwin.POSIX.termios extension termios { - /// See ``Termios/Termios/size`` @inlinable public var csize: Int32 { get { get(mask: CSIZE, from: c_cflag) } set { set(mask: CSIZE, to: newValue, in: &c_cflag) } } - /// See ``isTwoStopBitsUsed`` @inlinable public var cstopb: Bool { get { get(flag: CSTOPB, from: c_cflag) } set { set(flag: CSTOPB, to: newValue, in: &c_cflag) } } - /// See ``isParityEnabled`` + @inlinable public var cread: Bool { + get { get(flag: CREAD, from: c_cflag) } + set { set(flag: CREAD, to: newValue, in: &c_cflag) } + } + @inlinable public var parenb: Bool { get { get(flag: PARENB, from: c_cflag) } set { set(flag: PARENB, to: newValue, in: &c_cflag) } } - /// See ``parity-swift.property`` @inlinable public var parodd: Bool { get { get(flag: PARODD, from: c_cflag) } set { set(flag: PARODD, to: newValue, in: &c_cflag) } } - /// See ``isReadEnabled`` - @inlinable public var cread: Bool { - get { get(flag: CREAD, from: c_cflag) } - set { set(flag: CREAD, to: newValue, in: &c_cflag) } - } - - /// See ``isHangUpOnLastCloseEnabled`` @inlinable public var hupcl: Bool { get { get(flag: HUPCL, from: c_cflag) } set { set(flag: HUPCL, to: newValue, in: &c_cflag) } } - /// See ``isModemStatusLineMonitoringEnabled`` @inlinable public var clocal: Bool { get { get(flag: CLOCAL, from: c_cflag) } set { set(flag: CLOCAL, to: newValue, in: &c_cflag) } } - /// Currently unused, same as ``crtscts`` - @inlinable public var ccts_oflow: Bool { - get { get(flag: CCTS_OFLOW, from: c_cflag) } - set { set(flag: CCTS_OFLOW, to: newValue, in: &c_cflag) } - } - - /// Currently unused, same as ``ccts_oflow`` @inlinable public var crtscts: Bool { get { get(flag: CRTSCTS, from: c_cflag) } set { set(flag: CRTSCTS, to: newValue, in: &c_cflag) } } - /// See ``isFlowControlledByCarrier`` @inlinable public var mdmbuf: Bool { get { get(flag: MDMBUF, from: c_cflag) } set { set(flag: MDMBUF, to: newValue, in: &c_cflag) } diff --git a/Sources/Termios/ControlCharacters.swift b/Sources/Termios/ControlCharacters.swift index 7ec3912..b8694bb 100644 --- a/Sources/Termios/ControlCharacters.swift +++ b/Sources/Termios/ControlCharacters.swift @@ -7,131 +7,58 @@ import Darwin.POSIX.termios -/// The NL and CR characters cannot be changed. The values for all the remaining characters can be set and are -/// described later in the document under Special Control Characters. -/// -/// Special character functions associated with changeable special control characters can be disabled individually by -/// setting their value to {_POSIX_VDISABLE}; see Special Control Characters. -/// -/// If two or more special characters have the same value, the function performed when that character is received is -/// undefined. extension termios { - /// End of file, defaults to `^D` - /// - /// Special character on input and is recognized if the ICANON flag is set. When received, all the bytes - /// waiting to be read are immediately passed to the process, without waiting for a newline, and the EOF is - /// discarded. Thus, if there are no bytes waiting (that is, the EOF occurred at the beginning of a line), a - /// byte count of zero is returned from the read(), representing an end-of-file indication. If ICANON is - /// set, the EOF character is discarded when processed. NL Special character on input and is recognized if - /// the ICANON flag is set. It is the line delimiter ‘\n’. @inlinable public var veof: cc_t { get { get(character: VEOF) } set { set(character: VEOF, to: newValue) } } - /// End of line. Disabled by default. - /// - /// Special character on input and is recognized if the ICANON flag is set. Is an additional line delimiter, - /// like NL. @inlinable public var veol: cc_t { get { get(character: VEOL) } set { set(character: VEOL, to: newValue) } } - /// Erase, defaults to `^?` `\177` - /// - /// Special character on input and is recognized if the ICANON flag is set. Erases the last character in the - /// current line; see Canonical Mode Input Processing. It does not erase beyond the start of a line, as - /// delimited by an NL, EOF, or EOL character. If ICANON is set, the ERASE character is discarded when - /// processed. @inlinable public var verase: cc_t { get { get(character: VERASE) } set { set(character: VERASE, to: newValue) } } - /// Kill, defaults to `^U` - /// - /// Special character on input and is recognized if the ICANON flag is set. Deletes the entire line, as - /// delimited by a NL, EOF, or EOL character. If ICANON is set, the KILL character is discarded when - /// processed. @inlinable public var vkill: cc_t { get { get(character: VKILL) } set { set(character: VKILL, to: newValue) } } - /// Interrupt, defaults to `^C` - /// - /// Special character on input and is recognized if the ISIG flag (see the Local Modes section) is enabled. - /// Generates a SIGINT signal which is sent to all processes in the foreground process group for which the - /// terminal is the controlling terminal. If ISIG is set, the INTR character is discarded when processed. @inlinable public var vintr: cc_t { get { get(character: VINTR) } set { set(character: VINTR, to: newValue) } } - /// Quit, defaults to `^\` `\34` - /// - /// Special character on input and is recognized if the ISIG flag is enabled. Generates a SIGQUIT signal - /// which is sent to all processes in the foreground process group for which the terminal is the controlling - /// terminal. If ISIG is set, the QUIT character is discarded when processed. @inlinable public var vquit: cc_t { get { get(character: VQUIT) } set { set(character: VQUIT, to: newValue) } } - /// Suspend, defaults to `^Z` - /// - /// If the ISIG flag is enabled, receipt of the SUSP character causes a SIGTSTP signal to be sent to all - /// processes in the foreground process group for which the terminal is the controlling terminal, and the - /// SUSP character is discarded when processed. @inlinable public var vsusp: cc_t { get { get(character: VSUSP) } set { set(character: VSUSP, to: newValue) } } - /// Start, defaults to `^Q` - /// - /// Special character on both input and output and is recognized if the IXON (output control) or IXOFF (input - /// control) flag is set. Can be used to resume output that has been suspended by a STOP character. If IXON - /// is set, the START character is discarded when processed. CR Special character on input and is recognized - /// if the ICANON flag is set; it is the ‘\r’, as denoted in the C Standard {2}. When ICANON and ICRNL are - /// set and IGNCR is not set, this character is translated into a NL, and has the same effect as a NL - /// character. @inlinable public var vstart: cc_t { get { get(character: VSTART) } set { set(character: VSTART, to: newValue) } } - /// Suspend, defaults to `^S` - /// - /// Special character on both input and output and is recognized if the IXON (output control) or IXOFF (input - /// control) flag is set. Can be used to temporarily suspend output. It is useful with fast terminals to - /// prevent output from disappearing before it can be read. If IXON is set, the STOP character is discarded - /// when processed. @inlinable public var vstop: cc_t { get { get(character: VSTOP) } set { set(character: VSTOP, to: newValue) } } - /// The minimum number of bytes that should be received when the read function successfully returns. - /// - /// See also @inlinable public var vmin: cc_t { get { get(character: VMIN) } - set { - #if DEBUG - if newValue <= MAX_INPUT { - print("Termios.min \(newValue) is higher than MAX_INPUT \(MAX_INPUT), behaviour is undefined") - } - #endif - set(character: VMIN, to: newValue) - } - } - - /// A timer of 0.1 second granularity that is used to time out bursty and short term data transmissions. - /// - /// See also + set { set(character: VMIN, to: newValue) } + } + @inlinable public var vtime: cc_t { get { get(character: VTIME) } set { set(character: VTIME, to: newValue) } @@ -141,70 +68,36 @@ extension termios { #if os(macOS) - /// Secondary end of line character, same function as ``eol``. Disabled by default @inlinable public var veol2: cc_t { get { get(character: VEOL2) } set { set(character: VEOL2, to: newValue) } } - /// Word erase, defaults to `^W` - /// - /// Special character on input and is recognized if the ICANON flag is set. Erases the last word in the - /// current line according to one of two algorithms. If the ALTWERASE flag is not set, first any preceding - /// whitespace is erased, and then the maximal sequence of non-whitespace characters. If ALTWERASE is set, - /// first any preceding whitespace is erased, and then the maximal sequence of alphabetic/underscores or non - /// alphabetic/underscores. As a special case in this second algorithm, the first previous non-whitespace - /// character is skipped in determining whether the preceding word is a sequence of alphabetic/undercores. - /// This sounds confusing but turns out to be quite practical. @inlinable public var vwerase: cc_t { get { get(character: VWERASE) } set { set(character: VWERASE, to: newValue) } } - /// Reprint, defaults to `^R` - /// - /// Special character on input and is recognized if the ICANON flag is set. Causes the current input edit - /// line to be retyped. @inlinable public var vreprint: cc_t { get { get(character: VREPRINT) } set { set(character: VREPRINT, to: newValue) } } - /// Suspend, defaults to `^Y` - /// - /// Has similar actions to the SUSP character, except that the SIGTSTP signal is delivered when one of the - /// processes in the foreground process group issues a read() to the controlling terminal. @inlinable public var vdusp: cc_t { get { get(character: VDSUSP) } set { set(character: VDSUSP, to: newValue) } } - /// Escape character, defaults to `^V` - /// - /// Special character on input and is recognized if the IEXTEN flag is set. Receipt of this character causes - /// the next character to be taken literally. @inlinable public var vlnext: cc_t { get { get(character: VLNEXT) } set { set(character: VLNEXT, to: newValue) } } - /// Status, defaults to `^T` - /// - /// Special character on input and is recognized if the ICANON flag is set. Receipt of this character causes - /// a SIGINFO signal to be sent to the foreground process group of the terminal. Also, if the NOKERNINFO - /// flag is not set, it causes the kernel to write a status message to the terminal that displays the current - /// load average, the name of the command in the foreground, its process ID, the symbolic wait channel, the - /// number of user and system seconds used, the percentage of cpu the process is getting, and the resident - /// set size of the process. @inlinable public var vstatus: cc_t { get { get(character: VSTATUS) } set { set(character: VSTATUS, to: newValue) } } - /// Discard, defaults to `^O` - /// - /// Special character on input and is recognized if the IEXTEN flag is set. Receipt of this character - /// toggles the flushing of terminal output. @inlinable public var vdiscard: cc_t { get { get(character: VDISCARD) } set { set(character: VDISCARD, to: newValue) } @@ -213,34 +106,3 @@ extension termios { #endif } - -/* - Special Control Characters - The special control characters values are defined by the array c_cc. This table lists the array index, the corresponding special character, and the system default value. For an accurate list of the system - defaults, consult the header file ⟨ttydefaults.h⟩. - - Index Name Special Character Default Value - VEOF EOF ^D - VEOL EOL _POSIX_VDISABLE - VEOL2 EOL2 _POSIX_VDISABLE - VERASE ERASE ^? ‘\177’ - VWERASE WERASE ^W - VKILL KILL ^U - VREPRINT REPRINT ^R - VINTR INTR ^C - VQUIT QUIT ^\\ ‘\34’ - VSUSP SUSP ^Z - VDSUSP DSUSP ^Y - VSTART START ^Q - VSTOP STOP ^S - VLNEXT LNEXT ^V - VDISCARD DISCARD ^O - VMIN --- 1 - VTIME --- 0 - VSTATUS STATUS ^T - - If the value of one of the changeable special control characters (see Special Characters) is {_POSIX_VDISABLE}, that function is disabled; that is, no input data is recognized as the disabled special character. If - ICANON is not set, the value of {_POSIX_VDISABLE} has no special meaning for the VMIN and VTIME entries of the c_cc array. - - The initial values of the flags and control characters after open() is set according to the values in the header ⟨sys/ttydefaults.h⟩. - */ diff --git a/Sources/Termios/Documentation.docc/Articles/NonCanonicalInputProcessing.md b/Sources/Termios/Documentation.docc/Articles/NonCanonicalInputProcessing.md deleted file mode 100644 index a0f4095..0000000 --- a/Sources/Termios/Documentation.docc/Articles/NonCanonicalInputProcessing.md +++ /dev/null @@ -1,55 +0,0 @@ -# Non-Canonical Input Processing - -Character by character input. - -## Overview - -In noncanonical mode input processing, input bytes are not assembled into lines, and erase and kill processing -does not occur. The values of the MIN and TIME members of the c_cc array are used to determine how to process -the bytes received. - -MIN represents the minimum number of bytes that should be received when the read function successfully returns. -TIME is a timer of 0.1 second granularity that is used to time out bursty and short term data transmissions. If -MIN is greater than { MAX_INPUT}, the response to the request is undefined. The four possible values for MIN and -TIME and their interactions are described below. - -### Case A: MIN > 0, TIME > 0 - -In this case TIME serves as an inter-byte timer and is activated after the first byte is received. Since it is -an inter-byte timer, it is reset after a byte is received. The interaction between MIN and TIME is as follows: -as soon as one byte is received, the inter-byte timer is started. If MIN bytes are received before the inter- -byte timer expires (remember that the timer is reset upon receipt of each byte), the read is satisfied. If the -timer expires before MIN bytes are received, the characters received to that point are returned to the user. -Note that if TIME expires at least one byte is returned because the timer would not have been enabled unless a -byte was received. In this case (MIN > 0, TIME > 0) the read blocks until the MIN and TIME mechanisms are -activated by the receipt of the first byte, or a signal is received. If data is in the buffer at the time of the -read(), the result is as if data had been received immediately after the read(). - -### Case B: MIN > 0, TIME = 0 - -In this case, since the value of TIME is zero, the timer plays no role and only MIN is significant. A pending -read is not satisfied until MIN bytes are received (i.e., the pending read blocks until MIN bytes are received), -or a signal is received. A program that uses this case to read record-based terminal I/O may block indefinitely -in the read operation. - -### Case C: MIN = 0, TIME > 0 - -In this case, since MIN = 0, TIME no longer represents an inter-byte timer. It now serves as a read timer that -is activated as soon as the read function is processed. A read is satisfied as soon as a single byte is received -or the read timer expires. Note that in this case if the timer expires, no bytes are returned. If the timer -does not expire, the only way the read can be satisfied is if a byte is received. In this case the read will not -block indefinitely waiting for a byte; if no byte is received within TIME*0.1 seconds after the read is -initiated, the read returns a value of zero, having read no data. If data is in the buffer at the time of the -read, the timer is started as if data had been received immediately after the read. - -### Case D: MIN = 0, TIME = 0 - -The minimum of either the number of bytes requested or the number of bytes currently available is returned -without waiting for more bytes to be input. If no characters are available, read returns a value of zero, having -read no data. - -## Topics - -### Group - -- ``Symbol`` diff --git a/Sources/Termios/Documentation.docc/Documentation.md b/Sources/Termios/Documentation.docc/Documentation.md deleted file mode 100644 index d8342cc..0000000 --- a/Sources/Termios/Documentation.docc/Documentation.md +++ /dev/null @@ -1,50 +0,0 @@ -# ``Termios`` - -Cross-platform wrapper around the `termios` struct. - -## Overview - -You can access these options with either their raw flag, such as ``Termios/Termios/csize`` or using a comprehensive property like ``Termios/Termios/size``. - -## Topics - -### Control - -- ``Termios/Termios/size`` -- ``Termios/Termios/isTwoStopBitsUsed`` -- ``Termios/Termios/isParityEnabled`` -- ``Termios/Termios/parity-swift.property`` -- ``Termios/Termios/isReadEnabled`` -- ``Termios/Termios/willHangUpOnLastClose`` -- ``Termios/Termios/isModemStatusLineMonitoringEnabled`` -- ``Termios/Termios/isFlowControlledByCarrier`` - -### Input - -- ``Termios/Termios/isGeneratingInterruptOnIncomingBreaks`` -- ``Termios/Termios/isConvertingIncomingCarriageReturnsToNewline`` -- ``Termios/Termios/isIgnoringIncomingBreaks`` -- ``Termios/Termios/isIgnoringIncomingCarriageReturn`` -- ``Termios/Termios/isIgnoringInputParityErrors`` -- ``Termios/Termios/isConvertingIncomingNewlinesToCarriageReturns`` -- ``Termios/Termios/isInputParityChecked`` -- ``Termios/Termios/isInputStripped`` -- ``Termios/Termios/isResumeOnAnyCharacterEnabled`` -- ``Termios/Termios/isInputControlEnabled`` -- ``Termios/Termios/isOutputControlEnabled`` -- ``Termios/Termios/isParityErrorMarked`` -- ``Termios/Termios/isBellRingOnFullInputQueueEnabled`` - -### Local - -- ``Termios/Termios/isEchoEnabled`` -- ``Termios/Termios/isAlwaysEchoingNewlines`` -- ``Termios/Termios/isLineErasingEnabled`` -- ``Termios/Termios/isCharacterErasingEnabled`` -- ``Termios/Termios/isLineDiscardingEnabled`` - -### Utilities - -Additional properties provided for convenience. - -- ``Termios/Termios/bitsPerCharacter`` diff --git a/Sources/Termios/Error.swift b/Sources/Termios/Error.swift index 505332c..de87ddf 100644 --- a/Sources/Termios/Error.swift +++ b/Sources/Termios/Error.swift @@ -9,7 +9,7 @@ import Darwin.POSIX.termios public struct TermiosError: RawRepresentable, Error { - public var rawValue: errno_t + public let rawValue: errno_t @inlinable public init(rawValue: errno_t) { self.rawValue = rawValue diff --git a/Sources/Termios/Input+.swift b/Sources/Termios/Input+.swift deleted file mode 100644 index 76a4d13..0000000 --- a/Sources/Termios/Input+.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2021-12-24. -// - -import Darwin.POSIX.termios - -extension Termios { - - /// Indicates that an interrupt should be generated if the user types a `BREAK` - /// - /// This has no effect if ``isIgnoringIncomingBreaks`` is `true`. - /// - /// if this is true, then a `BREAK` will flush all input and output queues. In addition, if the terminal is the controlling terminal of a foreground process - /// group, the `BREAK` condition generates a single `SIGINT` signal for that foreground process group, which usually kills the process group. - /// - /// If this is `false`, a `BREAK` condition is taken as input depending on ``markParityErrors``: a single input character `NULL` if it's `false` - /// or three input characters `\377`, `NULL`, `NULL` if it's `true`. - @inlinable public var isGeneratingInterruptOnIncomingBreaks: Bool { - get { rawValue.brkint } - set { rawValue.brkint = newValue } - } - - /// Automatically converts input carriage returns to newline (line-feed) characters before they are passed to the application that reads the input - /// - /// This has no effect if ``isIgnoringIncomingCarriageReturn`` is `true`. - @inlinable public var isConvertingIncomingCarriageReturnsToNewline: Bool { - get { rawValue.icrnl } - set { rawValue.icrnl = newValue } - } - - /// Ignores `BREAK` conditions - @inlinable public var isIgnoringIncomingBreaks: Bool { - get { rawValue.ignbrk } - set { rawValue.ignbrk = newValue } - } - - /// Ignores input carriage returns - @inlinable public var isIgnoringIncomingCarriageReturn: Bool { - get { rawValue.igncr } - set { rawValue.igncr = newValue } - } - - /// Ignores input characters (other than `BREAK`) that have parity errors - @inlinable public var isIgnoringInputParityErrors: Bool { - get { rawValue.ignpar } - set { rawValue.ignpar = newValue } - } - - /// Automatically converts input newline (line-feed) characters to carriage returns before they are passed to the application that reads the input. - @inlinable public var isConvertingIncomingNewlinesToCarriageReturns: Bool { - get { rawValue.inlcr } - set { rawValue.inlcr = newValue } - } - - /// Enables input parity checking - /// - /// If this is `false`, it allows output parity generation without input parity errors. The enabling of input parity checking is independent of the enabling - /// of parity checking in the control modes field. (See ``Termios/Control-swift.struct``) - /// - /// While the control modes may dictate that the hardware recognizes the parity bit, the terminal special file does not check whether this bit is set correctly. - @inlinable public var isInputParityChecked: Bool { - get { rawValue.inpck } - set { rawValue.inpck = newValue } - } - - /// Strips valid input bytes to 7 bits, if this is `false` the complete byte is processed - /// - /// - Warning: Do not enable this for pseudoterminals, since it will make the terminal unusable. If you strip the first bit off of EBCDIC characters, - /// you destroy all printable EBCDIC characters. - @inlinable public var isInputStripped: Bool { - get { rawValue.istrip } - set { rawValue.istrip = newValue } - } - - /// Enables any character to restart output - /// - /// This requires ``isInputControlEnabled`` to be `true`. - /// - /// If a previous `STOP` character has been received, then receipt of any input character will cause the `STOP` condition to be removed. For pseudoterminals, data - /// in the output queue is passed to the application during master `read()` processing, and slave pseudoterminal writes are allowed to proceed. The character which - /// caused the output to restart is also processed normally as well (unless it is a `STOP` character). - @inlinable public var isResumeOnAnyCharacterEnabled: Bool { - get { rawValue.ixany } - set { rawValue.ixany = newValue } - } - - /// Enables start/stop input control - /// - /// If this is `true`, the system attempts to prevent the number of bytes in the input queue from exceeding the ``MAX_INPUT`` value. - /// It sends one or more `STOP` characters to the terminal device when the input queue is in danger of filling up. The system transmits - /// one or more START characters when it appears that there is space in the input queues for more input. - /// - /// - LINK TO SYMBOLS: - /// The character used as the `STOP` character is dictated by the `c_cc` member of the termios structure. It is intended to tell the terminal - /// to stop sending input for a while. Again, the character used as the START character is dictated by the `c_cc` member. It is intended to - /// tell the terminal that it can resume transmission of input. - @inlinable public var isInputControlEnabled: Bool { - get { rawValue.ixoff } - set { rawValue.ixoff = newValue } - } - - /// Enables start/stop output control - /// - /// If the system receives a `STOP` character as input, it will suspend output on the associated terminal until a `START` character is received. - /// An application reading input from the terminal does not see `STOP` or `START` characters; they are intercepted by the system, which does - /// all the necessary processing. - /// - /// If this is `false`, any `STOP` or `START` characters read are passed on as input to an application reading from the terminal. - @inlinable public var isOutputControlEnabled: Bool { - get { rawValue.ixon } - set { rawValue.ixon = newValue } - } - /// Marks characters with parity errors - /// - /// This has no effect if ``isIgnoringInputParityErrors`` is `true`. - /// - /// If this is `true`, then a byte with a framing or parity error is sent to the application as the characters `\377` and `NULL`, followed by the data part of - /// the byte that had the parity error. If `ISTRIP` is `false`, a valid input character of `\377` is sent as a pair of characters `\377`, `\377` to avoid ambiguity. - /// - /// If this is `false`, a character with a framing or parity error is sent to the application as `NULL`. - @inlinable public var isParityErrorMarked: Bool { - get { rawValue.parmrk } - set { rawValue.parmrk = newValue } - } - - /// Rings the terminal bell when the input queue is full - /// - /// When the input queue is full, any subsequent input will ring the bell. - @inlinable public var shouldRingBellOnFullInputQueue: Bool { - get { rawValue.imaxbel } - set { rawValue.imaxbel = newValue } - } - -} diff --git a/Sources/Termios/Input.swift b/Sources/Termios/Input.swift index 39923ed..593fd36 100644 --- a/Sources/Termios/Input.swift +++ b/Sources/Termios/Input.swift @@ -9,24 +9,14 @@ import Darwin.POSIX.termios extension termios { - @inlinable public var brkint: Bool { - get { get(flag: BRKINT, from: c_iflag) } - set { set(flag: BRKINT, to: newValue, in: &c_iflag) } - } - - @inlinable public var icrnl: Bool { - get { get(flag: ICRNL, from: c_iflag) } - set { set(flag: ICRNL, to: newValue, in: &c_iflag) } - } - @inlinable public var ignbrk: Bool { get { get(flag: IGNBRK, from: c_iflag) } set { set(flag: IGNBRK, to: newValue, in: &c_iflag) } } - @inlinable public var igncr: Bool { - get { get(flag: IGNCR, from: c_iflag) } - set { set(flag: IGNCR, to: newValue, in: &c_iflag) } + @inlinable public var brkint: Bool { + get { get(flag: BRKINT, from: c_iflag) } + set { set(flag: BRKINT, to: newValue, in: &c_iflag) } } @inlinable public var ignpar: Bool { @@ -34,9 +24,9 @@ extension termios { set { set(flag: IGNPAR, to: newValue, in: &c_iflag) } } - @inlinable public var inlcr: Bool { - get { get(flag: INLCR, from: c_iflag) } - set { set(flag: INLCR, to: newValue, in: &c_iflag) } + @inlinable public var parmrk: Bool { + get { get(flag: PARMRK, from: c_iflag) } + set { set(flag: PARMRK, to: newValue, in: &c_iflag) } } @inlinable public var inpck: Bool { @@ -49,14 +39,19 @@ extension termios { set { set(flag: ISTRIP, to: newValue, in: &c_iflag) } } - @inlinable public var ixany: Bool { - get { get(flag: IXANY, from: c_iflag) } - set { set(flag: IXANY, to: newValue, in: &c_iflag) } + @inlinable public var inlcr: Bool { + get { get(flag: INLCR, from: c_iflag) } + set { set(flag: INLCR, to: newValue, in: &c_iflag) } } - @inlinable public var ixoff: Bool { - get { get(flag: IXOFF, from: c_iflag) } - set { set(flag: IXOFF, to: newValue, in: &c_iflag) } + @inlinable public var igncr: Bool { + get { get(flag: IGNCR, from: c_iflag) } + set { set(flag: IGNCR, to: newValue, in: &c_iflag) } + } + + @inlinable public var icrnl: Bool { + get { get(flag: ICRNL, from: c_iflag) } + set { set(flag: ICRNL, to: newValue, in: &c_iflag) } } @inlinable public var ixon: Bool { @@ -64,9 +59,14 @@ extension termios { set { set(flag: IXON, to: newValue, in: &c_iflag) } } - @inlinable public var parmrk: Bool { - get { get(flag: PARMRK, from: c_iflag) } - set { set(flag: PARMRK, to: newValue, in: &c_iflag) } + @inlinable public var ixoff: Bool { + get { get(flag: IXOFF, from: c_iflag) } + set { set(flag: IXOFF, to: newValue, in: &c_iflag) } + } + + @inlinable public var ixany: Bool { + get { get(flag: IXANY, from: c_iflag) } + set { set(flag: IXANY, to: newValue, in: &c_iflag) } } @inlinable public var imaxbel: Bool { @@ -74,4 +74,13 @@ extension termios { set { set(flag: IMAXBEL, to: newValue, in: &c_iflag) } } + #if os(Linux) + + @inlinable public var iuclc: Bool { + get { get(flag: IUCLC, from: c_iflag) } + set { set(flag: IUCLC, to: newValue, in: &c_iflag) } + } + + #endif + } diff --git a/Sources/Termios/Local+.swift b/Sources/Termios/Local+.swift deleted file mode 100644 index 6af8f24..0000000 --- a/Sources/Termios/Local+.swift +++ /dev/null @@ -1,104 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2021-12-26. -// - -import Darwin.POSIX.termios - -extension Termios { - - //MARK: - Properties - - /// Input characters are echoed back to the terminal - @inlinable public var isEchoEnabled: Bool { - get { rawValue.echo } - set { rawValue.echo = newValue } - } - - /// Wether to always echo newlines regardless of ``isEchoEnabled``'s value - /// - /// This has no effect if ``isCanonical`` is `false` - @inlinable public var isAlwaysEchoingNewlines: Bool { - get { rawValue.echonl } - set { rawValue.echonl = newValue } - } - - /// Allows erasing lines with the special character ``erase`` - /// - /// This has no effect if ``isCanonical`` is `false` - @inlinable public var isLineErasingEnabled: Bool { - get { rawValue.echoke } - set { rawValue.echoke = newValue } - } - - /// Allows erasing the last character of the current line with the special character ``erase`` - /// - /// This has no effect if ``isCanonical`` is `false` - @inlinable public var isCharacterErasingEnabled: Bool { - get { rawValue.echoe } - set { rawValue.echoe = newValue } - } - - /// Allows discarding lines with the special character ``discard`` - /// - /// Note that **visually**, this is the equivalent of a linefeed. To erase the line from the display, enable ``isLineErasingEnabled`` instead. - /// - /// This has no effect if ``isCanonical`` is `false` - @inlinable public var isLineDiscardingEnabled: Bool { - get { rawValue.echok } - set { rawValue.echok = newValue } - } - - /// Processes input line by line, allows manipulating the line before submitting it - @inlinable public var isCanonical: Bool { - get { rawValue.icanon } - set { rawValue.icanon = newValue } - } - - /// This assumes the output is a printer and will wrap the erased characters with a backslash and forward slash - @inlinable public var describeErase: Bool { - get { rawValue.echoprt } - set { rawValue.echoprt = newValue } - } - - /// Displays control characters by prepending a caret, such as `^C` for control-C - @inlinable public var describeControlCharacters: Bool { - get { rawValue.echoctl } - set { rawValue.echoctl = newValue } - } - - /// Selects which word erasing algorithm to use. - /// - /// If this is `false`, whitespace is erased, and then the maximal sequence of non-whitespace characters. - /// - /// If this is `true`, first any preceding whitespace is erased, and then the maximal sequence of alphabetic/underscores or non alphabetic/underscores. - /// As a special case in this second algorithm, the first previous non-whitespace character is skipped in determining whether the preceding word is a sequence - /// of alphabetic/undercores. This sounds confusing but turns out to be quite practical. - @inlinable public var useAlternateWordEraseAlgorithm: Bool { - get { rawValue.altwerase } - set { rawValue.altwerase = newValue } - } - - /// Wether to process interrupts from ``Termios/Termios/ControlCharacters/interrupt``, kills from ``Termios/Termios/ControlCharacters/kill`` and suspensions from ``Termios/Termios/ControlCharacters/suspend`` - @inlinable public var isProcessControlEnabled: Bool { - get { rawValue.isig } - set { rawValue.isig = newValue } - } - - /// Wether to flush the input and output queues before doing process control functions - /// - /// This has no effect if ``isProcessControlEnabled`` is `false` - @inlinable public var preventFlushOnProcessControl: Bool { - get { rawValue.noflsh } - set { rawValue.noflsh = newValue } - } - - /// Wether to allow implementation-defined extended functionnality - @inlinable public var areExtensionsEnabled: Bool { - get { rawValue.iexten } - set { rawValue.iexten = newValue } - } - -} diff --git a/Sources/Termios/Local.swift b/Sources/Termios/Local.swift index cfc1383..999a5ae 100644 --- a/Sources/Termios/Local.swift +++ b/Sources/Termios/Local.swift @@ -9,16 +9,6 @@ import Darwin.POSIX.termios extension termios { - @inlinable public var echo: Bool { - get { get(flag: ECHO, from: c_lflag) } - set { set(flag: ECHO, to: newValue, in: &c_cflag) } - } - - @inlinable public var echonl: Bool { - get { get(flag: ECHONL, from: c_lflag) } - set { set(flag: ECHONL, to: newValue, in: &c_cflag) } - } - @inlinable public var echoke: Bool { get { get(flag: ECHOKE, from: c_lflag) } set { set(flag: ECHOKE, to: newValue, in: &c_cflag) } @@ -34,9 +24,14 @@ extension termios { set { set(flag: ECHOK, to: newValue, in: &c_cflag) } } - @inlinable public var icanon: Bool { - get { get(flag: ICANON, from: c_lflag) } - set { set(flag: ICANON, to: newValue, in: &c_cflag) } + @inlinable public var echo: Bool { + get { get(flag: ECHO, from: c_lflag) } + set { set(flag: ECHO, to: newValue, in: &c_cflag) } + } + + @inlinable public var echonl: Bool { + get { get(flag: ECHONL, from: c_lflag) } + set { set(flag: ECHONL, to: newValue, in: &c_cflag) } } @inlinable public var echoprt: Bool { @@ -49,16 +44,21 @@ extension termios { set { set(flag: ECHOCTL, to: newValue, in: &c_cflag) } } - @inlinable public var altwerase: Bool { - get { get(flag: ALTWERASE, from: c_lflag) } - set { set(flag: ALTWERASE, to: newValue, in: &c_cflag) } - } - @inlinable public var isig: Bool { get { get(flag: ISIG, from: c_lflag) } set { set(flag: ISIG, to: newValue, in: &c_lflag) } } + @inlinable public var icanon: Bool { + get { get(flag: ICANON, from: c_lflag) } + set { set(flag: ICANON, to: newValue, in: &c_cflag) } + } + + @inlinable public var altwerase: Bool { + get { get(flag: ALTWERASE, from: c_lflag) } + set { set(flag: ALTWERASE, to: newValue, in: &c_cflag) } + } + @inlinable public var iexten: Bool { get { get(flag: IEXTEN, from: c_lflag) } set { set(flag: IEXTEN, to: newValue, in: &c_lflag) } diff --git a/Sources/Termios/Models+.swift b/Sources/Termios/Models+.swift deleted file mode 100644 index a2eaab0..0000000 --- a/Sources/Termios/Models+.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2023-05-11. -// - -import Darwin.POSIX.termios - -extension CharacterSize { - - /// The number of bits used by characters with this configuration - @inlinable public var bits: Int { - switch rawValue { - case CS5: return 5 - case CS6: return 6 - case CS7: return 7 - case CS8: return 8 - default: - assertionFailure("Invalid CS \(rawValue), valid values are \(CS5), \(CS6), \(CS7) and \(CS8)") - return 0 - } - } - -} diff --git a/Sources/Termios/Options.swift b/Sources/Termios/Options.swift index aa46538..b7903e8 100644 --- a/Sources/Termios/Options.swift +++ b/Sources/Termios/Options.swift @@ -33,13 +33,10 @@ extension ParityChecking { extension UpdateScheduling { - /// The change should take place immediately. public static let now = UpdateScheduling(rawValue: TCSANOW) - /// The change should take place after all output written has been read by the master pseudoterminal. Use this value when changing terminal attributes that affect output. public static let drain = UpdateScheduling(rawValue: TCSADRAIN) - /// The change should take place after all output written has been sent; in addition, all input that has been received but not read should be discarded (flushed) before the change is made. public static let flush = UpdateScheduling(rawValue: TCSAFLUSH) #if os(macOS) diff --git a/Sources/Termios/Output+.swift b/Sources/Termios/Output+.swift deleted file mode 100644 index c0ff512..0000000 --- a/Sources/Termios/Output+.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2021-12-25. -// - -import Darwin.POSIX.termios - -extension Termios { - - /// Wether output is processed or displayed as-is, controls wether any other output processing is enabled - @inlinable public var isOutputProcessingEnabled: Bool { - get { rawValue.opost } - set { rawValue.opost = newValue } - } - - /// Wether newlines are translated to carriage return, linefeed - /// - /// This has no effect if ``isOutputPreprocessed`` is `false`. - @inlinable public var isOutputNewlineConvertedCarriageReturn: Bool { - get { rawValue.onlcr } - set { rawValue.onlcr = newValue } - } - - /// Wether tabs are expanded to 8 spaces - /// - /// This has no effect if ``isOutputPreprocessed`` is `false`. - @inlinable public var isOutputTabExpanded: Bool { - get { rawValue.oxtabs } - set { rawValue.oxtabs = newValue } - } - - /// Wether `EOT` should be discarded - /// - /// This has no effect if ``isOutputPreprocessed`` is `false`. - @inlinable public var isOutputEndOfTransmissionDiscarded: Bool { - get { rawValue.onoeot } - set { rawValue.onoeot = newValue } - } - - /// Wether carriage returns are translated to linefeeds - /// - /// This has no effect if ``isOutputPreprocessed`` is `false`. - @inlinable public var isOutputCarriageReturnConvertedNewline: Bool { - get { rawValue.ocrnl } - set { rawValue.ocrnl = newValue } - } - - /// Wether to discard carriage returns when the cursor is already at column 0 - /// - /// This has no effect if ``isOutputPreprocessed`` is `false`. - @inlinable public var isOutputCarriageReturnDiscarded: Bool { - get { rawValue.onocr } - set { rawValue.onocr = newValue } - } - - /// Wether to interpret linefeeds as also doing a carriage return - /// - /// This has no effect if ``isOutputPreprocessed`` is `false`. - @inlinable public var isNewlineAlsoCarriageReturn: Bool { - get { rawValue.onlret } - set { rawValue.onlret = newValue } - } - -} diff --git a/Sources/Termios/Presets.swift b/Sources/Termios/Presets.swift deleted file mode 100644 index fac6e4d..0000000 --- a/Sources/Termios/Presets.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2021-12-26. -// - -import Darwin.POSIX.termios - -extension Termios { - - // TODO: Canonical (line-based) - - // TODO: Streamed (character-based) - - - -} diff --git a/Sources/Termios/Termios+.swift b/Sources/Termios/Termios+.swift deleted file mode 100644 index d2e9f85..0000000 --- a/Sources/Termios/Termios+.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2023-05-11. -// - -import Darwin.POSIX.termios - -#warning("TODO: check which API are macOS only") -#warning("TODO: transfer man pages into documentation articles") - -public struct Termios: RawRepresentable { - - /// The raw termios value - public var rawValue: termios - - /// Wraps an existing `termios` configuration - @inlinable public init(rawValue: termios) { - self.rawValue = rawValue - } - - /// Retrieves the standard input's current configuration - @inlinable public static var current: Termios { - get throws { - Termios(rawValue: try termios(STDIN_FILENO)) - } - } - - @inlinable public func write(when schedule: UpdateScheduling = .now) throws { - try rawValue.write(to: STDIN_FILENO, on: schedule) - } - - //MARK: - Raw Mode - - /// Preset configuration with pure I/O - @inlinable public static var raw: Termios { - get throws { - var configuration = try termios(STDIN_FILENO) - configuration.raw() - return Termios(rawValue: configuration) - } - } - - /// Executes a block with a specific configuration, then returns to the previous configuration - @inlinable public func raw(execute block: () -> Void) throws { - var tmp = rawValue - tmp.raw() - try tmp.write(to: STDIN_FILENO, on: .now) - block() - try rawValue.write(to: STDIN_FILENO, on: .now) - } - -} diff --git a/Tests/TermiosTests/TODO.swift b/Tests/TermiosTests/TODO.swift deleted file mode 100644 index 30617be..0000000 --- a/Tests/TermiosTests/TODO.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// File.swift -// -// -// Created by Christophe Bronner on 2023-05-10. -// - -import Foundation