KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > text > Char


1 package gnu.text;
2 import java.io.*;
3 import java.util.Hashtable JavaDoc;
4 import gnu.lists.Consumer;
5
6 /**
7  * A wrapper for characters.
8  * #author Per Bothner
9  */

10
11 /*
12  * This is similar to java.lang.Character, so why don't we just use that?
13  * Good question, since this new class makes us a little less compatible
14  * with "standard" Java. However, that should be fairly minor, since
15  * few methods will require Character parameters or arrays (better to
16  * just use chars then).
17  * The Char class uses hashing to ensure that characters are unique.
18  * Thus equal? Char are eq?, which is convenient.
19  * Also, using our own class lets us make sure it implements Printable.
20  * Finally, we can use 32-bit character values to allow for non-Unicode chars.
21  */

22
23 public class Char
24   implements
25   /* #ifdef JAVA2 */
26   Comparable JavaDoc,
27   /* #endif */
28   Externalizable
29 {
30   // Leave open the possibility for characters beyond Unicode.
31
int value;
32
33   /** Should only be used for serialization. */
34   public Char ()
35   {
36   }
37
38   private Char (int ch)
39   {
40     value = ch;
41   }
42
43   public void print (Consumer out)
44   {
45     print(value, out);
46   }
47
48   public static void print (int i, Consumer out)
49   {
50     if (i >= 0x10000)
51       {
52         out.write((char) (((i - 0x10000) >> 10) + 0xD800));
53         out.write((char) ((i & 0x3FF) + 0xDC00));
54       }
55     else
56       out.write((char) i);
57   }
58
59   public final char charValue ()
60   {
61     return (char) value;
62   }
63
64   public final int intValue ()
65   {
66     return value;
67   }
68
69   public int hashCode ()
70   {
71     return value;
72   }
73
74   static Char[] ascii;
75
76   static Char temp = new Char (0);
77   static Hashtable JavaDoc hashTable;
78
79   static
80   {
81     ascii = new Char[128];
82     for (int i = 128; --i >= 0; )
83       ascii[i] = new Char(i);
84   }
85
86   public static Char make (int ch)
87   {
88     if (ch < 128)
89       return ascii[ch];
90     else
91       {
92     // Re-writing this will allow equals to just use ==. FIXME.
93
temp.value = ch;
94     if (hashTable == null)
95       hashTable = new Hashtable JavaDoc ();
96     Object JavaDoc entry = hashTable.get (temp);
97     if (entry != null)
98       return (Char) entry;
99     Char newChar = new Char (ch);
100     hashTable.put (newChar, newChar);
101     return newChar;
102       }
103   }
104
105   public boolean equals (Object JavaDoc obj)
106   {
107     // This does not work for hashing in make! Redo make! FIXME
108
// return this == obj;
109
return obj != null && (obj instanceof Char)
110       && ((Char)obj).intValue() == value;
111   }
112
113   static char[] charNameValues = { ' ', '\t', '\n', '\n'
114                    ,'\r', '\f', '\b',
115                    '\033', '\177', '\177', '\007', '\0' };
116   static String JavaDoc[] charNames = { "space",
117                 "tab",
118                 "newline",
119                 "linefeed",
120                 "return",
121                 "page",
122                 "backspace",
123                 "esc",
124                 "del",
125                 "rubout",
126                 "bel",
127                 "nul"};
128
129   public static int nameToChar(String JavaDoc name)
130   {
131     for (int i = charNames.length; --i >= 0 ; )
132       {
133         if (charNames[i].equals(name))
134           return charNameValues[i];
135       }
136     for (int i = charNames.length; --i >= 0 ; )
137       {
138         if (charNames[i].equalsIgnoreCase(name))
139           return charNameValues[i];
140       }
141     int len = name.length();
142     if (len > 1 && name.charAt(0) == 'u')
143       {
144     int value = 0;
145     for (int pos = 1; ; pos++)
146       {
147         if (pos == len)
148           return value;
149         int dig = Character.digit(name.charAt(pos), 16);
150         if (dig < 0)
151           break;
152         value = (value << 4) + dig;
153       }
154       }
155
156     // Check for Emacs control character syntax.
157
if (len == 3 && name.charAt(1) == '-')
158       {
159     char ch = name.charAt(0);
160     if (ch == 'c' || ch == 'C')
161       {
162         ch = name.charAt(2);
163         return ch & 31;
164       }
165       }
166
167     return -1;
168   }
169
170   public String JavaDoc toString ()
171   {
172     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
173     buf.append('\'');
174     if (value >= (int) ' ' && value < 127 && value != '\'')
175       buf.append((char) value);
176     else
177       {
178     buf.append('\\');
179     if (value == '\'')
180       buf.append('\'');
181     else if (value == '\n')
182       buf.append('n');
183     else if (value == '\r')
184       buf.append('r');
185     else if (value == '\t')
186       buf.append('t');
187     else if (value < 256)
188       {
189         String JavaDoc str = Integer.toOctalString(value);
190         for (int i = 3 - str.length(); --i >= 0; )
191           buf.append('0');
192         buf.append(str);
193       }
194     else
195       {
196         buf.append('u');
197         String JavaDoc str = Integer.toHexString(value);
198         for (int i = 4 - str.length(); --i >= 0; )
199           buf.append('0');
200         buf.append(str);
201       }
202       }
203     buf.append('\'');
204     return buf.toString();
205   }
206
207   public static String JavaDoc toScmReadableString (int ch)
208   {
209     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(20);
210     sbuf.append("#\\");
211     for (int i = 0; i < charNameValues.length; i++)
212       {
213     if ((char) ch == charNameValues[i])
214       {
215         sbuf.append(charNames[i]);
216         return sbuf.toString();
217       }
218       }
219     if (ch < 8)
220       {
221     sbuf.append('0'); // make sure there at least two octal digits
222
sbuf.append(ch);
223       }
224     else if (ch < ' ' || ch > 0x7F)
225       {
226     sbuf.append(Integer.toString(ch, 8));
227       }
228     else
229       sbuf.append((char) ch);
230     return sbuf.toString();
231   }
232
233   /**
234    * @serialData Writes the char value as a char.
235    * If the value is > 0xFFFF, write a pair of surrogate values.
236    * If the value is is a high surrogate only, write it followed by '\0'.
237    */

238   public void writeExternal(ObjectOutput out) throws IOException
239   {
240     if (value > 0xD800)
241       {
242     if (value > 0xFFFF)
243       {
244         out.writeChar(((value - 0x10000) >> 10) + 0xD800);
245         value = (value & 0x3FF) + 0xDC00;
246       }
247     else if (value <= 0xDBFF)
248       {
249         out.writeChar(value);
250         value = '\0';
251       }
252       }
253     out.writeChar(value);
254   }
255
256   public void readExternal(ObjectInput in)
257     throws IOException, ClassNotFoundException JavaDoc
258   {
259     value = in.readChar();
260     if (value >= 0xD800 && value < 0xDBFF)
261       {
262     char next = in.readChar();
263     if (next >= 0xDC00 && next <= 0xDFFF)
264       value = ((value - 0xD800) << 10) + (next - 0xDC00) + 0x10000;
265       }
266   }
267
268   public Object JavaDoc readResolve() throws ObjectStreamException
269   {
270     return make(value);
271   }
272
273   public int compareTo(Object JavaDoc o)
274   {
275     return value - ((Char) o).value;
276   }
277 }
278
Popular Tags