From 9c798768cc0d007a8e92aa971cb35210a5130688 Mon Sep 17 00:00:00 2001 From: the-homeless-god Date: Fri, 4 Sep 2026 11:55:59 +0000 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B7=D0=B1=D0=BE=D1=80=20stty=20?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D0=B0=D0=B5=D1=82=20=D0=BF=D0=B0=D1=80=D1=83?= =?UTF-8?q?,=20=D0=B0=20=D0=BD=D0=B5=20=D1=81=D0=BE=D1=81=D0=B5=D0=B4?= =?UTF-8?q?=D0=B0:=20BSD=20=D0=B4=D0=B0=D0=B2=D0=B0=D0=BB=2080=C3=9780=20?= =?UTF-8?q?=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=2024=C3=9780?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Задача 7185. `stty -a` пишут двумя записями: GNU — «rows 24; columns 80», BSD и macOS — «24 rows; 80 columns». Разбор брал число «рядом» с ключом, сначала справа, потом слева, и на записи BSD отвечал 80×80: speed 38400 baud; 24 rows; 80 columns; [0] [1] [2] [3] [4] [5] у «rows» справа стоит 80, и оно годилось. Перевернуть порядок нельзя: тогда «columns» у GNU взял бы слева 24. Ни одна сторона по отдельности не верна — верна ПАРА, а какая она, видно по тому, число слово или нет. Теперь разбирается пара, и съеденная пропускается целиком: иначе число из пары GNU досталось бы следующему ключу как пара BSD. Замер мой, обеими версиями на тех же трёх строках: было GNU 24×80 BSD 80×80 сырой 24×80 стало GNU 24×80 BSD 24×80 сырой 24×80 Тест на это в дереве уже стоял и был красным с 2 сентября — с того же дня, когда файл завели (c7729e0). ЧТО ЭТО ЧИНИТ СВЕРХ РАЗМЕРА ТЕРМИНАЛА. Шаг «Тесты, включая те, которым нужен мак» был красным на обоих маковских бегунках, и из-за этого ПРОПУСКАЛИСЬ два шага ниже — «Снимок содержит числа, а не прочерки» и «В выводе нет инженерного дневника». Десять проверок на числа в снимке и сторож против объяснений вместо чисел не работали на маке ни на одном прогоне: не красные, а непрогнанные. --- host/internal/run/tty_other.go | 78 ++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/host/internal/run/tty_other.go b/host/internal/run/tty_other.go index 9f06866..969dc28 100644 --- a/host/internal/run/tty_other.go +++ b/host/internal/run/tty_other.go @@ -48,31 +48,73 @@ func parseStty(text string) (ttyState, bool) { return r == ' ' || r == '\t' || r == '\n' || r == ';' || r == ',' }) st := ttyState{Cooked: true} - for i, f := range fields { - switch f { - case "rows": - st.Rows = numberNear(fields, i) - case "columns": - st.Cols = numberNear(fields, i) - case "-icanon", "-echo": + // РАЗБИРАЕТСЯ ПАРА, А НЕ СОСЕД, и это единственный способ прочитать обе + // записи одним проходом. + // + // Прежний разбор брал число «рядом» — сначала справа, потом слева, — и на + // записи BSD отвечал 80×80 вместо 24×80: + // + // speed 38400 baud; 24 rows; 80 columns; + // [0] [1] [2] [3] [4] [5] + // + // у «rows» справа стоит 80, и оно годилось. Перевернуть порядок нельзя: + // тогда «columns» у GNU («rows 24; columns 80») взял бы слева 24. Ни одна + // сторона по отдельности не верна — верна пара, а какая она, видно по + // тому, число слово или нет. + // + // Съеденная пара пропускается целиком: иначе число из пары GNU досталось + // бы следующему ключу как пара BSD. + for i := 0; i < len(fields); i++ { + f := fields[i] + if f == "-icanon" || f == "-echo" { st.Cooked = false + continue + } + if i+1 >= len(fields) { + continue + } + next := fields[i+1] + // GNU: <ключ> <число> + if key := sizeKey(f); key != "" { + if n, err := strconv.Atoi(next); err == nil { + st.set(key, n) + i++ + continue + } + } + // BSD: <число> <ключ> + if key := sizeKey(next); key != "" { + if n, err := strconv.Atoi(f); err == nil { + st.set(key, n) + i++ + } } } return st, st.Rows > 0 && st.Cols > 0 } -// numberNear takes the number written beside a word, on whichever side this -// stty put it. -func numberNear(fields []string, i int) int { - if i+1 < len(fields) { - if n, err := strconv.Atoi(fields[i+1]); err == nil { - return n - } +// sizeKey says which of the two sizes this word names, and "" when it names +// neither. +func sizeKey(word string) string { + switch word { + case "rows", "columns": + return word } - if i > 0 { - if n, err := strconv.Atoi(fields[i-1]); err == nil { - return n + return "" +} + +// set writes the size the key names. Первым записанным значением, а не +// последним: у BSD слово «rows» встречается ещё раз в строке флагов, и +// перезапись стёрла бы уже найденный размер. +func (s *ttyState) set(key string, n int) { + switch key { + case "rows": + if s.Rows == 0 { + s.Rows = n + } + case "columns": + if s.Cols == 0 { + s.Cols = n } } - return 0 }