| 153 | | |
|---|
| 154 | | |
|---|
| 155 | | |
|---|
| 156 | | gdbmclass::~gdbmclass() |
|---|
| 157 | | { |
|---|
| 158 | | closedatabase(); |
|---|
| 159 | | } |
|---|
| 160 | | |
|---|
| 161 | | // returns true if opened |
|---|
| 162 | | bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys, |
|---|
| 163 | | #ifdef __WIN32__ |
|---|
| 164 | | bool need_filelock |
|---|
| 165 | | #else |
|---|
| 166 | | bool |
|---|
| 167 | | #endif |
|---|
| 168 | | ) |
|---|
| 169 | | { |
|---|
| 170 | | text_t data_location; |
|---|
| 171 | | int block_size = 512; |
|---|
| 172 | | |
|---|
| 173 | | if (gdbmfile != NULL) { |
|---|
| 174 | | if (openfile == filename) return true; |
|---|
| 175 | | else closedatabase (); |
|---|
| 176 | | } |
|---|
| 177 | | |
|---|
| 178 | | openfile = filename; |
|---|
| 179 | | |
|---|
| 180 | | char *namebuffer = filename.getcstr(); |
|---|
| 181 | | do { |
|---|
| 182 | | #ifdef __WIN32__ |
|---|
| 183 | | gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL, (need_filelock) ? 1 : 0); |
|---|
| 184 | | #else |
|---|
| 185 | | gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL); |
|---|
| 186 | | #endif |
|---|
| 187 | | --num_retrys; |
|---|
| 188 | | } while (num_retrys>0 && gdbmfile==NULL && |
|---|
| 189 | | (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER)); |
|---|
| 190 | | delete []namebuffer; |
|---|
| 191 | | |
|---|
| 192 | | if (gdbmfile == NULL && logout != NULL) { |
|---|
| 193 | | outconvertclass text_t2ascii; |
|---|
| 194 | | (*logout) << text_t2ascii << "database open failed on: " << filename << "\n"; |
|---|
| 195 | | } |
|---|
| 196 | | |
|---|
| 197 | | return (gdbmfile != NULL); |
|---|
| 198 | | } |
|---|
| 199 | | |
|---|
| 200 | | |
|---|
| 201 | | void gdbmclass::closedatabase () |
|---|
| 202 | | { |
|---|
| 203 | | if (gdbmfile == NULL) return; |
|---|
| 204 | | |
|---|
| 205 | | gdbm_close (gdbmfile); |
|---|
| 206 | | gdbmfile = NULL; |
|---|
| 207 | | openfile.clear(); |
|---|
| 208 | | } |
|---|
| 209 | | |
|---|
| 210 | | |
|---|
| 211 | | // returns true on success |
|---|
| 212 | | bool gdbmclass::setinfo (const text_t &key, const infodbclass &info) |
|---|
| 213 | | { |
|---|
| 214 | | if (gdbmfile == NULL) return false; |
|---|
| 215 | | |
|---|
| 216 | | text_t subkey; |
|---|
| 217 | | text_t data; |
|---|
| 218 | | |
|---|
| 219 | | // get all the keys and values |
|---|
| 220 | | infodbclass::const_iterator info_here = info.begin(); |
|---|
| 221 | | infodbclass::const_iterator info_end = info.end(); |
|---|
| 222 | | while (info_here != info_end) { |
|---|
| 223 | | // add the key |
|---|
| 224 | | subkey.clear(); |
|---|
| 225 | | subkey.push_back('<'); |
|---|
| 226 | | text_t::const_iterator subkey_here = (*info_here).first.begin(); |
|---|
| 227 | | text_t::const_iterator subkey_end = (*info_here).first.end(); |
|---|
| 228 | | while (subkey_here != subkey_end) { |
|---|
| 229 | | if (*subkey_here == '>') { |
|---|
| 230 | | subkey.push_back('\\'); subkey.push_back('>'); |
|---|
| 231 | | } else if (*subkey_here == '\n') { |
|---|
| 232 | | subkey.push_back('\\'); subkey.push_back('n'); |
|---|
| 233 | | } else if (*subkey_here == '\r') { |
|---|
| 234 | | subkey.push_back('\\'); subkey.push_back('r'); |
|---|
| 235 | | } else if (*subkey_here == '\\') { |
|---|
| 236 | | subkey.push_back('\\'); subkey.push_back('\\'); |
|---|
| 237 | | } else { |
|---|
| 238 | | subkey.push_back (*subkey_here); |
|---|
| 239 | | } |
|---|
| 240 | | ++subkey_here; |
|---|
| 241 | | } |
|---|
| 242 | | subkey.push_back('>'); |
|---|
| 243 | | |
|---|
| 244 | | // add the values |
|---|
| 245 | | text_tarray::const_iterator subvalue_here = (*info_here).second.begin(); |
|---|
| 246 | | text_tarray::const_iterator subvalue_end = (*info_here).second.end(); |
|---|
| 247 | | while (subvalue_here != subvalue_end) { |
|---|
| 248 | | data += subkey; |
|---|
| 249 | | |
|---|
| 250 | | text_t::const_iterator thissubvalue_here = (*subvalue_here).begin(); |
|---|
| 251 | | text_t::const_iterator thissubvalue_end = (*subvalue_here).end(); |
|---|
| 252 | | while (thissubvalue_here != thissubvalue_end) { |
|---|
| 253 | | if (*thissubvalue_here == '>') { |
|---|
| 254 | | data.push_back('\\'); data.push_back('>'); |
|---|
| 255 | | } else if (*thissubvalue_here == '\n') { |
|---|
| 256 | | data.push_back('\\'); data.push_back('n'); |
|---|
| 257 | | } else if (*thissubvalue_here == '\r') { |
|---|
| 258 | | data.push_back('\\'); data.push_back('r'); |
|---|
| 259 | | } else if (*thissubvalue_here == '\\') { |
|---|
| 260 | | data.push_back('\\'); data.push_back('\\'); |
|---|
| 261 | | } else { |
|---|
| 262 | | data.push_back (*thissubvalue_here); |
|---|
| 263 | | } |
|---|
| 264 | | |
|---|
| 265 | | ++thissubvalue_here; |
|---|
| 266 | | } |
|---|
| 267 | | |
|---|
| 268 | | data.push_back('\n'); |
|---|
| 269 | | ++subvalue_here; |
|---|
| 270 | | } |
|---|
| 271 | | |
|---|
| 272 | | ++info_here; |
|---|
| 273 | | } |
|---|
| 274 | | |
|---|
| 275 | | // store the value |
|---|
| 276 | | datum key_data; |
|---|
| 277 | | datum data_data; |
|---|
| 278 | | |
|---|
| 279 | | // get a utf-8 encoded c string of the unicode key |
|---|
| 280 | | key_data.dptr = (to_utf8(key)).getcstr(); |
|---|
| 281 | | if (key_data.dptr == NULL) { |
|---|
| 282 | | if (logout != NULL) (*logout) << "gdbmclass: out of memory\n"; |
|---|
| 283 | | return false; |
|---|
| 284 | | } |
|---|
| 285 | | key_data.dsize = strlen (key_data.dptr); |
|---|
| 286 | | |
|---|
| 287 | | data_data.dptr = (to_utf8(data)).getcstr(); |
|---|
| 288 | | if (data_data.dptr == NULL) { |
|---|
| 289 | | if (logout != NULL) (*logout) << "gdbmclass: out of memory\n"; |
|---|
| 290 | | delete []key_data.dptr; |
|---|
| 291 | | return false; |
|---|
| 292 | | } |
|---|
| 293 | | data_data.dsize = strlen (data_data.dptr); |
|---|
| 294 | | |
|---|
| 295 | | int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE); |
|---|
| 296 | | delete []key_data.dptr; |
|---|
| 297 | | delete []data_data.dptr; |
|---|
| 298 | | |
|---|
| 299 | | return (ret == 0); |
|---|
| 300 | | } |
|---|
| 301 | | |
|---|
| 302 | | |
|---|
| 303 | | //returns true on success |
|---|
| 304 | | bool gdbmclass::setinfo (const text_t &key, const text_t &data) |
|---|
| 305 | | { |
|---|
| 306 | | if (gdbmfile == NULL) return false; |
|---|
| 307 | | |
|---|
| 308 | | // store the value |
|---|
| 309 | | datum key_data; |
|---|
| 310 | | datum data_data; |
|---|
| 311 | | |
|---|
| 312 | | // get a utf-8 encoded c string of the unicode key |
|---|
| 313 | | key_data.dptr = (to_utf8(key)).getcstr(); |
|---|
| 314 | | if (key_data.dptr == NULL) { |
|---|
| 315 | | if (logout != NULL) (*logout) << "gdbmclass: out of memory\n"; |
|---|
| 316 | | return false; |
|---|
| 317 | | } |
|---|
| 318 | | key_data.dsize = strlen (key_data.dptr); |
|---|
| 319 | | |
|---|
| 320 | | data_data.dptr = (to_utf8(data)).getcstr(); |
|---|
| 321 | | if (data_data.dptr == NULL) { |
|---|
| 322 | | if (logout != NULL) (*logout) << "gdbmclass: out of memory\n"; |
|---|
| 323 | | delete []key_data.dptr; |
|---|
| 324 | | return false; |
|---|
| 325 | | } |
|---|
| 326 | | data_data.dsize = strlen (data_data.dptr); |
|---|
| 327 | | |
|---|
| 328 | | int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE); |
|---|
| 329 | | delete []key_data.dptr; |
|---|
| 330 | | delete []data_data.dptr; |
|---|
| 331 | | |
|---|
| 332 | | return (ret == 0); |
|---|
| 333 | | } |
|---|
| 334 | | |
|---|
| 335 | | |
|---|
| 336 | | void gdbmclass::deletekey (const text_t &key) |
|---|
| 337 | | { |
|---|
| 338 | | if (gdbmfile == NULL) return; |
|---|
| 339 | | |
|---|
| 340 | | // get a utf-8 encoded c string of the unicode key |
|---|
| 341 | | datum key_data; |
|---|
| 342 | | key_data.dptr = (to_utf8(key)).getcstr(); |
|---|
| 343 | | if (key_data.dptr == NULL) return; |
|---|
| 344 | | key_data.dsize = strlen (key_data.dptr); |
|---|
| 345 | | |
|---|
| 346 | | // delete the key |
|---|
| 347 | | gdbm_delete (gdbmfile, key_data); |
|---|
| 348 | | |
|---|
| 349 | | // free up the key memory |
|---|
| 350 | | delete []key_data.dptr; |
|---|
| 351 | | } |
|---|
| 352 | | |
|---|
| 353 | | |
|---|
| 354 | | // getfirstkey and getnextkey are used for traversing the database |
|---|
| 355 | | // no insertions or deletions should be carried out while traversing |
|---|
| 356 | | // the database. when there are no keys left to visit in the database |
|---|
| 357 | | // an empty string is returned. |
|---|
| 358 | | text_t gdbmclass::getfirstkey () |
|---|
| 359 | | { |
|---|
| 360 | | if (gdbmfile == NULL) return g_EmptyText; |
|---|
| 361 | | |
|---|
| 362 | | // get the first key |
|---|
| 363 | | datum firstkey_data = gdbm_firstkey (gdbmfile); |
|---|
| 364 | | if (firstkey_data.dptr == NULL) return g_EmptyText; |
|---|
| 365 | | |
|---|
| 366 | | // convert it to text_t |
|---|
| 367 | | text_t firstkey; |
|---|
| 368 | | firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize); |
|---|
| 369 | | free (firstkey_data.dptr); |
|---|
| 370 | | return to_uni(firstkey); // convert to unicode |
|---|
| 371 | | } |
|---|
| 372 | | |
|---|
| 373 | | |
|---|
| 374 | | text_t gdbmclass::getnextkey (const text_t &key) |
|---|
| 375 | | { |
|---|
| 376 | | if (gdbmfile == NULL || key.empty()) return g_EmptyText; |
|---|
| 377 | | |
|---|
| 378 | | // get a utf-8 encoded c string of the unicode key |
|---|
| 379 | | datum key_data; |
|---|
| 380 | | key_data.dptr = (to_utf8(key)).getcstr(); |
|---|
| 381 | | if (key_data.dptr == NULL) return g_EmptyText; |
|---|
| 382 | | key_data.dsize = strlen (key_data.dptr); |
|---|
| 383 | | |
|---|
| 384 | | // get the next key |
|---|
| 385 | | datum nextkey_data = gdbm_nextkey (gdbmfile, key_data); |
|---|
| 386 | | if (nextkey_data.dptr == NULL) { |
|---|
| 387 | | delete []key_data.dptr; |
|---|
| 388 | | return g_EmptyText; |
|---|
| 389 | | } |
|---|
| 390 | | |
|---|
| 391 | | // convert it to text_t |
|---|
| 392 | | text_t nextkey; |
|---|
| 393 | | nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize); |
|---|
| 394 | | free (nextkey_data.dptr); |
|---|
| 395 | | delete []key_data.dptr; |
|---|
| 396 | | return to_uni(nextkey); // convert to unicode |
|---|
| 397 | | } |
|---|
| 398 | | |
|---|
| 399 | | |
|---|
| 400 | | // replaces the .fc, .lc, .pr, .rt, .ns and .ps syntax (first child, |
|---|
| 401 | | // last child, parent, root, next sibling, previous sibling) |
|---|
| 402 | | // it expects child, parent, etc. to exist if syntax has been used |
|---|
| 403 | | // so you should test before using |
|---|
| 404 | | text_t gdbmclass::translate_OID (const text_t &inOID, infodbclass &info) |
|---|
| 405 | | { |
|---|
| 406 | | if (inOID.size() < 4) return inOID; |
|---|
| 407 | | if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID; |
|---|
| 408 | | |
|---|
| 409 | | text_t OID = inOID; |
|---|
| 410 | | text_tarray tailarray; |
|---|
| 411 | | text_t tail = substr (OID.end()-3, OID.end()); |
|---|
| 412 | | if (tail == ".rt") { |
|---|
| 413 | | get_top (inOID, OID); |
|---|
| 414 | | return OID; |
|---|
| 415 | | } |
|---|
| 416 | | while (tail == ".fc" || tail == ".lc" || tail == ".pr" || |
|---|
| 417 | | tail == ".ns" || tail == ".ps") { |
|---|
| 418 | | tailarray.push_back(tail); |
|---|
| 419 | | OID.erase (OID.end()-3, OID.end()); |
|---|
| 420 | | tail = substr (OID.end()-3, OID.end()); |
|---|
| 421 | | if (tail == ".rt") { |
|---|
| 422 | | get_top (inOID, OID); |
|---|
| 423 | | return OID; |
|---|
| 424 | | } |
|---|
| 425 | | } |
|---|
| 426 | | |
|---|
| 427 | | if (tailarray.empty()) return inOID; |
|---|
| 428 | | text_tarray::const_iterator begin = tailarray.begin(); |
|---|
| 429 | | text_tarray::const_iterator here = tailarray.end() - 1; |
|---|
| 430 | | |
|---|
| 431 | | while (here >= begin) { |
|---|
| 432 | | |
|---|
| 433 | | if (*here == ".fc") |
|---|
| 434 | | get_first_child (OID, info); |
|---|
| 435 | | else if (*here == ".lc") |
|---|
| 436 | | get_last_child (OID, info); |
|---|
| 437 | | else if (*here == ".pr") |
|---|
| 438 | | OID = get_parent (OID); |
|---|
| 439 | | else if (*here == ".ns") |
|---|
| 440 | | get_next_sibling (OID, info); |
|---|
| 441 | | else if (*here == ".ps") |
|---|
| 442 | | get_previous_sibling (OID, info); |
|---|
| 443 | | |
|---|
| 444 | | if (here == begin) |
|---|
| 445 | | break; |
|---|
| 446 | | --here; |
|---|
| 447 | | } |
|---|
| 448 | | |
|---|
| 449 | | return OID; |
|---|
| 450 | | } |
|---|
| 451 | | |
|---|
| 452 | | |
|---|
| 453 | | void gdbmclass::get_first_child (text_t &OID, infodbclass &info) |
|---|
| 454 | | { |
|---|
| 455 | | text_t firstchild; |
|---|
| 456 | | if (getinfo (OID, info)) { |
|---|
| 457 | | text_t &contains = info["contains"]; |
|---|
| 458 | | if (!contains.empty()) { |
|---|
| 459 | | text_t parent = OID; |
|---|
| 460 | | getdelimitstr (contains.begin(), contains.end(), ';', firstchild); |
|---|
| 461 | | if (firstchild.empty()) OID = contains; |
|---|
| 462 | | else OID = firstchild; |
|---|
| 463 | | if (*(OID.begin()) == '"') translate_parent (OID, parent); |
|---|
| 464 | | } |
|---|
| 465 | | } |
|---|
| 466 | | } |
|---|
| 467 | | |
|---|
| 468 | | |
|---|
| 469 | | void gdbmclass::get_last_child (text_t &OID, infodbclass &info) |
|---|
| 470 | | { |
|---|
| 471 | | text_tarray children; |
|---|
| 472 | | if (getinfo (OID, info)) { |
|---|
| 473 | | text_t &contains = info["contains"]; |
|---|
| 474 | | if (!contains.empty()) { |
|---|
| 475 | | text_t parent = OID; |
|---|
| 476 | | splitchar (contains.begin(), contains.end(), ';', children); |
|---|
| 477 | | OID = children.back(); |
|---|
| 478 | | if (*(OID.begin()) == '"') translate_parent (OID, parent); |
|---|
| 479 | | } |
|---|
| 480 | | } |
|---|
| 481 | | } |
|---|
| 482 | | |
|---|
| 483 | | |
|---|
| 484 | | void gdbmclass::get_next_sibling (text_t &OID, infodbclass &info) |
|---|
| 485 | | { |
|---|
| 486 | | text_tarray siblings; |
|---|
| 487 | | text_t parent = get_parent (OID); |
|---|
| 488 | | |
|---|
| 489 | | if (getinfo (parent, info)) { |
|---|
| 490 | | text_t &contains = info["contains"]; |
|---|
| 491 | | if (!contains.empty()) { |
|---|
| 492 | | splitchar (contains.begin(), contains.end(), ';', siblings); |
|---|
| 493 | | text_tarray::const_iterator here = siblings.begin(); |
|---|
| 494 | | text_tarray::const_iterator end = siblings.end(); |
|---|
| 495 | | text_t shrunk_OID = OID; |
|---|
| 496 | | shrink_parent (shrunk_OID); |
|---|
| 497 | | while (here != end) { |
|---|
| 498 | | if (*here == shrunk_OID && (here+1 != end)) { |
|---|
| 499 | | OID = *(here+1); |
|---|
| 500 | | if (*(OID.begin()) == '"') translate_parent (OID, parent); |
|---|
| 501 | | break; |
|---|
| 502 | | } |
|---|
| 503 | | ++here; |
|---|
| 504 | | } |
|---|
| 505 | | } |
|---|
| 506 | | } |
|---|
| 507 | | } |
|---|
| 508 | | |
|---|
| 509 | | |
|---|
| 510 | | void gdbmclass::get_previous_sibling (text_t &OID, infodbclass &info) |
|---|
| 511 | | { |
|---|
| 512 | | text_tarray siblings; |
|---|
| 513 | | text_t parent = get_parent (OID); |
|---|
| 514 | | |
|---|
| 515 | | if (getinfo (parent, info)) { |
|---|
| 516 | | text_t &contains = info["contains"]; |
|---|
| 517 | | if (!contains.empty()) { |
|---|
| 518 | | splitchar (contains.begin(), contains.end(), ';', siblings); |
|---|
| 519 | | text_tarray::const_iterator here = siblings.begin(); |
|---|
| 520 | | text_tarray::const_iterator end = siblings.end(); |
|---|
| 521 | | text_t shrunk_OID = OID; |
|---|
| 522 | | shrink_parent (shrunk_OID); |
|---|
| 523 | | while (here != end) { |
|---|
| 524 | | if (*here == shrunk_OID && (here != siblings.begin())) { |
|---|
| 525 | | OID = *(here-1); |
|---|
| 526 | | if (*(OID.begin()) == '"') translate_parent (OID, parent); |
|---|
| 527 | | break; |
|---|
| 528 | | } |
|---|
| 529 | | ++here; |
|---|
| 530 | | } |
|---|
| 531 | | } |
|---|
| 532 | | } |
|---|
| 533 | | } |
|---|
| 534 | | |
|---|
| 535 | | |
|---|
| 536 | | // returns true on success |
|---|
| 537 | | bool gdbmclass::getinfo (const text_t& key, infodbclass &info) |
|---|
| 538 | | { |
|---|
| 539 | | text_t data; |
|---|
| 540 | | |
|---|
| 541 | | if (!getkeydata (key, data)) return false; |
|---|
| 542 | | text_t::iterator here = data.begin (); |
|---|
| 543 | | text_t::iterator end = data.end (); |
|---|
| 544 | | |
|---|
| 545 | | text_t ikey, ivalue; |
|---|
| 546 | | info.clear (); // reset info |
|---|
| 547 | | |
|---|
| 548 | | while (getinfoline (here, end, ikey, ivalue)) { |
|---|
| 549 | | info.addinfo (ikey, ivalue); |
|---|
| 550 | | } |
|---|
| 551 | | |
|---|
| 552 | | return true; |
|---|
| 553 | | } |
|---|
| 554 | | |
|---|
| 555 | | |
|---|
| 556 | | // returns true if exists |
|---|
| 557 | | bool gdbmclass::exists (const text_t& key) |
|---|
| 558 | | { |
|---|
| 559 | | text_t data; |
|---|
| 560 | | return getkeydata (key, data); |
|---|
| 561 | | } |
|---|
| 562 | | |
|---|
| 563 | | |
|---|
| 564 | | // returns true on success |
|---|
| 565 | | bool gdbmclass::getkeydata (const text_t& key, text_t &data) |
|---|
| 566 | | { |
|---|
| 567 | | datum key_data; |
|---|
| 568 | | datum return_data; |
|---|
| 569 | | |
|---|
| 570 | | if (gdbmfile == NULL) return false; |
|---|
| 571 | | |
|---|
| 572 | | // get a utf-8 encoded c string of the unicode key |
|---|
| 573 | | key_data.dptr = (to_utf8(key)).getcstr(); |
|---|
| 574 | | if (key_data.dptr == NULL) { |
|---|
| 575 | | if (logout != NULL) (*logout) << "gdbmclass: out of memory\n"; |
|---|
| 576 | | return false; |
|---|
| 577 | | } |
|---|
| 578 | | key_data.dsize = strlen (key_data.dptr); |
|---|
| 579 | | |
|---|
| 580 | | // fetch the result |
|---|
| 581 | | return_data = gdbm_fetch (gdbmfile, key_data); |
|---|
| 582 | | delete []key_data.dptr; |
|---|
| 583 | | |
|---|
| 584 | | if (return_data.dptr == NULL) return false; |
|---|
| 585 | | |
|---|
| 586 | | data.setcarr (return_data.dptr, return_data.dsize); |
|---|
| 587 | | free (return_data.dptr); |
|---|
| 588 | | data = to_uni(data); // convert to unicode |
|---|
| 589 | | |
|---|
| 590 | | return true; |
|---|
| 591 | | } |
|---|
| 592 | | |
|---|
| 593 | | |
|---|
| 594 | | // returns true on success |
|---|
| 595 | | bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end, |
|---|
| 596 | | text_t &key, text_t &value) |
|---|
| 597 | | { |
|---|
| 598 | | key.clear(); |
|---|
| 599 | | value.clear(); |
|---|
| 600 | | |
|---|
| 601 | | // ignore white space |
|---|
| 602 | | while (here != end && is_unicode_space (*here)) ++here; |
|---|
| 603 | | |
|---|
| 604 | | // get the '<' |
|---|
| 605 | | if (here == end || *here != '<') return false; |
|---|
| 606 | | ++here; |
|---|
| 607 | | |
|---|
| 608 | | // get the key |
|---|
| 609 | | while (here != end && *here != '>') { |
|---|
| 610 | | key.push_back(*here); |
|---|
| 611 | | ++here; |
|---|
| 612 | | } |
|---|
| 613 | | |
|---|
| 614 | | // get the '>' |
|---|
| 615 | | if (here == end || *here != '>') return false; |
|---|
| 616 | | ++here; |
|---|
| 617 | | |
|---|
| 618 | | // get the value |
|---|
| 619 | | while (here != end && *here != '\n') { |
|---|
| 620 | | if (*here == '\\') { |
|---|
| 621 | | // found escape character |
|---|
| 622 | | ++here; |
|---|
| 623 | | if (here != end) { |
|---|
| 624 | | if (*here == 'n') value.push_back ('\n'); |
|---|
| 625 | | else if (*here == 'r') value.push_back ('\r'); |
|---|
| 626 | | else value.push_back(*here); |
|---|
| 627 | | } |
|---|
| 628 | | |
|---|
| 629 | | } else { |
|---|
| 630 | | // a normal character |
|---|
| 631 | | value.push_back(*here); |
|---|
| 632 | | } |
|---|
| 633 | | |
|---|
| 634 | | ++here; |
|---|
| 635 | | } |
|---|
| 636 | | |
|---|
| 637 | | return true; |
|---|
| 638 | | } |
|---|