1 /* 2 * rdata.c 3 * 4 * rdata implementation 5 * 6 * a Net::DNS like library for C 7 * 8 * (c) NLnet Labs, 2004-2006 9 * 10 * See the file LICENSE for the license 11 */ 12 13 #include <ldns/config.h> 14 15 #include <ldns/ldns.h> 16 17 /* 18 * Access functions 19 * do this as functions to get type checking 20 */ 21 22 /* read */ 23 size_t 24 ldns_rdf_size(const ldns_rdf *rd) 25 { 26 assert(rd != NULL); 27 return rd->_size; 28 } 29 30 ldns_rdf_type 31 ldns_rdf_get_type(const ldns_rdf *rd) 32 { 33 assert(rd != NULL); 34 return rd->_type; 35 } 36 37 uint8_t * 38 ldns_rdf_data(const ldns_rdf *rd) 39 { 40 assert(rd != NULL); 41 return rd->_data; 42 } 43 44 /* write */ 45 void 46 ldns_rdf_set_size(ldns_rdf *rd, size_t size) 47 { 48 assert(rd != NULL); 49 rd->_size = size; 50 } 51 52 void 53 ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type) 54 { 55 assert(rd != NULL); 56 rd->_type = type; 57 } 58 59 void 60 ldns_rdf_set_data(ldns_rdf *rd, void *data) 61 { 62 /* only copy the pointer */ 63 assert(rd != NULL); 64 rd->_data = data; 65 } 66 67 /* for types that allow it, return 68 * the native/host order type */ 69 uint8_t 70 ldns_rdf2native_int8(const ldns_rdf *rd) 71 { 72 uint8_t data; 73 74 /* only allow 8 bit rdfs */ 75 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) { 76 return 0; 77 } 78 79 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 80 return data; 81 } 82 83 uint16_t 84 ldns_rdf2native_int16(const ldns_rdf *rd) 85 { 86 uint16_t data; 87 88 /* only allow 16 bit rdfs */ 89 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) { 90 return 0; 91 } 92 93 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 94 return ntohs(data); 95 } 96 97 uint32_t 98 ldns_rdf2native_int32(const ldns_rdf *rd) 99 { 100 uint32_t data; 101 102 /* only allow 32 bit rdfs */ 103 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) { 104 return 0; 105 } 106 107 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 108 return ntohl(data); 109 } 110 111 time_t 112 ldns_rdf2native_time_t(const ldns_rdf *rd) 113 { 114 uint32_t data; 115 116 /* only allow 32 bit rdfs */ 117 if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD || 118 ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TIME) { 119 return 0; 120 } 121 memcpy(&data, ldns_rdf_data(rd), sizeof(data)); 122 return (time_t)ntohl(data); 123 } 124 125 ldns_rdf * 126 ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value) 127 { 128 return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value); 129 } 130 131 ldns_rdf * 132 ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value) 133 { 134 uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1); 135 ldns_rdf* rdf; 136 if (!rdf_data) { 137 return NULL; 138 } 139 ldns_write_uint16(rdf_data, value); 140 rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data); 141 if(!rdf) 142 LDNS_FREE(rdf_data); 143 return rdf; 144 } 145 146 ldns_rdf * 147 ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value) 148 { 149 uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1); 150 ldns_rdf* rdf; 151 if (!rdf_data) { 152 return NULL; 153 } 154 ldns_write_uint32(rdf_data, value); 155 rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data); 156 if(!rdf) 157 LDNS_FREE(rdf_data); 158 return rdf; 159 } 160 161 ldns_rdf * 162 ldns_native2rdf_int16_data(size_t size, uint8_t *data) 163 { 164 uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2); 165 ldns_rdf* rdf; 166 if (!rdf_data) { 167 return NULL; 168 } 169 ldns_write_uint16(rdf_data, size); 170 memcpy(rdf_data + 2, data, size); 171 rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data); 172 if(!rdf) 173 LDNS_FREE(rdf_data); 174 return rdf; 175 } 176 177 /* note: data must be allocated memory */ 178 ldns_rdf * 179 ldns_rdf_new(ldns_rdf_type type, size_t size, void *data) 180 { 181 ldns_rdf *rd; 182 rd = LDNS_MALLOC(ldns_rdf); 183 if (!rd) { 184 return NULL; 185 } 186 ldns_rdf_set_size(rd, size); 187 ldns_rdf_set_type(rd, type); 188 ldns_rdf_set_data(rd, data); 189 return rd; 190 } 191 192 ldns_rdf * 193 ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data) 194 { 195 ldns_rdf *rdf; 196 197 /* if the size is too big, fail */ 198 if (size > LDNS_MAX_RDFLEN) { 199 return NULL; 200 } 201 202 /* allocate space */ 203 rdf = LDNS_MALLOC(ldns_rdf); 204 if (!rdf) { 205 return NULL; 206 } 207 rdf->_data = LDNS_XMALLOC(uint8_t, size); 208 if (!rdf->_data) { 209 LDNS_FREE(rdf); 210 return NULL; 211 } 212 213 /* set the values */ 214 ldns_rdf_set_type(rdf, type); 215 ldns_rdf_set_size(rdf, size); 216 memcpy(rdf->_data, data, size); 217 218 return rdf; 219 } 220 221 ldns_rdf * 222 ldns_rdf_clone(const ldns_rdf *rd) 223 { 224 assert(rd != NULL); 225 return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd), 226 ldns_rdf_size(rd), ldns_rdf_data(rd))); 227 } 228 229 void 230 ldns_rdf_deep_free(ldns_rdf *rd) 231 { 232 if (rd) { 233 if (rd->_data) { 234 LDNS_FREE(rd->_data); 235 } 236 LDNS_FREE(rd); 237 } 238 } 239 240 void 241 ldns_rdf_free(ldns_rdf *rd) 242 { 243 if (rd) { 244 LDNS_FREE(rd); 245 } 246 } 247 248 ldns_rdf * 249 ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str) 250 { 251 ldns_rdf *rdf = NULL; 252 ldns_status status; 253 254 switch (type) { 255 case LDNS_RDF_TYPE_DNAME: 256 status = ldns_str2rdf_dname(&rdf, str); 257 break; 258 case LDNS_RDF_TYPE_INT8: 259 status = ldns_str2rdf_int8(&rdf, str); 260 break; 261 case LDNS_RDF_TYPE_INT16: 262 status = ldns_str2rdf_int16(&rdf, str); 263 break; 264 case LDNS_RDF_TYPE_INT32: 265 status = ldns_str2rdf_int32(&rdf, str); 266 break; 267 case LDNS_RDF_TYPE_A: 268 status = ldns_str2rdf_a(&rdf, str); 269 break; 270 case LDNS_RDF_TYPE_AAAA: 271 status = ldns_str2rdf_aaaa(&rdf, str); 272 break; 273 case LDNS_RDF_TYPE_STR: 274 status = ldns_str2rdf_str(&rdf, str); 275 break; 276 case LDNS_RDF_TYPE_APL: 277 status = ldns_str2rdf_apl(&rdf, str); 278 break; 279 case LDNS_RDF_TYPE_B64: 280 status = ldns_str2rdf_b64(&rdf, str); 281 break; 282 case LDNS_RDF_TYPE_B32_EXT: 283 status = ldns_str2rdf_b32_ext(&rdf, str); 284 break; 285 case LDNS_RDF_TYPE_HEX: 286 status = ldns_str2rdf_hex(&rdf, str); 287 break; 288 case LDNS_RDF_TYPE_NSEC: 289 status = ldns_str2rdf_nsec(&rdf, str); 290 break; 291 case LDNS_RDF_TYPE_TYPE: 292 status = ldns_str2rdf_type(&rdf, str); 293 break; 294 case LDNS_RDF_TYPE_CLASS: 295 status = ldns_str2rdf_class(&rdf, str); 296 break; 297 case LDNS_RDF_TYPE_CERT_ALG: 298 status = ldns_str2rdf_cert_alg(&rdf, str); 299 break; 300 case LDNS_RDF_TYPE_ALG: 301 status = ldns_str2rdf_alg(&rdf, str); 302 break; 303 case LDNS_RDF_TYPE_UNKNOWN: 304 status = ldns_str2rdf_unknown(&rdf, str); 305 break; 306 case LDNS_RDF_TYPE_TIME: 307 status = ldns_str2rdf_time(&rdf, str); 308 break; 309 case LDNS_RDF_TYPE_PERIOD: 310 status = ldns_str2rdf_period(&rdf, str); 311 break; 312 case LDNS_RDF_TYPE_HIP: 313 status = ldns_str2rdf_hip(&rdf, str); 314 break; 315 case LDNS_RDF_TYPE_SERVICE: 316 status = ldns_str2rdf_service(&rdf, str); 317 break; 318 case LDNS_RDF_TYPE_LOC: 319 status = ldns_str2rdf_loc(&rdf, str); 320 break; 321 case LDNS_RDF_TYPE_WKS: 322 status = ldns_str2rdf_wks(&rdf, str); 323 break; 324 case LDNS_RDF_TYPE_NSAP: 325 status = ldns_str2rdf_nsap(&rdf, str); 326 break; 327 case LDNS_RDF_TYPE_ATMA: 328 status = ldns_str2rdf_atma(&rdf, str); 329 break; 330 case LDNS_RDF_TYPE_IPSECKEY: 331 status = ldns_str2rdf_ipseckey(&rdf, str); 332 break; 333 case LDNS_RDF_TYPE_NSEC3_SALT: 334 status = ldns_str2rdf_nsec3_salt(&rdf, str); 335 break; 336 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 337 status = ldns_str2rdf_b32_ext(&rdf, str); 338 break; 339 case LDNS_RDF_TYPE_ILNP64: 340 status = ldns_str2rdf_ilnp64(&rdf, str); 341 break; 342 case LDNS_RDF_TYPE_EUI48: 343 status = ldns_str2rdf_eui48(&rdf, str); 344 break; 345 case LDNS_RDF_TYPE_EUI64: 346 status = ldns_str2rdf_eui64(&rdf, str); 347 break; 348 case LDNS_RDF_TYPE_TAG: 349 status = ldns_str2rdf_tag(&rdf, str); 350 break; 351 case LDNS_RDF_TYPE_LONG_STR: 352 status = ldns_str2rdf_long_str(&rdf, str); 353 break; 354 case LDNS_RDF_TYPE_CERTIFICATE_USAGE: 355 status = ldns_str2rdf_certificate_usage(&rdf, str); 356 break; 357 case LDNS_RDF_TYPE_SELECTOR: 358 status = ldns_str2rdf_selector(&rdf, str); 359 break; 360 case LDNS_RDF_TYPE_MATCHING_TYPE: 361 status = ldns_str2rdf_matching_type(&rdf, str); 362 break; 363 case LDNS_RDF_TYPE_AMTRELAY: 364 status = ldns_str2rdf_amtrelay(&rdf, str); 365 break; 366 case LDNS_RDF_TYPE_NONE: 367 default: 368 /* default default ??? */ 369 status = LDNS_STATUS_ERR; 370 break; 371 } 372 if (LDNS_STATUS_OK == status) { 373 ldns_rdf_set_type(rdf, type); 374 return rdf; 375 } 376 if (rdf) { 377 LDNS_FREE(rdf); 378 } 379 return NULL; 380 } 381 382 ldns_status 383 ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp) 384 { 385 return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL); 386 } 387 388 ldns_status 389 ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr) 390 { 391 char *line; 392 ldns_rdf *r; 393 ssize_t t; 394 395 line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); 396 if (!line) { 397 return LDNS_STATUS_MEM_ERR; 398 } 399 400 /* read an entire line in from the file */ 401 if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) { 402 LDNS_FREE(line); 403 return LDNS_STATUS_SYNTAX_RDATA_ERR; 404 } 405 r = ldns_rdf_new_frm_str(type, (const char*) line); 406 LDNS_FREE(line); 407 if (rdf) { 408 *rdf = r; 409 return LDNS_STATUS_OK; 410 } else { 411 return LDNS_STATUS_NULL; 412 } 413 } 414 415 ldns_rdf * 416 ldns_rdf_address_reverse(const ldns_rdf *rd) 417 { 418 uint8_t buf_4[LDNS_IP4ADDRLEN]; 419 uint8_t buf_6[LDNS_IP6ADDRLEN * 2]; 420 ldns_rdf *rev; 421 ldns_rdf *in_addr; 422 ldns_rdf *ret_dname; 423 uint8_t octet; 424 uint8_t nnibble; 425 uint8_t nibble; 426 uint8_t i, j; 427 428 char *char_dname; 429 int nbit; 430 431 if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A && 432 ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) { 433 return NULL; 434 } 435 436 in_addr = NULL; 437 ret_dname = NULL; 438 439 switch(ldns_rdf_get_type(rd)) { 440 case LDNS_RDF_TYPE_A: 441 /* the length of the buffer is 4 */ 442 buf_4[3] = ldns_rdf_data(rd)[0]; 443 buf_4[2] = ldns_rdf_data(rd)[1]; 444 buf_4[1] = ldns_rdf_data(rd)[2]; 445 buf_4[0] = ldns_rdf_data(rd)[3]; 446 in_addr = ldns_dname_new_frm_str("in-addr.arpa."); 447 if (!in_addr) { 448 return NULL; 449 } 450 /* make a new rdf and convert that back */ 451 rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A, 452 LDNS_IP4ADDRLEN, (void*)&buf_4); 453 if (!rev) { 454 LDNS_FREE(in_addr); 455 return NULL; 456 } 457 458 /* convert rev to a string */ 459 char_dname = ldns_rdf2str(rev); 460 if (!char_dname) { 461 LDNS_FREE(in_addr); 462 ldns_rdf_deep_free(rev); 463 return NULL; 464 } 465 /* transform back to rdf with type dname */ 466 ret_dname = ldns_dname_new_frm_str(char_dname); 467 if (!ret_dname) { 468 LDNS_FREE(in_addr); 469 ldns_rdf_deep_free(rev); 470 LDNS_FREE(char_dname); 471 return NULL; 472 } 473 /* not needed anymore */ 474 ldns_rdf_deep_free(rev); 475 LDNS_FREE(char_dname); 476 break; 477 case LDNS_RDF_TYPE_AAAA: 478 /* some foo magic to reverse the nibbles ... */ 479 480 for (nbit = 127; nbit >= 0; nbit = nbit - 4) { 481 /* calculate octet (8 bit) */ 482 octet = ( ((unsigned int) nbit) & 0x78) >> 3; 483 /* calculate nibble */ 484 nnibble = ( ((unsigned int) nbit) & 0x04) >> 2; 485 /* extract nibble */ 486 nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 - 487 nnibble)) ) ) >> ( 4 * (1 - 488 nnibble)); 489 490 buf_6[(LDNS_IP6ADDRLEN * 2 - 1) - 491 (octet * 2 + nnibble)] = 492 (uint8_t)ldns_int_to_hexdigit((int)nibble); 493 } 494 495 char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4)); 496 if (!char_dname) { 497 return NULL; 498 } 499 char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */ 500 501 /* walk the string and add . 's */ 502 for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) { 503 char_dname[j] = (char)buf_6[i]; 504 if (i != LDNS_IP6ADDRLEN * 2 - 1) { 505 char_dname[j + 1] = '.'; 506 } 507 } 508 in_addr = ldns_dname_new_frm_str("ip6.arpa."); 509 if (!in_addr) { 510 LDNS_FREE(char_dname); 511 return NULL; 512 } 513 514 /* convert rev to a string */ 515 ret_dname = ldns_dname_new_frm_str(char_dname); 516 LDNS_FREE(char_dname); 517 if (!ret_dname) { 518 ldns_rdf_deep_free(in_addr); 519 return NULL; 520 } 521 break; 522 default: 523 break; 524 } 525 /* add the suffix */ 526 rev = ldns_dname_cat_clone(ret_dname, in_addr); 527 528 ldns_rdf_deep_free(ret_dname); 529 ldns_rdf_deep_free(in_addr); 530 return rev; 531 } 532 533 ldns_status 534 ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, 535 uint8_t *hit_size, uint8_t** hit, 536 uint16_t *pk_size, uint8_t** pk) 537 { 538 uint8_t *data; 539 size_t rdf_size; 540 541 if (! rdf || ! alg || ! hit || ! hit_size || ! pk || ! pk_size) { 542 return LDNS_STATUS_INVALID_POINTER; 543 } else if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_HIP) { 544 return LDNS_STATUS_INVALID_RDF_TYPE; 545 } else if ((rdf_size = ldns_rdf_size(rdf)) < 6) { 546 return LDNS_STATUS_WIRE_RDATA_ERR; 547 } 548 data = ldns_rdf_data(rdf); 549 *hit_size = data[0]; 550 *alg = data[1]; 551 *pk_size = ldns_read_uint16(data + 2); 552 *hit = data + 4; 553 *pk = data + 4 + *hit_size; 554 if (*hit_size == 0 || *pk_size == 0 || 555 rdf_size < (size_t) *hit_size + *pk_size + 4) { 556 return LDNS_STATUS_WIRE_RDATA_ERR; 557 } 558 return LDNS_STATUS_OK; 559 } 560 561 ldns_status 562 ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, 563 uint8_t hit_size, uint8_t *hit, 564 uint16_t pk_size, uint8_t *pk) 565 { 566 uint8_t *data; 567 568 if (! rdf) { 569 return LDNS_STATUS_INVALID_POINTER; 570 } 571 if (4 + hit_size + pk_size > LDNS_MAX_RDFLEN) { 572 return LDNS_STATUS_RDATA_OVERFLOW; 573 } 574 data = LDNS_XMALLOC(uint8_t, 4 + hit_size + pk_size); 575 if (data == NULL) { 576 return LDNS_STATUS_MEM_ERR; 577 } 578 data[0] = hit_size; 579 data[1] = alg; 580 ldns_write_uint16(data + 2, pk_size); 581 memcpy(data + 4, hit, hit_size); 582 memcpy(data + 4 + hit_size, pk, pk_size); 583 *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HIP, 4 + hit_size + pk_size, data); 584 if (! *rdf) { 585 LDNS_FREE(data); 586 return LDNS_STATUS_MEM_ERR; 587 } 588 return LDNS_STATUS_OK; 589 } 590 591 ldns_status 592 ldns_octet(char *word, size_t *length) 593 { 594 char *s; 595 char *p; 596 *length = 0; 597 598 for (s = p = word; *s != '\0'; s++,p++) { 599 switch (*s) { 600 case '.': 601 if (s[1] == '.') { 602 return LDNS_STATUS_EMPTY_LABEL; 603 } 604 *p = *s; 605 (*length)++; 606 break; 607 case '\\': 608 if ('0' <= s[1] && s[1] <= '9' && 609 '0' <= s[2] && s[2] <= '9' && 610 '0' <= s[3] && s[3] <= '9') { 611 /* \DDD seen */ 612 int val = ((s[1] - '0') * 100 + 613 (s[2] - '0') * 10 + (s[3] - '0')); 614 615 if (0 <= val && val <= 255) { 616 /* this also handles \0 */ 617 s += 3; 618 *p = val; 619 (*length)++; 620 } else { 621 return LDNS_STATUS_DDD_OVERFLOW; 622 } 623 } else { 624 /* an espaced character, like \<space> ? 625 * remove the '\' keep the rest */ 626 *p = *++s; 627 (*length)++; 628 } 629 break; 630 case '\"': 631 /* non quoted " Is either first or the last character in 632 * the string */ 633 634 *p = *++s; /* skip it */ 635 (*length)++; 636 /* I'm not sure if this is needed in libdns... MG */ 637 if ( *s == '\0' ) { 638 /* ok, it was the last one */ 639 *p = '\0'; 640 return LDNS_STATUS_OK; 641 } 642 break; 643 default: 644 *p = *s; 645 (*length)++; 646 break; 647 } 648 } 649 *p = '\0'; 650 return LDNS_STATUS_OK; 651 } 652 653 int 654 ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2) 655 { 656 uint16_t i1, i2, i; 657 uint8_t *d1, *d2; 658 659 /* only when both are not NULL we can say anything about them */ 660 if (!rd1 && !rd2) { 661 return 0; 662 } 663 if (!rd1 || !rd2) { 664 return -1; 665 } 666 i1 = ldns_rdf_size(rd1); 667 i2 = ldns_rdf_size(rd2); 668 669 if (i1 < i2) { 670 return -1; 671 } else if (i1 > i2) { 672 return +1; 673 } else { 674 d1 = (uint8_t*)ldns_rdf_data(rd1); 675 d2 = (uint8_t*)ldns_rdf_data(rd2); 676 for(i = 0; i < i1; i++) { 677 if (d1[i] < d2[i]) { 678 return -1; 679 } else if (d1[i] > d2[i]) { 680 return +1; 681 } 682 } 683 } 684 return 0; 685 } 686 687 uint32_t 688 ldns_str2period(const char *nptr, const char **endptr) 689 { 690 int sign = 0; 691 uint32_t i = 0; 692 uint32_t seconds = 0; 693 694 for(*endptr = nptr; **endptr; (*endptr)++) { 695 switch (**endptr) { 696 case ' ': 697 case '\t': 698 break; 699 case '-': 700 if(sign == 0) { 701 sign = -1; 702 } else { 703 return seconds; 704 } 705 break; 706 case '+': 707 if(sign == 0) { 708 sign = 1; 709 } else { 710 return seconds; 711 } 712 break; 713 case 's': 714 case 'S': 715 seconds += i; 716 i = 0; 717 break; 718 case 'm': 719 case 'M': 720 seconds += i * 60; 721 i = 0; 722 break; 723 case 'h': 724 case 'H': 725 seconds += i * 60 * 60; 726 i = 0; 727 break; 728 case 'd': 729 case 'D': 730 seconds += i * 60 * 60 * 24; 731 i = 0; 732 break; 733 case 'w': 734 case 'W': 735 seconds += i * 60 * 60 * 24 * 7; 736 i = 0; 737 break; 738 case '0': 739 case '1': 740 case '2': 741 case '3': 742 case '4': 743 case '5': 744 case '6': 745 case '7': 746 case '8': 747 case '9': 748 i *= 10; 749 i += (**endptr - '0'); 750 break; 751 default: 752 seconds += i; 753 /* disregard signedness */ 754 return seconds; 755 } 756 } 757 seconds += i; 758 /* disregard signedness */ 759 return seconds; 760 } 761