src/primes.h \
src/crctab.c \
src/tac-pipe.c \
- src/extract-magic
+ src/extract-magic \
+ src/speedgen
CLEANFILES += $(SCRIPTS)
$(AM_V_at)chmod a-w $@t
$(AM_V_at)mv $@t $@
+# Target-specific termios baud rate file. This is opportunistic;
+# if cc -E doesn't support -dM, the speedgen script still includes
+# an extensive fallback list of common constants.
+CLEANFILES += src/speedlist.h
+src/speedlist.h: src/termios.c lib/config.h src/speedgen
+ $(AM_V_GEN)rm -f $@
+ $(AM_V_at)${MKDIR_P} src
+ $(AM_V_at)$(COMPILE) -E -dM $< 2>/dev/null | \
+ $(SHELL) $(srcdir)/src/speedgen $@t
+ $(AM_V_at)chmod a-w $@t
+ $(AM_V_at)mv $@t $@
+
+src/stty.$(OBJEXT): src/speedlist.h
+
# Generates a list of macro invocations like:
# SINGLE_BINARY_PROGRAM(program_name_str, main_name)
# once for each program list on $(single_binary_progs). Note that
--- /dev/null
+#!/bin/sh -e
+
+out="$1"
+tmp="$out.tmp"
+
+if [ -z "$out" ]; then
+ echo "Usage: $0 outfile" 2>&1
+ exit 1
+fi
+
+s='[[:space:]]' # For brevity's sake
+
+trap "rm -f '$tmp'" EXIT
+trap "rm -f '$tmp' '$out'" ERR HUP INT QUIT TERM
+
+# Fallback list of speeds that are always tested for
+defspeeds="0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 7200 9600 \
+14400 19200 28800 33600 38400 57600 76800 115200 153600 230400 307200 \
+460800 500000 576000 614400 921600 1000000 1152000 1500000 \
+2000000 2500000 3000000 3500000 4000000 5000000 10000000"
+(
+ sed -n -e "s/^$s*\#$s*define$s$s*B\\([1-9][0-9]*\\)$s.*\$/\\1/p"
+ for s in $defspeeds; do echo "$s"; done
+) | sort -n | uniq > "$tmp"
+
+cat > "$out" <<'EOF'
+#ifndef SPEEDLIST_H
+# define SPEEDLIST_H 1
+
+# if 1 \
+EOF
+
+sed -e 's/^.*$/ \&\& (!defined(B&) || B& == &) \\/' < "$tmp" >> "$out"
+
+cat >> "$out" <<'EOF'
+
+# define TERMIOS_SPEED_T_SANE 1
+
+# endif
+
+ATTRIBUTE_CONST
+static unsigned long int
+baud_to_value (speed_t speed)
+{
+# ifdef TERMIOS_SPEED_T_SANE
+ return speed;
+# else
+ switch (speed)
+ {
+EOF
+
+sed -e 's/^.*$/# ifdef B&\n case B&: return &;\n# endif/' \
+ < "$tmp" >> "$out"
+
+cat >> "$out" <<'EOF'
+ default: return -1;
+ }
+# endif
+}
+
+ATTRIBUTE_CONST
+static speed_t
+value_to_baud (unsigned long int value)
+{
+# ifdef TERMIOS_SPEED_T_SANE
+ speed_t speed = value;
+ if (speed != value)
+ speed = (speed_t) -1; /* Unrepresentable (overflow?) */
+ return speed;
+# else
+ switch (value)
+ {
+EOF
+
+sed -e 's/^.*$/# ifdef B&\n case &: return B&;\n# endif/' \
+ < "$tmp" >> "$out"
+
+cat >> "$out" <<'EOF'
+ default: return (speed_t) -1;
+ }
+# endif
+}
+
+#endif
+EOF
#include "system.h"
#include "assure.h"
+#include "c-ctype.h"
#include "fd-reopen.h"
#include "quote.h"
#include "xdectoint.h"
return true;
}
-struct speed_map
-{
- char const *string; /* ASCII representation. */
- speed_t speed; /* Internal form. */
- unsigned long int value; /* Numeric value. */
-};
-
-static struct speed_map const speeds[] =
-{
- {"0", B0, 0},
- {"50", B50, 50},
- {"75", B75, 75},
- {"110", B110, 110},
- {"134", B134, 134},
- {"134.5", B134, 134},
- {"150", B150, 150},
- {"200", B200, 200},
- {"300", B300, 300},
- {"600", B600, 600},
- {"1200", B1200, 1200},
- {"1800", B1800, 1800},
- {"2400", B2400, 2400},
- {"4800", B4800, 4800},
- {"9600", B9600, 9600},
- {"19200", B19200, 19200},
- {"38400", B38400, 38400},
- {"exta", B19200, 19200},
- {"extb", B38400, 38400},
-#ifdef B57600
- {"57600", B57600, 57600},
-#endif
-#ifdef B115200
- {"115200", B115200, 115200},
-#endif
-#ifdef B230400
- {"230400", B230400, 230400},
-#endif
-#ifdef B460800
- {"460800", B460800, 460800},
-#endif
-#ifdef B500000
- {"500000", B500000, 500000},
-#endif
-#ifdef B576000
- {"576000", B576000, 576000},
-#endif
-#ifdef B921600
- {"921600", B921600, 921600},
-#endif
-#ifdef B1000000
- {"1000000", B1000000, 1000000},
-#endif
-#ifdef B1152000
- {"1152000", B1152000, 1152000},
-#endif
-#ifdef B1500000
- {"1500000", B1500000, 1500000},
-#endif
-#ifdef B2000000
- {"2000000", B2000000, 2000000},
-#endif
-#ifdef B2500000
- {"2500000", B2500000, 2500000},
-#endif
-#ifdef B3000000
- {"3000000", B3000000, 3000000},
-#endif
-#ifdef B3500000
- {"3500000", B3500000, 3500000},
-#endif
-#ifdef B4000000
- {"4000000", B4000000, 4000000},
-#endif
- {nullptr, 0, 0}
-};
+/* Autogenerated conversion functions to/from speed_t */
+#include "speedlist.h"
ATTRIBUTE_PURE
static speed_t
string_to_baud (char const *arg)
{
- for (int i = 0; speeds[i].string != nullptr; ++i)
- if (STREQ (arg, speeds[i].string))
- return speeds[i].speed;
- return (speed_t) -1;
-}
+ char *ep;
+ unsigned long value;
+ unsigned char c;
-ATTRIBUTE_PURE
-static unsigned long int
-baud_to_value (speed_t speed)
-{
- for (int i = 0; speeds[i].string != nullptr; ++i)
- if (speed == speeds[i].speed)
- return speeds[i].value;
- return 0;
+ /* Explicitly disallow negative numbers. */
+ while (c_isspace (*arg))
+ arg++;
+ if (*arg == '-')
+ return (speed_t) -1;
+
+ value = strtoul (arg, &ep, 10);
+
+ c = *ep++;
+ if (c == '.')
+ {
+ /* Number includes a fraction. Round it to nearest-even.
+ Note in particular that 134.5 must round to 134! */
+ c = *ep++;
+ if (c)
+ {
+ c -= '0';
+ if (c > 9)
+ {
+ return (speed_t) -1; /* Garbage after otherwise valid number */
+ }
+ else if (c > 5)
+ {
+ value++;
+ }
+ else if (c == 5)
+ {
+ while ((c = *ep++) == '0')
+ ; /* Skip zeroes after .5 */
+
+ if (c >= '1' && c <= '9')
+ value++; /* Nonzero digit, round up */
+ else
+ value += (value & 1); /* Exactly in the middle, round even */
+ }
+ }
+ }
+ else if (c)
+ {
+ /* Not a valid number; check for legacy aliases "exta" and "extb" */
+ if (STREQ (arg, "exta"))
+ return B19200;
+ else if (STREQ (arg, "extb"))
+ return B38400;
+ else
+ return (speed_t) -1;
+ }
+
+ return value_to_baud (value);
}
static void
--- /dev/null
+/* termios.c -- coax out Bxxx macros from termios.h
+
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* This simply #includes headers which may or may not provide Bxxx
+ constant macros. This is run through the C preprocessor and defined
+ macros are extracted.
+
+ In the case where the C preprocessor isn't capable of doing so,
+ the script this is fed through contains a pre-defined set of common
+ constants. */
+
+#include <config.h>
+
+#ifdef TERMIOS_NEEDS_XOPEN_SOURCE
+# define _XOPEN_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <termios.h>
+#include <sys/ioctl.h>