1 /* 2 * Copyright (c) 2002-2016, the original author or authors. 3 * 4 * This software is distributable under the BSD license. See the terms of the 5 * BSD license in the documentation provided with this software. 6 * 7 * https://opensource.org/licenses/BSD-3-Clause 8 */ 9 package jdk.internal.org.jline.terminal; 10 11 import java.util.EnumMap; 12 import java.util.EnumSet; 13 import java.util.function.Function; 14 import java.util.stream.Collectors; 15 16 public class Attributes { 17 18 /** 19 * Control characters 20 */ 21 public enum ControlChar { 22 VEOF, 23 VEOL, 24 VEOL2, 25 VERASE, 26 VWERASE, 27 VKILL, 28 VREPRINT, 29 VINTR, 30 VQUIT, 31 VSUSP, 32 VDSUSP, 33 VSTART, 34 VSTOP, 35 VLNEXT, 36 VDISCARD, 37 VMIN, 38 VTIME, 39 VSTATUS 40 } 41 42 /** 43 * Input flags - software input processing 44 */ 45 public enum InputFlag { 46 IGNBRK, /* ignore BREAK condition */ 47 BRKINT, /* map BREAK to SIGINTR */ 48 IGNPAR, /* ignore (discard) parity errors */ 49 PARMRK, /* mark parity and framing errors */ 50 INPCK, /* enable checking of parity errors */ 51 ISTRIP, /* strip 8th bit off chars */ 52 INLCR, /* map NL into CR */ 53 IGNCR, /* ignore CR */ 54 ICRNL, /* map CR to NL (ala CRMOD) */ 55 IXON, /* enable output flow control */ 56 IXOFF, /* enable input flow control */ 57 IXANY, /* any char will restart after stop */ 58 IMAXBEL, /* ring bell on input queue full */ 59 IUTF8 /* maintain state for UTF-8 VERASE */ 60 } 61 62 /* 63 * Output flags - software output processing 64 */ 65 public enum OutputFlag { 66 OPOST, /* enable following output processing */ 67 ONLCR, /* map NL to CR-NL (ala CRMOD) */ 68 OXTABS, /* expand tabs to spaces */ 69 ONOEOT, /* discard EOT's (^D) on output) */ 70 OCRNL, /* map CR to NL on output */ 71 ONOCR, /* no CR output at column 0 */ 72 ONLRET, /* NL performs CR function */ 73 OFILL, /* use fill characters for delay */ 74 NLDLY, /* \n delay */ 75 TABDLY, /* horizontal tab delay */ 76 CRDLY, /* \r delay */ 77 FFDLY, /* form feed delay */ 78 BSDLY, /* \b delay */ 79 VTDLY, /* vertical tab delay */ 80 OFDEL /* fill is DEL, else NUL */ 81 } 82 83 /* 84 * Control flags - hardware control of terminal 85 */ 86 public enum ControlFlag { 87 CIGNORE, /* ignore control flags */ 88 CS5, /* 5 bits (pseudo) */ 89 CS6, /* 6 bits */ 90 CS7, /* 7 bits */ 91 CS8, /* 8 bits */ 92 CSTOPB, /* send 2 stop bits */ 93 CREAD, /* enable receiver */ 94 PARENB, /* parity enable */ 95 PARODD, /* odd parity, else even */ 96 HUPCL, /* hang up on last close */ 97 CLOCAL, /* ignore modem status lines */ 98 CCTS_OFLOW, /* CTS flow control of output */ 99 CRTS_IFLOW, /* RTS flow control of input */ 100 CDTR_IFLOW, /* DTR flow control of input */ 101 CDSR_OFLOW, /* DSR flow control of output */ 102 CCAR_OFLOW /* DCD flow control of output */ 103 } 104 105 /* 106 * "Local" flags - dumping ground for other state 107 * 108 * Warning: some flags in this structure begin with 109 * the letter "I" and look like they belong in the 110 * input flag. 111 */ 112 public enum LocalFlag { 113 ECHOKE, /* visual erase for line kill */ 114 ECHOE, /* visually erase chars */ 115 ECHOK, /* echo NL after line kill */ 116 ECHO, /* enable echoing */ 117 ECHONL, /* echo NL even if ECHO is off */ 118 ECHOPRT, /* visual erase mode for hardcopy */ 119 ECHOCTL, /* echo control chars as ^(Char) */ 120 ISIG, /* enable signals INTR, QUIT, [D]SUSP */ 121 ICANON, /* canonicalize input lines */ 122 ALTWERASE, /* use alternate WERASE algorithm */ 123 IEXTEN, /* enable DISCARD and LNEXT */ 124 EXTPROC, /* external processing */ 125 TOSTOP, /* stop background jobs from output */ 126 FLUSHO, /* output being flushed (state) */ 127 NOKERNINFO, /* no kernel output from VSTATUS */ 128 PENDIN, /* XXX retype pending input (state) */ 129 NOFLSH /* don't flush after interrupt */ 130 } 131 132 final EnumSet<InputFlag> iflag = EnumSet.noneOf(InputFlag.class); 133 final EnumSet<OutputFlag> oflag = EnumSet.noneOf(OutputFlag.class); 134 final EnumSet<ControlFlag> cflag = EnumSet.noneOf(ControlFlag.class); 135 final EnumSet<LocalFlag> lflag = EnumSet.noneOf(LocalFlag.class); 136 final EnumMap<ControlChar, Integer> cchars = new EnumMap<>(ControlChar.class); 137 Attributes()138 public Attributes() { 139 } 140 Attributes(Attributes attr)141 public Attributes(Attributes attr) { 142 copy(attr); 143 } 144 145 // 146 // Input flags 147 // 148 getInputFlags()149 public EnumSet<InputFlag> getInputFlags() { 150 return iflag; 151 } 152 setInputFlags(EnumSet<InputFlag> flags)153 public void setInputFlags(EnumSet<InputFlag> flags) { 154 iflag.clear(); 155 iflag.addAll(flags); 156 } 157 getInputFlag(InputFlag flag)158 public boolean getInputFlag(InputFlag flag) { 159 return iflag.contains(flag); 160 } 161 setInputFlags(EnumSet<InputFlag> flags, boolean value)162 public void setInputFlags(EnumSet<InputFlag> flags, boolean value) { 163 if (value) { 164 iflag.addAll(flags); 165 } else { 166 iflag.removeAll(flags); 167 } 168 } 169 setInputFlag(InputFlag flag, boolean value)170 public void setInputFlag(InputFlag flag, boolean value) { 171 if (value) { 172 iflag.add(flag); 173 } else { 174 iflag.remove(flag); 175 } 176 } 177 178 // 179 // Output flags 180 // 181 getOutputFlags()182 public EnumSet<OutputFlag> getOutputFlags() { 183 return oflag; 184 } 185 setOutputFlags(EnumSet<OutputFlag> flags)186 public void setOutputFlags(EnumSet<OutputFlag> flags) { 187 oflag.clear(); 188 oflag.addAll(flags); 189 } 190 getOutputFlag(OutputFlag flag)191 public boolean getOutputFlag(OutputFlag flag) { 192 return oflag.contains(flag); 193 } 194 setOutputFlags(EnumSet<OutputFlag> flags, boolean value)195 public void setOutputFlags(EnumSet<OutputFlag> flags, boolean value) { 196 if (value) { 197 oflag.addAll(flags); 198 } else { 199 oflag.removeAll(flags); 200 } 201 } 202 setOutputFlag(OutputFlag flag, boolean value)203 public void setOutputFlag(OutputFlag flag, boolean value) { 204 if (value) { 205 oflag.add(flag); 206 } else { 207 oflag.remove(flag); 208 } 209 } 210 211 // 212 // Control flags 213 // 214 getControlFlags()215 public EnumSet<ControlFlag> getControlFlags() { 216 return cflag; 217 } 218 setControlFlags(EnumSet<ControlFlag> flags)219 public void setControlFlags(EnumSet<ControlFlag> flags) { 220 cflag.clear(); 221 cflag.addAll(flags); 222 } 223 getControlFlag(ControlFlag flag)224 public boolean getControlFlag(ControlFlag flag) { 225 return cflag.contains(flag); 226 } 227 setControlFlags(EnumSet<ControlFlag> flags, boolean value)228 public void setControlFlags(EnumSet<ControlFlag> flags, boolean value) { 229 if (value) { 230 cflag.addAll(flags); 231 } else { 232 cflag.removeAll(flags); 233 } 234 } 235 setControlFlag(ControlFlag flag, boolean value)236 public void setControlFlag(ControlFlag flag, boolean value) { 237 if (value) { 238 cflag.add(flag); 239 } else { 240 cflag.remove(flag); 241 } 242 } 243 244 // 245 // Local flags 246 // 247 getLocalFlags()248 public EnumSet<LocalFlag> getLocalFlags() { 249 return lflag; 250 } 251 setLocalFlags(EnumSet<LocalFlag> flags)252 public void setLocalFlags(EnumSet<LocalFlag> flags) { 253 lflag.clear(); 254 lflag.addAll(flags); 255 } 256 getLocalFlag(LocalFlag flag)257 public boolean getLocalFlag(LocalFlag flag) { 258 return lflag.contains(flag); 259 } 260 setLocalFlags(EnumSet<LocalFlag> flags, boolean value)261 public void setLocalFlags(EnumSet<LocalFlag> flags, boolean value) { 262 if (value) { 263 lflag.addAll(flags); 264 } else { 265 lflag.removeAll(flags); 266 } 267 } 268 setLocalFlag(LocalFlag flag, boolean value)269 public void setLocalFlag(LocalFlag flag, boolean value) { 270 if (value) { 271 lflag.add(flag); 272 } else { 273 lflag.remove(flag); 274 } 275 } 276 277 // 278 // Control chars 279 // 280 getControlChars()281 public EnumMap<ControlChar, Integer> getControlChars() { 282 return cchars; 283 } 284 setControlChars(EnumMap<ControlChar, Integer> chars)285 public void setControlChars(EnumMap<ControlChar, Integer> chars) { 286 cchars.clear(); 287 cchars.putAll(chars); 288 } 289 getControlChar(ControlChar c)290 public int getControlChar(ControlChar c) { 291 Integer v = cchars.get(c); 292 return v != null ? v : -1; 293 } 294 setControlChar(ControlChar c, int value)295 public void setControlChar(ControlChar c, int value) { 296 cchars.put(c, value); 297 } 298 299 // 300 // Miscellaneous methods 301 // 302 copy(Attributes attributes)303 public void copy(Attributes attributes) { 304 setControlFlags(attributes.getControlFlags()); 305 setInputFlags(attributes.getInputFlags()); 306 setLocalFlags(attributes.getLocalFlags()); 307 setOutputFlags(attributes.getOutputFlags()); 308 setControlChars(attributes.getControlChars()); 309 } 310 311 @Override toString()312 public String toString() { 313 return "Attributes[" + 314 "lflags: " + append(lflag) + ", " + 315 "iflags: " + append(iflag) + ", " + 316 "oflags: " + append(oflag) + ", " + 317 "cflags: " + append(cflag) + ", " + 318 "cchars: " + append(EnumSet.allOf(ControlChar.class), this::display) + 319 "]"; 320 } 321 display(ControlChar c)322 private String display(ControlChar c) { 323 String value; 324 int ch = getControlChar(c); 325 if (c == ControlChar.VMIN || c == ControlChar.VTIME) { 326 value = Integer.toString(ch); 327 } else if (ch < 0) { 328 value = "<undef>"; 329 } else if (ch < 32) { 330 value = "^" + (char) (ch + 'A' - 1); 331 } else if (ch == 127) { 332 value = "^?"; 333 } else if (ch >= 128) { 334 value = String.format("\\u%04x", ch); 335 } else { 336 value = String.valueOf((char) ch); 337 } 338 return c.name().toLowerCase().substring(1) + "=" + value; 339 } 340 append(EnumSet<T> set)341 private <T extends Enum<T>> String append(EnumSet<T> set) { 342 return append(set, e -> e.name().toLowerCase()); 343 } 344 append(EnumSet<T> set, Function<T, String> toString)345 private <T extends Enum<T>> String append(EnumSet<T> set, Function<T, String> toString) { 346 return set.stream().map(toString).collect(Collectors.joining(" ")); 347 } 348 349 } 350