1use std::mem::zeroed;
7use std::os::raw::{c_int, c_ulong, c_ushort};
8
9static STDOUT_FILENO: c_int = 1;
10
11#[cfg(any(target_os = "linux", target_os = "android"))]
13static TIOCGWINSZ: c_ulong = 0x5413;
14
15#[cfg(any(
16 target_os = "macos",
17 target_os = "ios",
18 target_os = "dragonfly",
19 target_os = "freebsd",
20 target_os = "netbsd",
21 target_os = "openbsd"
22))]
23static TIOCGWINSZ: c_ulong = 0x40087468;
24
25#[cfg(target_os = "solaris")]
26static TIOCGWINSZ: c_ulong = 0x5468;
27
28#[repr(C)]
30struct winsize {
31 ws_row: c_ushort,
32 ws_col: c_ushort,
33 ws_xpixel: c_ushort,
34 ws_ypixel: c_ushort,
35}
36
37extern "C" {
38 fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
39}
40
41unsafe fn get_dimensions() -> winsize {
45 let mut window: winsize = zeroed();
46 let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);
47
48 if result != -1 {
49 return window;
50 }
51 zeroed()
52}
53
54pub fn term_cols() -> Option<usize> {
57 let winsize { ws_col, .. } = unsafe { get_dimensions() };
58
59 if ws_col == 0 {
60 None
61 } else {
62 Some(ws_col as usize)
63 }
64}
65
66#[cfg(test)]
67mod test {
68 #[test]
71 fn compare_with_stty() {
72 use std::process::{Command, Stdio};
73
74 let output = if cfg!(target_os = "linux") {
75 Command::new("stty")
76 .arg("size")
77 .arg("-F")
78 .arg("/dev/stderr")
79 .stderr(Stdio::inherit())
80 .output()
81 .unwrap()
82 } else {
83 Command::new("stty")
84 .arg("-f")
85 .arg("/dev/stderr")
86 .arg("size")
87 .stderr(Stdio::inherit())
88 .output()
89 .unwrap()
90 };
91 assert!(output.status.success());
92
93 let stdout = String::from_utf8(output.stdout).unwrap();
94 println!("stty: {}", stdout);
95
96 let mut data = stdout.split_whitespace();
98 let expected: usize = str::parse(data.nth(1).unwrap()).unwrap();
99 println!("cols: {}", expected);
100
101 if let Some(actual) = super::term_cols() {
102 assert_eq!(actual, expected);
103 } else if expected == 0 {
105 eprintln!("WARN: stty reports cols 0, skipping test");
106 } else {
107 panic!("term_cols() return None");
108 }
109 }
110}