Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 60 additions & 18 deletions host/internal/run/tty_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Loading