1 /** 2 * Consoleur: a package for interaction with character-oriented terminal emulators 3 * 4 * Copyright: Maxim Freck, 2017. 5 * Authors: Maxim Freck <maxim@freck.pp.ru> 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 */ 8 module consoleur.terminfo.io; 9 version(Posix) { 10 11 import std.stdio: File; 12 import std.traits: isScalarType; 13 14 /******* 15 * Determines terminfo file name 16 * Returns: the path to the file or an empty string if the file is not found 17 */ 18 string determineTermFile() @safe 19 { 20 import std.process: environment, get; 21 22 auto fname = environment.get("TERM", "unknown"); 23 fname = cast(char)(fname[0])~"/"~fname; 24 25 auto home = getHomeDir() ~ "/.terminfo/" ~ fname; 26 27 if (fileExists(home)) { 28 return home; 29 } 30 31 if (fileExists("/etc/terminfo/"~fname)) { 32 return "/etc/terminfo/"~fname; 33 } 34 35 if (fileExists("/lib/terminfo/"~fname)) { 36 return "/lib/terminfo/"~fname; 37 } 38 39 return ""; 40 } 41 42 private bool fileExists(string name) @trusted 43 { 44 import core.sys.posix.sys.stat: stat, stat_t, S_ISREG; 45 46 stat_t path_stat; 47 stat((name~"\0").ptr, &path_stat); 48 return S_ISREG(path_stat.st_mode); 49 } 50 51 private string getHomeDir() @trusted 52 { 53 import core.sys.posix.pwd: getpwuid; 54 import core.sys.posix.unistd: getuid; 55 import std.conv: to; 56 57 auto passwdEnt = *getpwuid(getuid()); 58 return to!string(passwdEnt.pw_dir); 59 } 60 61 /******* 62 * Determines whether the system is big endian 63 * Returns: true if the system is big endan, false otherwise 64 */ 65 pure nothrow immutable(bool) isBigEndian() @trusted @nogc 66 { 67 union E {ushort s; ubyte[2] b; } 68 E e = {s: 0xdead}; 69 return (e.b[0] == 0xad) ? false : true; 70 } 71 72 /******* 73 * Performes inplace reverse of a static array 74 */ 75 private pure nothrow void reverse(T, size_t n)(ref T[n] a) @safe @nogc 76 { 77 foreach (i; 0 .. n/2) { 78 immutable temp = a[i]; 79 a[i] = a[n - 1 - i]; 80 a[n - 1 - i] = temp; 81 } 82 } 83 84 /******* 85 * Reads variable of type T from a file in the little endian format. 86 * Returns: variable of type T in the little endian format. 87 */ 88 auto get(T)(File f) @safe if (isScalarType!(T)) 89 { 90 static if (T.sizeof == 1) { 91 T[1] b = [0]; 92 f.rawRead(b); 93 return b[0]; 94 95 } else { 96 97 union buffer {ubyte[T.sizeof] b; T v;} 98 buffer buf; 99 f.rawRead(buf.b); 100 101 if(isBigEndian()) { 102 reverse(buf.b); 103 } 104 105 return buf.v; 106 } 107 } 108 109 /******* 110 * Reads array of variables of type T from a file in the little endian format. 111 * Returns: array of variables of type T in the little endian format. 112 */ 113 T[] get(T)(File f, size_t size) @safe if (isScalarType!(T)) 114 { 115 if (size < 1) return []; 116 117 auto buf = new T[size]; 118 f.rawRead(buf); 119 120 if(isBigEndian()) { 121 union item {ubyte[T.sizeof] b; T v;} 122 foreach (ref i; buf) { 123 item itm; 124 itm.v = i; 125 reverse(itm.b); 126 i = itm.v; 127 } 128 } 129 130 return buf; 131 } 132 133 }