00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "VestaLog.H"
00029 #include "Recovery.H"
00030 #include <ctype.h>
00031 #include <stdlib.h>
00032 #include <errno.h>
00033
00034 using std::istream;
00035
00036
00037 RecoveryReader::RecoveryReader(VestaLog* vl) throw ()
00038 {
00039 vl_ = vl;
00040 is_ = NULL;
00041 }
00042
00043 RecoveryReader::RecoveryReader(istream* is) throw ()
00044 {
00045 vl_ = NULL;
00046 is_ = is;
00047 }
00048
00049 void
00050 RecoveryReader::get(char &c) throw(VestaLog::Eof, VestaLog::Error)
00051 {
00052 if (vl_ != NULL) {
00053 vl_->get(c);
00054 } else {
00055 if (is_->get(c)) return;
00056 if (is_->bad())
00057 throw VestaLog::Error(errno, Text("RecoveryReader::get got \"") +
00058 Basics::errno_Text(errno) + "\" on read");
00059 throw VestaLog::Eof();
00060 }
00061 }
00062
00063 void
00064 RecoveryReader::get(char* p, int n, char term)
00065 throw(VestaLog::Eof, VestaLog::Error)
00066 {
00067 if (vl_ != NULL) {
00068 vl_->get(p, n, term);
00069 } else {
00070 if (is_->get(p, n, term)) return;
00071 if (is_->bad())
00072 throw VestaLog::Error(errno, Text("RecoveryReader::get got \"") +
00073 Basics::errno_Text(errno) + "\" on read");
00074 throw VestaLog::Eof();
00075 }
00076 }
00077
00078 int
00079 RecoveryReader::read(char* p, int n) throw(VestaLog::Error)
00080 {
00081 if (vl_ != NULL) {
00082 return vl_->read(p, n);
00083 } else {
00084 if (is_->read(p, n)) {
00085 return n;
00086 } else if (is_->bad()) {
00087 throw VestaLog::Error(errno, Text("RecoveryReader::read got \"") +
00088 Basics::errno_Text(errno) + "\" on read");
00089 } else {
00090 return is_->gcount();
00091 }
00092 }
00093 }
00094
00095 void
00096 RecoveryReader::readAll(char* p, int n) throw(VestaLog::Eof, VestaLog::Error)
00097 {
00098 if (vl_ != NULL) {
00099 vl_->readAll(p, n);
00100 return;
00101 } else {
00102 if (is_->read(p, n)) {
00103 return;
00104 } else if (is_->bad()) {
00105 throw VestaLog::Error(errno,
00106 Text("RecoveryReader::readAll got \"") +
00107 Basics::errno_Text(errno) + "\" on read");
00108 } else {
00109 throw VestaLog::Eof();
00110 }
00111 }
00112 }
00113
00114 bool
00115 RecoveryReader::eof() throw(VestaLog::Error)
00116 {
00117 if (vl_ != NULL) {
00118 return vl_->eof();
00119 } else if (is_->peek() == EOF) {
00120 if (is_->bad()) {
00121 throw VestaLog::Error(errno,
00122 Text("RecoveryReader::eof got \"") +
00123 Basics::errno_Text(errno) + "\" on peek");
00124 }
00125 return true;
00126 }
00127 return false;
00128 }
00129
00130
00131
00132
00133 void
00134 RecoveryReader::skipWhite(char& c) throw(VestaLog::Eof, VestaLog::Error)
00135 {
00136 while (isspace(c)) {
00137 this->get(c);
00138 }
00139 }
00140
00141 void
00142 RecoveryReader::requireChar(char& c, char required)
00143 throw(VestaLog::Eof, VestaLog::Error)
00144 {
00145 this->skipWhite(c);
00146 if (c != required) {
00147 throw VestaLog::Error(0, Text("RecoveryReader::requireChar: ") +
00148 "expected '" + required + "'; got '" + c + "'");
00149 }
00150 this->get(c);
00151 }
00152
00153 void
00154 RecoveryReader::getIdent(char& c, Ident id)
00155 throw(VestaLog::Eof, VestaLog::Error)
00156 {
00157 int guard = sizeof(Ident) - 1;
00158 char* p = &id[0];
00159 this->skipWhite(c);
00160 while (isalnum(c)) {
00161 if (guard-- <= 0) {
00162 id[sizeof(Ident) - 1] = '\0';
00163 throw VestaLog::Error(0, Text("RecoveryReader::getIdent: ") +
00164 "ident too long: " + id + "...");
00165 }
00166 *p++ = c;
00167 this->get(c);
00168 }
00169 *p = '\0';
00170 }
00171
00172 void
00173 RecoveryReader::getLong(char& c, long& n)
00174 throw(VestaLog::Eof, VestaLog::Error)
00175 {
00176 char digits[256];
00177 char *endptr;
00178 int guard = sizeof(digits) - 1;
00179 char* p = &digits[0];
00180 this->skipWhite(c);
00181 while (isxdigit(c) || c == 'x' || c == 'X' || c == '-' || c == '+') {
00182 if (guard-- <= 0) {
00183 digits[sizeof(Ident) - 1] = '\0';
00184 throw VestaLog::Error(0, Text("RecoveryReader::getLong: ") +
00185 "number too long: " + digits + "...");
00186 }
00187 *p++ = c;
00188 this->get(c);
00189 }
00190 *p = '\0';
00191 n = strtol(digits, &endptr, 0);
00192 if (*endptr != '\0') {
00193 n = 0;
00194 throw VestaLog::Error(0, Text("RecoveryReader::getLong: ") +
00195 "garbled number: " + digits);
00196 }
00197 }
00198
00199 void
00200 RecoveryReader::getULong(char& c, unsigned long& n)
00201 throw(VestaLog::Eof, VestaLog::Error)
00202 {
00203 char digits[256];
00204 char *endptr;
00205 int guard = sizeof(digits) - 1;
00206 char* p = &digits[0];
00207 this->skipWhite(c);
00208 while (isxdigit(c) || c == 'x' || c == 'X' || c == '-' || c == '+') {
00209 if (guard-- <= 0) {
00210 digits[sizeof(Ident) - 1] = '\0';
00211 throw VestaLog::Error(0, Text("RecoveryReader::getULong: ") +
00212 "number too long: " + digits + "...");
00213 }
00214 *p++ = c;
00215 this->get(c);
00216 }
00217 *p = '\0';
00218 n = strtoul(digits, &endptr, 0);
00219 if (*endptr != '\0') {
00220 n = 0;
00221 throw VestaLog::Error(0, Text("RecoveryReader::getULong: ") +
00222 "garbled number: " + digits);
00223 }
00224 }
00225
00226 void
00227 RecoveryReader::getLongId(char& c, Byte32& value)
00228 throw(VestaLog::Eof, VestaLog::Error)
00229 {
00230 int i;
00231 char chr[3];
00232 chr[2] = '\000';
00233 this->skipWhite(c);
00234 if (!isxdigit(c)) {
00235 throw VestaLog::Error(0, Text("RecoveryReader::getLongId: ") +
00236 "bad LongId: " + c + "...");
00237 }
00238 for (i=0; i<32; i++) {
00239 if (!isxdigit(c)) break;
00240 int byte;
00241 chr[0] = c;
00242 this->get(c);
00243 if (isxdigit(c)) {
00244 chr[1] = c;
00245 this->get(c);
00246 } else {
00247 chr[1] = '0';
00248 }
00249 value.byte[i] = strtol(chr, NULL, 16);
00250 }
00251 for (; i<32; i++) {
00252 value.byte[i] = 0;
00253 }
00254 }
00255
00256 void
00257 RecoveryReader::getQuotedString(char& c, char* buf, int maxLen)
00258 throw(VestaLog::Eof, VestaLog::Error)
00259 {
00260 this->skipWhite(c);
00261 this->requireChar(c, '\"');
00262 char *p = buf;
00263 while (maxLen > 0) {
00264 if (c == '\\') {
00265 this->get(c);
00266 *p++ = c;
00267 maxLen--;
00268 this->get(c);
00269 } else if (c == '\"') {
00270 *p = '\000';
00271 this->get(c);
00272 return;
00273 } else if (c == '\000') {
00274 *p = '\000';
00275 throw
00276 VestaLog::Error(0, Text("RecoveryReader::getQuotedString: ") +
00277 "illegal null character after: " + buf);
00278 } else {
00279 *p++ = c;
00280 maxLen--;
00281 this->get(c);
00282 }
00283 }
00284 *--p = '\000';
00285 throw VestaLog::Error(0, Text("RecoveryReader::getQuotedString: ") +
00286 "string too long: " + buf + "...\n");
00287 }
00288
00289 void
00290 RecoveryReader::getNewQuotedString(char& c, char*& string)
00291 throw(VestaLog::Eof, VestaLog::Error)
00292 {
00293 this->skipWhite(c);
00294 this->requireChar(c, '\"');
00295 int stringLen = 64;
00296 int len = 0;
00297 char* p = string = NEW_PTRFREE_ARRAY(char, stringLen);
00298 for (;;) {
00299 while (len < stringLen) {
00300 if (c == '\\') {
00301 this->get(c);
00302 *p++ = c;
00303 len++;
00304 this->get(c);
00305 } else if (c == '\"') {
00306 *p = '\000';
00307 this->get(c);
00308 return;
00309 } else if (c == '\000') {
00310 *p = '\000';
00311 VestaLog::Error
00312 f(0, Text("RecoveryReader::getNewQuotedString: ") +
00313 "illegal null character after: " + string);
00314 delete [] string;
00315 throw f;
00316 } else {
00317 *p++ = c;
00318 len++;
00319 this->get(c);
00320 }
00321 }
00322
00323 int oldLen = stringLen;
00324 char *oldString = string;
00325 stringLen *= 2;
00326 string = NEW_PTRFREE_ARRAY(char, stringLen);
00327 memcpy(string, oldString, oldLen);
00328 delete [] oldString;
00329
00330 p = &string[len];
00331 }
00332 }
00333
00334 struct RecoveryDispatch {
00335 RecoveryDispatch* next;
00336 char* id;
00337 RecoveryCallback* rc;
00338 };
00339
00340
00341 static RecoveryDispatch* RDHead;
00342
00343 void
00344 RegisterRecoveryCallback(RecoveryReader::Ident id, RecoveryCallback* rc)
00345 throw ()
00346 {
00347 RecoveryDispatch* rd = NEW(RecoveryDispatch);
00348 rd->next = RDHead;
00349 rd->id = strdup(id);
00350 rd->rc = rc;
00351 RDHead = rd;
00352 }
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 void
00363 RecoverFrom(RecoveryReader* rr) throw(VestaLog::Error)
00364 {
00365 char c;
00366 RecoveryReader::Ident id;
00367
00368 try {
00369 try {
00370 rr->get(c);
00371 } catch (VestaLog::Eof) {
00372 return;
00373 }
00374 for (;;) {
00375 try {
00376 rr->skipWhite(c);
00377 } catch (VestaLog::Eof) {
00378 return;
00379 }
00380 rr->requireChar(c, '(');
00381 rr->skipWhite(c);
00382 rr->getIdent(c, id);
00383
00384
00385 RecoveryDispatch* rd = RDHead;
00386 for (;;) {
00387 if (rd == NULL) {
00388 throw VestaLog::Error(0,
00389 Text("RecoveryReader::recoverFrom: unknown record type ")
00390 + id);
00391 }
00392 if (strcmp(id, rd->id) == 0) {
00393 rd->rc(rr, c);
00394 break;
00395 }
00396 rd = rd->next;
00397 }
00398
00399 try {
00400 rr->requireChar(c, ')');
00401 } catch (VestaLog::Eof) {
00402 return;
00403 }
00404 }
00405 } catch (VestaLog::Eof) {
00406 throw VestaLog::Error(0,
00407 "RecoveryReader::recoverFrom: unexpected end of file");
00408 }
00409 }