commit 85b0d6b5ace0fb5fd3fb46a9836d857cbfefe7f2 Author: Scott Garrett Date: Fri Sep 4 13:55:06 2026 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e9e58d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +baud diff --git a/baud.c b/baud.c new file mode 100644 index 0000000..6f20967 --- /dev/null +++ b/baud.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +/* + + baud - A tool to simulate a specified baud rate in a pipe. + + I wrote this to be able to play some of the old VT100/ansi animations + at the rate of your choice. Since most terminal emulator apps render + the text as fast as the system can (which is effectively instantaneous), + the animations do not actually animate. This allows you to add + a throttle to view as if you were on an actual serial terminal. + + It takes one parameter, which is the desired baud rate. If you do not + specify one, it will use the default defined below. Extra parameters + will be ignored. + + -- Scott Garrett + version 2022050401 + +*/ + +#define defaultbaudrate 9600 + +int main(int argc, char *argv[]) +{ + int baudrate; + int c; + + if ( argc == 1 ) + baudrate = defaultbaudrate; + else + baudrate = atoi(argv[1]); + + /* Cannot have a negative baud rate, and 0 makes no sense + (and would cause a division by zero). + */ + if ( baudrate <= 0 ) + { + printf("Invalid baud rate: %d\n", baudrate); + exit(1); + } + + /* Convert the desired baud rate into nanoseconds */ + int baud = 10000000000 / baudrate; + + /* Make sure the final value is in the valid range that nanosleep() + supports. + */ + if ( baud < 0 || baud > 999999999 ) + { + printf("Invalid baud rate: %d\n", baudrate); + exit(1); + } + + /* Now that we know the desired baud rate delay in nanoseconds, + load up the struct with the values. 0 seconds and the baud rate delay. + */ + struct timespec remaining, request = {0, baud}; + + while ((c = getchar()) != EOF) + { + /* Here we grab a character from stdin, write it, flush it out + so it is seen immediately, then pause for "remaining" nanoseconds. + */ + putchar((char)c); + fflush(stdout); + int response = nanosleep(&request, &remaining); + } +} diff --git a/baudshell.py b/baudshell.py new file mode 100755 index 0000000..e9bd43a --- /dev/null +++ b/baudshell.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""pty_baud.py – run a shell behind two baud-rate simulators.""" +import os, pty, sys, tty, termios, select, subprocess + +BAUD = sys.argv[1] if len(sys.argv) > 1 else "baud" +SHELL = ["bash", "--norc"] + +master, slave = pty.openpty() +shell = subprocess.Popen(SHELL, stdin=slave, stdout=slave, stderr=slave, + preexec_fn=os.setsid, close_fds=True) +os.close(slave) + +baud_out = subprocess.Popen([BAUD], stdin=subprocess.PIPE, + stdout=subprocess.PIPE) +baud_in = subprocess.Popen([BAUD], stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + +# ── flatten every endpoint to an int fd ────────────────────────── +fd_term = sys.stdin.fileno() +fd_baud_in_stdin = baud_in.stdin.fileno() +fd_baud_in_out = baud_in.stdout.fileno() +fd_baud_out_in = baud_out.stdin.fileno() +fd_baud_out_out = baud_out.stdout.fileno() +# master is already an int from openpty() + +old = termios.tcgetattr(fd_term) +tty.setraw(fd_term) + +def pump(r, w): + try: + d = os.read(r, 4096) # r is already an int + except OSError: + return False + if not d: + return False + try: + os.write(w, d) # w is already an int + except OSError: + return False + return True + +try: + while True: + r, _, _ = select.select( + [fd_term, master, fd_baud_in_out, fd_baud_out_out], + [], [], 0.01) + + if fd_term in r: pump(fd_term, fd_baud_in_stdin) + if master in r: pump(master, fd_baud_out_in) + if fd_baud_in_out in r: pump(fd_baud_in_out, master) + if fd_baud_out_out in r: pump(fd_baud_out_out, fd_term) +except KeyboardInterrupt: + pass +finally: + termios.tcsetattr(fd_term, termios.TCSADRAIN, old) + for p in (shell, baud_in, baud_out): + try: p.terminate() + except OSError: pass +