* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / corlib / System / TermInfoReader.cs
1 //
2 // System.TermInfoReader
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 #if NET_2_0
31 using System.IO;
32 using System.Text;
33 namespace System {
34         // This class reads data from a byte array or file containing the terminfo capabilities
35         // information for any given terminal. The maximum allowed size is 4096 bytes.
36         //
37         // Terminfo database files are divided in the following sections:
38         //
39         //      Header
40         //      Terminal names
41         //      Boolean capabilities
42         //      Numeric capabilities
43         //      Offset of string capabilities
44         //      String capabilities
45         //
46         // The header is as follows:
47         //
48         //      Magic number (0x1 and 0x1A)
49         //      Terminal names size
50         //      Boolean section size
51         //      Numeric section size
52         //      String offsets section size
53         //      Strings size
54         //
55         // After the header, there's a NUL terminated string containing terminal names separated
56         // by the character '|'. The last one is the terminal description.
57         //
58         // The boolean capabilities section has bytes that are set to 1 if the capability is supported
59         // and 0 otherwise. If the index of a capability is greater than the section size, 0 is assumed.
60         //
61         // The numeric capabilities section holds 2-byte integers in little endian format. No negative
62         // values are allowed and the absence of a capability is marked as two 0xFF.
63         //
64         // The string offsets section contains 2-byte integer offsets into the string capabilies section.
65         // If the capability is not supported, the index will be two 0xFF bytes.
66         //
67         // The string capabilities section contains NUL terminated strings starting at the offsets found
68         // in the previous section.
69         //
70         // Terminal capabilities indexes are found in /usr/include/term.h file and described in
71         // 'man 5 terminfo'.
72         //
73
74         class TermInfoReader {
75                 short nameSize;
76                 short boolSize;
77                 short numSize;
78                 short strOffsets;
79                 short strSize;
80
81                 string [] names; // Last one is the description
82                 byte [] buffer;
83                 int booleansOffset;
84                 string term;
85
86                 public TermInfoReader (string term, string filename)
87                 {
88                         using (FileStream st = File.OpenRead (filename)) {
89                                 long length = st.Length;
90                                 if (length > 4096)
91                                         throw new Exception ("File must be smaller than 4K");
92
93                                 buffer = new byte [(int) length];
94                                 if (st.Read (buffer, 0, buffer.Length) != buffer.Length)
95                                         throw new Exception ("Short read");
96
97                                 ReadHeader (buffer, ref booleansOffset);
98                                 ReadNames (buffer, ref booleansOffset);
99                         }
100
101                 }
102
103                 public TermInfoReader (string term, byte [] buffer)
104                 {
105                         if (buffer == null)
106                                 throw new ArgumentNullException ("buffer");
107
108                         this.buffer = buffer;
109                         ReadHeader (buffer, ref booleansOffset);
110                         ReadNames (buffer, ref booleansOffset);
111                 }
112
113                 public string Term {
114                         get { return term; }
115                 }
116
117                 void ReadHeader (byte [] buffer, ref int position)
118                 {
119                         short magic = GetInt16 (buffer, position);
120                         position += 2;
121                         if (magic != 282)
122                                 throw new Exception (String.Format ("Magic number is wrong: {0}", magic));
123                         
124                         nameSize = GetInt16 (buffer, position);
125                         position += 2;
126                         boolSize = GetInt16 (buffer, position);
127                         position += 2;
128                         numSize = GetInt16 (buffer, position);
129                         position += 2;
130                         strOffsets = GetInt16 (buffer, position);
131                         position += 2;
132                         strSize = GetInt16 (buffer, position);
133                         position += 2;
134                 }
135
136                 void ReadNames (byte [] buffer, ref int position)
137                 {
138                         string prev = GetString (buffer, position);
139                         position += prev.Length + 1;
140                         names = prev.Split ('|');
141                 }
142
143                 public bool Get (TermInfoBooleans boolean)
144                 {
145                         int x = (int) boolean;
146                         if (x < 0 || boolean >= TermInfoBooleans.Last || x >= boolSize)
147                                 return false;
148
149                         int offset = booleansOffset;
150                         offset += (int) boolean;
151                         return (buffer [offset] != 0);
152                 }
153
154                 public int Get (TermInfoNumbers number)
155                 {
156                         int x = (int) number;
157                         if (x < 0 || number >= TermInfoNumbers.Last || x > numSize)
158                                 return -1;
159
160                         int offset = booleansOffset + boolSize;
161                         if ((offset % 2) == 1)
162                                 offset++;
163
164                         offset += ((int) number) * 2;
165                         return GetInt16 (buffer, offset);
166                 }
167
168                 public string Get (TermInfoStrings tstr)
169                 {
170                         int x = (int) tstr;
171                         if (x < 0 || tstr >= TermInfoStrings.Last || x > strOffsets)
172                                 return null;
173
174                         int offset = booleansOffset + boolSize;
175                         if ((offset % 2) == 1)
176                                 offset++;
177
178                         offset += numSize * 2;
179                         int off2 = GetInt16 (buffer, offset + (int) tstr * 2);
180                         if (off2 == -1)
181                                 return null;
182
183                         return GetString (buffer, offset + strOffsets * 2 + off2);
184                 }
185
186                 public byte [] GetStringBytes (TermInfoStrings tstr)
187                 {
188                         int x = (int) tstr;
189                         if (x < 0 || tstr >= TermInfoStrings.Last || x > strOffsets)
190                                 return null;
191
192                         int offset = booleansOffset + boolSize;
193                         if ((offset % 2) == 1)
194                                 offset++;
195
196                         offset += numSize * 2;
197                         int off2 = GetInt16 (buffer, offset + (int) tstr * 2);
198                         if (off2 == -1)
199                                 return null;
200
201                         return GetStringBytes (buffer, offset + strOffsets * 2 + off2);
202                 }
203
204                 short GetInt16 (byte [] buffer, int offset)
205                 {
206                         int uno = (int) buffer [offset];
207                         int dos = (int) buffer [offset + 1];
208                         if (uno == 255  && dos == 255)
209                                 return -1;
210
211                         return (short) (uno + dos * 256);
212                 }
213
214                 string GetString (byte [] buffer, int offset)
215                 {
216                         int length = 0;
217                         int off = offset;
218                         while (buffer [off++] != 0)
219                                 length++;
220
221                         return Encoding.ASCII.GetString (buffer, offset, length);
222                 }
223
224                 byte [] GetStringBytes (byte [] buffer, int offset)
225                 {
226                         int length = 0;
227                         int off = offset;
228                         while (buffer [off++] != 0)
229                                 length++;
230
231                         byte [] result = new byte [length];
232                         Buffer.BlockCopyInternal (buffer, offset, result, 0, length);
233                         return result;
234                 }
235
236                 internal static string Escape (string s)
237                 {
238                         StringBuilder sb = new StringBuilder ();
239                         for (int i = 0; i < s.Length; i++) {
240                                 char current = s [i];
241                                 if (Char.IsControl (current)) {
242                                         sb.AppendFormat ("\\x{0:X2}", (int) current);
243                                 } else {
244                                         sb.Append (current);
245                                 }
246                         }
247
248                         return sb.ToString ();
249                 }
250         }
251 }
252 #endif
253