00001 /* 00002 File: String.cc 00003 00004 Function: Implements string class 00005 00006 Author: Andrew Willmott 00007 00008 Notes: 00009 */ 00010 00011 00012 #include "cl/String.h" 00013 #include "cl/CLConfig.h" 00014 00015 #include <stdio.h> 00016 #include <ctype.h> 00017 #include <stdlib.h> 00018 #include <stdarg.h> 00019 00020 String::String(StrConst s) : Array<Char>(s.Length() + 1) 00021 { 00022 strcpy(item, s); 00023 } 00024 00025 String &String::operator = (StrConst s) 00026 { 00027 Assert(!s.IsNull(), "(String::=) Can't assign null to a String"); 00028 00029 SetSize(s.Length() + 1); 00030 strcpy(item, s); 00031 00032 return(SELF); 00033 } 00034 00035 String &String::operator = (const Char *s) 00036 { 00037 Assert(s != 0, "(String::=) Can't assign null to a String"); 00038 00039 SetSize(strlen(s) + 1); 00040 strcpy(item, s); 00041 00042 return(SELF); 00043 } 00044 00045 String &String::Append(StrConst s) 00046 { 00047 Int start = Length(); 00048 Add(s.Length()); 00049 strcpy(item + start, s); 00050 return(SELF); 00051 } 00052 00053 String &String::Insert(StrConst s, Int position) 00054 { 00055 Int len = s.Length(); 00056 00057 Array<Char>::Insert(position, len); 00058 memcpy(item + position, s, len); 00059 00060 return(SELF); 00061 } 00062 00063 String &String::Delete(Int start, Int length) 00064 { 00065 Array<Char>::Delete(start, length); 00066 return(SELF); 00067 } 00068 00069 // --- StrConst class --------------------------------------------------------------- 00070 00071 Int StrConst::FindChar(Char c) const 00072 { 00073 Char *s = strchr(theString, c); 00074 00075 if (s) 00076 return((s - theString)); 00077 else 00078 return(-1); 00079 } 00080 00081 Int StrConst::FindCharLast(Char c) const 00082 { 00083 Char *s = strrchr(theString, c); 00084 00085 if (s) 00086 return((s - theString)); 00087 else 00088 return(-1); 00089 } 00090 00091 String StrConst::SubString(Int start, Int length) 00092 { 00093 String result; 00094 Int strLength = Length(); 00095 00096 if (length > 0) 00097 { 00098 if (start < 0) 00099 start = Max(0, Length() + start); 00100 else 00101 start = Min(strLength, start); 00102 00103 length = Min(length, strLength - start); 00104 00105 result.SetSize(length + 1); 00106 memcpy(result.item, theString + start, length); 00107 result.item[length] = 0; 00108 } 00109 00110 return(result); 00111 } 00112 00113 String StrConst::Prefix(Int length) 00114 { 00115 String result; 00116 Int strLength = Length(); 00117 00118 if (length < 0) 00119 length = Max(0, strLength + length); 00120 else 00121 length = Min(strLength, length); 00122 00123 result.SetSize(length + 1); 00124 memcpy(result.item, theString, length); 00125 result.item[length] = 0; 00126 00127 return(result); 00128 } 00129 00130 String StrConst::Suffix(Int length) 00131 { 00132 String result; 00133 Int strLength = Length(), offset; 00134 00135 if (length < 0) 00136 offset = Min(strLength, -length); 00137 else 00138 offset = Max(0, strLength - length); 00139 00140 result = (theString + offset); 00141 00142 return(result); 00143 } 00144 00145 istream &String::ReadString(istream &s) 00146 { 00147 Char c; 00148 00149 // Expected format: "... " 00150 00151 while (isspace(s.peek())) // chomp white space 00152 s.get(c); 00153 00154 if (s.peek() == '"') 00155 { 00156 s.get(c); 00157 Clear(); 00158 00159 while (s.peek() != '"') 00160 { 00161 s.get(c); 00162 00163 if (!s) 00164 { 00165 Expect(false, "Couldn't read array component"); 00166 return(s); 00167 } 00168 else 00169 Array<Char>::Append(c); 00170 } 00171 s.get(c); 00172 } 00173 else 00174 { 00175 s.clear(ios::failbit); 00176 Expect(false, "Error: Expected '\"' while reading string"); 00177 return(s); 00178 } 00179 00180 Array<Char>::Append(0); 00181 00182 return(s); 00183 } 00184 00185 istream &operator >> (istream &s, String &str) 00186 { 00187 // We default to reading a string. Use the other Read... methods to 00188 // read/parse other types of data. 00189 00190 str.ReadString(s); 00191 return(s); 00192 } 00193 00194 istream &String::ReadWord(istream &s) 00195 { 00196 Char c; 00197 00198 // Expected format: "... " 00199 00200 while (isspace(s.peek())) // chomp white space 00201 s.get(c); 00202 00203 Clear(); 00204 00205 while (!isspace(s.peek())) 00206 { 00207 s.get(c); 00208 00209 if (!s) 00210 { 00211 Expect(false, "Couldn't read word"); 00212 return(s); 00213 } 00214 else 00215 Array<Char>::Append(c); 00216 } 00217 00218 Array<Char>::Append(0); 00219 00220 return(s); 00221 } 00222 00223 int iseol(int c) 00224 { 00225 return(c == 0x0a || c == 0x0d); 00226 } 00227 00228 istream &String::ReadLine(istream &s) 00229 { 00230 Char c; 00231 00232 Clear(); 00233 00234 while (1) 00235 { 00236 s.get(c); 00237 00238 if (!s || iseol(c)) 00239 break; 00240 else 00241 Array<Char>::Append(c); 00242 } 00243 00244 Array<Char>::Append(0); 00245 00246 return(s); 00247 } 00248 00249 00250 String &String::Printf(const Char *format, ...) 00251 { 00252 static Char buffer[2048]; 00253 Int size; 00254 va_list ap; 00255 00256 va_start(ap, format); 00257 #ifdef CL_HAS_VSNPRINTF 00258 size = vsnprintf(buffer, 2048, format, ap); 00259 #else 00260 size = vsprintf(buffer, format, ap); 00261 #endif 00262 00263 if (size >= 0) 00264 { 00265 SetSize(size + 1); 00266 strcpy(item, buffer); 00267 } 00268 else 00269 SELF = "<string too large>"; 00270 00271 va_end(ap); 00272 00273 return(SELF); 00274 } 00275 00276 // --- String utilities ------------------------------------------- 00277 00278 00279 Bool IsEndOfLine(istream &s) 00280 { 00281 char c; 00282 00283 while (isspace(s.peek()) && !iseol(s.peek())) 00284 s.get(c); 00285 00286 return(iseol(s.peek())); 00287 } 00288 00289 Void ChompWhiteSpace(istream &s) 00290 { 00291 char c; 00292 00293 while (isspace(s.peek())) // chomp white space 00294 s.get(c); 00295 } 00296 00297 TempString SubstituteEnvVars(StrConst s) 00298 { 00299 StrConst varStart, varSub, oldVarStart; 00300 String var; 00301 TempString result; 00302 Int vlen; 00303 00304 varStart = s; 00305 00306 while (varStart) 00307 { 00308 oldVarStart = varStart; 00309 varStart = strchr(varStart, '$'); 00310 00311 if (varStart) 00312 { 00313 result += oldVarStart.Prefix((varStart - oldVarStart)); 00314 vlen = strcspn(varStart, "/- \t}.,;\"'"); 00315 var = varStart.SubString(1, vlen - 1); 00316 00317 varStart = varStart + vlen; 00318 if (var[0] == '{' && varStart[0] == '}') 00319 { 00320 varStart = varStart + 1; 00321 var = var.Suffix(-1); 00322 } 00323 varSub = getenv(var.CString()); 00324 if (varSub) 00325 result += varSub; 00326 else 00327 result += "<" + var + ">"; 00328 } 00329 } 00330 00331 result += oldVarStart; 00332 00333 return(result); 00334 } 00335 00336 Void Split(StrConst line, StrConstArray &a, StrConst sep) 00337 // Splits 'line' into an array of tokens 'a', where each token is separated 00338 // by the characters in "sep" (default is white space). 00339 { 00340 static String buffer; 00341 StrConst s; 00342 00343 buffer = line; 00344 a.Clear(); 00345 s = strtok(buffer.CString(), sep); 00346 if (!s) 00347 return; 00348 a.Append(s); 00349 while (s = strtok(0, sep)) 00350 a.Append(s); 00351 } 00352 00353 #ifdef CL_TMPL_INST 00354 template class Array<Char>; 00355 #endif