00001 /* 00002 * Character.cc 00003 * 00004 * Smalltalk like class library for C++ 00005 * Character wrapper. 00006 * 00007 * Copyright (c) 2003-5 Milan Cermak 00008 */ 00009 /* 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with this library; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 */ 00024 #include <stlib/Character.h> 00025 #include <stlib/Association.h> 00026 #include <stlib/Dictionary.h> 00027 #include <stlib/Integer.h> 00028 #include <stlib/String.h> 00029 #include <stlib/Stream.h> 00030 #include <stlib/Visitor.h> 00031 00032 #include <ctype.h> 00033 00034 Dictionary *Character::character_store = nil; 00035 00036 Character::Character(unsigned long val) 00037 { 00038 _value = val; 00039 } 00040 00041 /* Class-accessing protocol */ 00042 String *Character::className(void) const 00043 { 00044 return new String("Character"); 00045 } 00046 00047 Dictionary *Character::characterStore(void) 00048 { 00049 if (character_store == nil) 00050 character_store = new Dictionary(128); 00051 return character_store; 00052 } 00053 00054 /* Class-constants protocol */ 00055 Character *Character::cr(void) 00056 { 00057 return value('\r'); 00058 } 00059 00060 Character *Character::lf(void) 00061 { 00062 return value('\n'); 00063 } 00064 00065 Character *Character::space(void) 00066 { 00067 return value(32); 00068 } 00069 00070 Character *Character::tab(void) 00071 { 00072 return value('\t'); 00073 } 00074 00075 /* Instance creation protocol */ 00076 Character *Character::value(unsigned long val) 00077 { 00078 return Character::value(Integer::value(val)); 00079 } 00080 00081 Character *Character::value(Integer *val) 00082 { 00083 /* Can't use Dictionary>>#at:ifAbsent: method 'cause it raises exception 00084 that may need to construct more Characters. */ 00085 Character *chr; 00086 int index = characterStore()->findKeyOrNil(val); 00087 if (characterStore()->isEmptyAt(index)) { 00088 /* Need to construct new one */ 00089 chr = new Character(val->asUnsignedLong()); 00090 characterStore()->atNewIndexPut(index, new Association(val, chr)); 00091 } else { 00092 /* OK now. Sure it's there. */ 00093 Association *assoc = dynamic_cast<Association *>(characterStore()->privAtIndex(index)); 00094 chr = dynamic_cast<Character *>(assoc->value()); 00095 } 00096 return chr; 00097 } 00098 00099 /* Accessing protocol */ 00100 int Character::byteSize(void) 00101 { 00102 if (_value < 256) return 1; 00103 if (_value < 65536) return 2; 00104 return 4; 00105 } 00106 00107 int Character::digitValue(void) 00108 { 00109 int code = asInteger(); 00110 int val = code - '0'; 00111 if (val <= 9) return val; 00112 val = code - 'A'; 00113 if (val >= 0 && val < 26) return val + 10; 00114 val = code - 'a'; 00115 if (val >= 0 && val < 26) return val + 10; 00116 return -1; 00117 } 00118 00119 /* Comparing protocol */ 00120 long Character::hash(void) const 00121 { 00122 return (long) _value; 00123 } 00124 00125 bool Character::isEqual(const Object *object) const 00126 { 00127 if (object == nil) return false; 00128 00129 return object->isCharacter() && 00130 _value == ((Character *) object)->_value; 00131 } 00132 00133 bool Character::isEqual(char cChar) const 00134 { 00135 return _value == cChar; 00136 } 00137 00138 /* Converting protocol */ 00139 unsigned long Character::asInteger(void) 00140 { 00141 return _value; 00142 } 00143 00144 Character *Character::asLowercase(void) 00145 { 00146 return value(tolower(_value)); 00147 } 00148 00149 Character *Character::asUppercase(void) 00150 { 00151 return value(toupper(_value)); 00152 } 00153 00154 /* Printing protocol */ 00155 void Character::printOn(Stream *stream) const 00156 { 00157 stream->nextPut('\''); 00158 stream->nextPut(_value); 00159 stream->nextPutAll("\' /* "); 00160 stream->nextPutAll(String::format("0x%02X", _value)); 00161 stream->nextPutAll(" */"); 00162 } 00163 00164 /* Testing protocol */ 00165 bool Character::isCharacter(void) const 00166 { 00167 return true; 00168 } 00169 00170 bool Character::isSeparator(void) const 00171 { 00172 return isspace(_value); 00173 } 00174 00175 bool Character::isVowel(void) const 00176 { 00177 char upperCase = toupper(_value); 00178 return upperCase == 'A' || upperCase == 'E' || upperCase == 'I' || 00179 upperCase == 'Y' || upperCase == 'O' || upperCase == 'U'; 00180 } 00181 00182 bool Character::isDigit(void) const 00183 { 00184 return isdigit(_value); 00185 } 00186 00187 bool Character::isLowercase(void) const 00188 { 00189 return islower(_value); 00190 } 00191 00192 bool Character::isUppercase(void) const 00193 { 00194 return isupper(_value); 00195 } 00196 00197 /* Visiting protocol */ 00198 void Character::visitBy(Visitor *visitor) 00199 { 00200 visitor->visitCharacter(this); 00201 }