github.com/iDigitalFlame/xmt@v0.5.4/device/os.go (about) 1 // Copyright (C) 2020 - 2023 iDigitalFlame 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 // 16 17 // Package device contains many function that provide access to Operating System 18 // functions and resources. Many of these are OS agnostic and might not work 19 // as intended on some systems. 20 package device 21 22 import ( 23 "os" 24 "sync" 25 "syscall" 26 "time" 27 28 "github.com/iDigitalFlame/xmt/data" 29 "github.com/iDigitalFlame/xmt/device/arch" 30 "github.com/iDigitalFlame/xmt/util" 31 ) 32 33 // Arch represents the current device Architecture type. 34 const Arch = arch.Current 35 36 const ( 37 // Windows represents the Windows family of Operating Systems. 38 Windows OSType = 0x0 39 // Linux represents the Linux family of Operating Systems 40 Linux OSType = 0x1 41 // Unix represents the Unix/BSD family of Operating Systems 42 Unix OSType = 0x2 43 // Mac represents the macOS family of Operating Systems 44 Mac OSType = 0x3 45 // IOS represents the iOS family of Operating Systems 46 // Technically is Mac, but deserves its own type for any special actions. 47 IOS OSType = 0x4 48 // Android represents the Android family of Operating Systems 49 // Technically is Linux, but deserves its own type for any special actions. 50 Android OSType = 0x5 51 // Plan9 represents the Plan9 family of Operating Systems 52 Plan9 OSType = 0x6 53 // Unsupported represents a device type that does not have direct support 54 // any may not work properly. 55 Unsupported OSType = 0xF 56 ) 57 58 var builders = sync.Pool{ 59 New: func() interface{} { 60 return new(util.Builder) 61 }, 62 } 63 64 // OSType is a numerical representation of the device Operating System type. 65 type OSType uint8 66 67 // Login is a struct that represents a current user Session on the device. 68 type Login struct { 69 _ [0]func() 70 Login time.Time 71 LastInput time.Time 72 User string 73 Host string 74 From Address 75 ID uint32 76 Status uint8 77 } 78 79 func init() { 80 t := os.TempDir() 81 syscall.Setenv("tmp", t) 82 syscall.Setenv("temp", t) 83 } 84 85 // Expand attempts to determine environment variables from the current session 86 // and translate them from the supplied string. 87 // 88 // This function supports both Windows (%var%) and *nix ($var or ${var}) 89 // variable substitutions. 90 func Expand(s string) string { 91 if len(s) == 0 { 92 return s 93 } 94 if len(s) >= 2 && s[0] == '~' && s[1] == '/' { 95 // Account for shell expansion. (Except JS/WASM) 96 if h := UserHomeDir(); len(h) > 0 { 97 s = h + s[1:] 98 } 99 } 100 var ( 101 l = -1 102 b = builders.Get().(*util.Builder) 103 c byte 104 v string 105 ok bool 106 ) 107 for i := range s { 108 switch { 109 case s[i] == '$': 110 if c > 0 { 111 if c == '{' { 112 b.WriteString(s[l-1 : i]) 113 } else { 114 b.WriteString(s[l:i]) 115 } 116 } 117 c, l = s[i], i 118 case s[i] == '%' && c == '%' && i != l: 119 if v, ok = syscall.Getenv(s[l+1 : i]); ok { 120 b.WriteString(v) 121 } else { 122 b.WriteString(s[l:i]) 123 } 124 c, l = 0, 0 125 case s[i] == '%': 126 c, l = s[i], i 127 case s[i] == '}' && c == '{': 128 if v, ok = syscall.Getenv(s[l+1 : i]); ok { 129 b.WriteString(v) 130 } else { 131 b.WriteString(s[l-1 : i]) 132 } 133 c, l = 0, 0 134 case s[i] == '{' && i > 0 && c == '$': 135 c, l = s[i], i 136 case s[i] >= 'a' && s[i] <= 'z': 137 fallthrough 138 case s[i] >= 'A' && s[i] <= 'Z': 139 fallthrough 140 case s[i] == '_': 141 if c == 0 { 142 b.WriteByte(s[i]) 143 } 144 case s[i] >= '0' && s[i] <= '9': 145 if c > 0 && i > l && i-l == 1 { 146 c, l = 0, 0 147 } 148 if c == 0 { 149 b.WriteByte(s[i]) 150 } 151 default: 152 if c == '$' { 153 if v, ok = syscall.Getenv(s[l+1 : i]); ok { 154 b.WriteString(v) 155 } else { 156 b.WriteString(s[l:i]) 157 } 158 c, l = 0, 0 159 } else if c > 0 { 160 if c == '{' { 161 b.WriteString(s[l-1 : i]) 162 } else { 163 b.WriteString(s[l:i]) 164 } 165 c, l = 0, 0 166 } 167 b.WriteByte(s[i]) 168 } 169 } 170 if l == -1 { 171 b.Reset() 172 builders.Put(b) 173 return s 174 } 175 if l < len(s) && c > 0 { 176 if c == '$' { 177 if v, ok = syscall.Getenv(s[l+1:]); ok { 178 b.WriteString(v) 179 } else { 180 b.WriteString(s[l:]) 181 } 182 } else if c == '{' { 183 b.WriteString(s[l-1:]) 184 } else { 185 b.WriteString(s[l:]) 186 } 187 } 188 v = b.Output() 189 b.Reset() 190 builders.Put(b) 191 return v 192 } 193 194 // MarshalStream writes the data of this c to the supplied Writer. 195 func (l Login) MarshalStream(w data.Writer) error { 196 if err := w.WriteUint32(l.ID); err != nil { 197 return err 198 } 199 if err := w.WriteUint8(l.Status); err != nil { 200 return err 201 } 202 if err := w.WriteInt64(l.Login.Unix()); err != nil { 203 return err 204 } 205 if err := w.WriteInt64(l.LastInput.Unix()); err != nil { 206 return err 207 } 208 if err := l.From.MarshalStream(w); err != nil { 209 return err 210 } 211 if err := w.WriteString(l.User); err != nil { 212 return err 213 } 214 return w.WriteString(l.Host) 215 } 216 217 // UnmarshalStream reads the data of this Login from the supplied Reader. 218 func (l *Login) UnmarshalStream(r data.Reader) error { 219 if err := r.ReadUint32(&l.ID); err != nil { 220 return err 221 } 222 if err := r.ReadUint8(&l.Status); err != nil { 223 return err 224 } 225 v, err := r.Int64() 226 if err != nil { 227 return err 228 } 229 i, err := r.Int64() 230 if err != nil { 231 return err 232 } 233 l.Login, l.LastInput = time.Unix(v, 0), time.Unix(i, 0) 234 if err = l.From.UnmarshalStream(r); err != nil { 235 return err 236 } 237 if err = r.ReadString(&l.User); err != nil { 238 return err 239 } 240 return r.ReadString(&l.Host) 241 }