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