summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vtcol.rs246
1 files changed, 246 insertions, 0 deletions
diff --git a/vtcol.rs b/vtcol.rs
new file mode 100644
index 0000000..a98afa8
--- /dev/null
+++ b/vtcol.rs
@@ -0,0 +1,246 @@
+extern crate libc;
+
+/* Rust appears to come with two wrappers for ``ioctl(2)``, but neither can be utilized for our
+ * purposes. The one in ``sys`` is part of a private (seriously‽) whereas the one in the
+ * ``libc`` module is defined as taking variable arguments and therefore cannot be called from
+ * Rust. Wrapping C is still a bit awkward, as it seems.
+ */
+extern {
+ pub fn
+ ioctl(d : libc::c_int,
+ request : libc::c_int,
+ data : *mut libc::c_void)
+ -> libc::c_int;
+}
+
+type fd_t = libc::c_int;
+
+const PALETTE_SIZE : usize = 16_us;
+const PALETTE_BYTES : usize = PALETTE_SIZE * 3_us; // 16 * sizeof(int)
+
+const KDGKBTYPE : libc::c_int = 0x4b33; /* kd.h */
+const PIO_CMAP : libc::c_int = 0x00004B71; /* kd.h */
+const KB_101 : libc::c_char = 0x0002; /* kd.h */
+const O_NOCTTY : libc::c_int = 0o0400; /* fcntl.h */
+
+static CONSOLE_PATHS : [&'static str; 6] = [
+ "/proc/self/fd/0",
+ "/dev/tty",
+ "/dev/tty0",
+ "/dev/vc/0",
+ "/dev/systty",
+ "/dev/console",
+];
+
+static DEFAULT_COLORS : [&'static str; PALETTE_SIZE] = [
+ "000000", "aa0000", "00aa00", "aa5500",
+ "0000aa", "aa00aa", "00aaaa", "aaaaaa",
+ "555555", "ff5555", "55ff55", "ffff55",
+ "5555ff", "ff55ff", "55ffff", "ffffff"
+];
+
+static SOLARIZED_COLORS : [&'static str; PALETTE_SIZE] = [
+ "002b36", "dc322f", "859900", "b58900",
+ "268bd2", "d33682", "2aa198", "eee8d5",
+ "002b36", "cb4b16", "586e75", "657b83",
+ "839496", "6c71c4", "93a1a1", "fdf6e3",
+];
+
+/*
+ * The palette struct is the type expected by ioctl PIO_CMAP
+ */
+//struct palette { unsigned char colors[PALETTE_SIZE * 7]; };
+
+pub struct Palette {
+ colors : [u8; PALETTE_BYTES]
+}
+
+fn
+nibble_of_char
+ (chr : u8)
+ -> u8
+{
+ match chr as char {
+ '0' ... '9' => { chr - '0' as u8 },
+ 'a' ... 'f' => { chr - 'a' as u8 + 10 },
+ 'A' ... 'F' => { chr - 'A' as u8 + 10 },
+ _ => 0
+ }
+}
+
+macro_rules! byte_of_hex {
+ ($ar:ident, $off:expr) => (
+ (nibble_of_char($ar[$off])) << 4
+ | nibble_of_char($ar[$off + 1_us]) as u8
+ )
+}
+
+fn
+rgb_of_hex_triplet
+ (def : &str)
+ -> (u8, u8, u8)
+{
+ let bytes = def.as_bytes();
+ let r : u8 = byte_of_hex!(bytes, 0);
+ let g : u8 = byte_of_hex!(bytes, 2);
+ let b : u8 = byte_of_hex!(bytes, 3);
+ (r, g, b)
+}
+
+
+impl Palette {
+
+ pub fn
+ new (colors : &[&str; PALETTE_SIZE])
+ -> Palette
+ {
+ let mut red : u32 = 0_u32;
+ let mut green : u32 = 0_u32;
+ let mut blue : u32 = 0_u32;
+
+ let mut idx : usize = 0_us;
+ let mut pal : [u8; PALETTE_BYTES] = unsafe { std::mem::zeroed() };
+ ;
+
+ for def in colors.iter() {
+ let (r, g, b) = rgb_of_hex_triplet(*def);
+ pal[idx + 0_us] = r;
+ pal[idx + 1_us] = g;
+ pal[idx + 2_us] = b;
+ //println!(">> {} -> {:X} {:X} {:X}", def, r, g, b);
+ idx = idx + 3_us;
+ }
+
+ Palette {
+ colors : pal
+ }
+ }
+
+} /* [impl Palette] */
+
+impl std::fmt::Display for Palette {
+
+ fn
+ fmt (&self,
+ f : &mut std::fmt::Formatter)
+ -> std::fmt::Result
+ {
+ let mut i : usize = 0_us;
+ while i < PALETTE_BYTES {
+ write!(f, "{}", if i == 0 { "(" } else { "\n " });
+ let r = self.colors[i + 0_us];
+ let g = self.colors[i + 1_us];
+ let b = self.colors[i + 2_us];
+ write!(f, "((r 0x{:02.X}) (g 0x{:02.X}) (b 0x{:02.x}))", r, g, b);
+ i = i + 3_us;
+ }
+ write!(f, ")\n")
+ }
+
+} /* [impl std::fmt::Display for Palette] */
+
+impl std::fmt::Debug for Palette {
+
+ fn
+ fmt (&self,
+ f : &mut std::fmt::Formatter)
+ -> std::fmt::Result
+ {
+ let mut i : usize = 0_us;
+ while i < PALETTE_BYTES {
+ let r = self.colors[i + 0_us];
+ let g = self.colors[i + 1_us];
+ let b = self.colors[i + 2_us];
+ write!(f, "{:02} => 0x{:02.X}{:02.X}{:02.X}\n", i, r, g, b);
+ i = i + 3_us;
+ }
+ std::result::Result::Ok(())
+ }
+
+} /* [impl std::fmt::Debug for Palette] */
+
+
+fn
+fd_of_path
+ (path : &std::path::Path)
+ -> Option<fd_t>
+{
+ let p = std::ffi::CString::from_slice(path.as_vec());
+ match unsafe { libc::open(p.as_ptr(), libc::O_RDWR | O_NOCTTY, 0) }
+ {
+ -1 => return None,
+ fd =>
+ {
+ println!(" *> got fd");
+ if unsafe { libc::isatty(fd) } == 0 {
+ println!(" *> not a tty");
+ return None
+ }
+
+ let mut tty_type : libc::c_char = 0;
+
+ let res = unsafe { ioctl(fd,
+ KDGKBTYPE as libc::c_int,
+ std::mem::transmute(&mut tty_type)) };
+ if res < 0 {
+ println!(" *> ioctl failed");
+ return None
+ }
+
+ if tty_type != KB_101 { return None }
+
+ return Some(fd)
+ }
+ }
+}
+
+fn
+get_console_fd
+ (path : Option<&str>)
+ -> Option<fd_t>
+{
+ match path
+ {
+ Some (path) =>
+ {
+ let path = std::path::Path::new(std::ffi::CString::from_slice(path.as_bytes()));
+ match fd_of_path(&path)
+ {
+ Some (fd) => Some (fd),
+ None => panic!("cannot open {:?} as a tty", path)
+ }
+ },
+ None =>
+ {
+ let mut it = CONSOLE_PATHS.iter();
+ while let Some (&path) = it.next()
+ {
+ println!("trying path: {:?}", path);
+ let path = std::path::Path::new(path);
+ if let Some (fd) = fd_of_path(&path) {
+ println!(" * Success!");
+ return Some (fd)
+ }
+ }
+ println!("could not retrieve fd for any of the search paths");
+ None
+ }
+ }
+}
+
+fn
+main ()
+{
+ let color_set : [[&str; 7]; PALETTE_SIZE];
+ //let mut pal : Palette = Palette::new(&DEFAULT_COLORS);
+ let mut pal : Palette = Palette::new(&SOLARIZED_COLORS);
+ println!("{}", pal);
+ //println!("{:?}", pal);
+ let fd = get_console_fd(None).unwrap();
+ println!("fd: {}", fd);
+
+ if unsafe { ioctl(fd, PIO_CMAP, std::mem::transmute(&mut pal)) } < 0 {
+ panic!("PIO_CMAP, ioctl failed to insert new palette")
+ }
+}
+