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_NONE: 364 default: 365 /* default default ??? */ 366 status = LDNS_STATUS_ERR; 367 break; 368 } 369 if (LDNS_STATUS_OK == status) { 370 ldns_rdf_set_type(rdf, type); 371 return rdf; 372 } 373 if (rdf) { 374 LDNS_FREE(rdf); 375 } 376 return NULL; 377 } 378 379 ldns_status 380 ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp) 381 { 382 return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL); 383 } 384 385 ldns_status 386 ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr) 387 { 388 char *line; 389 ldns_rdf *r; 390 ssize_t t; 391 392 line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); 393 if (!line) { 394 return LDNS_STATUS_MEM_ERR; 395 } 396 397 /* read an entire line in from the file */ 398 if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) { 399 LDNS_FREE(line); 400 return LDNS_STATUS_SYNTAX_RDATA_ERR; 401 } 402 r = ldns_rdf_new_frm_str(type, (const char*) line); 403 LDNS_FREE(line); 404 if (rdf) { 405 *rdf = r; 406 return LDNS_STATUS_OK; 407 } else { 408 return LDNS_STATUS_NULL; 409 } 410 } 411 412 ldns_rdf * 413 ldns_rdf_address_reverse(const ldns_rdf *rd) 414 { 415 uint8_t buf_4[LDNS_IP4ADDRLEN]; 416 uint8_t buf_6[LDNS_IP6ADDRLEN * 2]; 417 ldns_rdf *rev; 418 ldns_rdf *in_addr; 419 ldns_rdf *ret_dname; 420 uint8_t octet; 421 uint8_t nnibble; 422 uint8_t nibble; 423 uint8_t i, j; 424 425 char *char_dname; 426 int nbit; 427 428 if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A && 429 ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) { 430 return NULL; 431 } 432 433 in_addr = NULL; 434 ret_dname = NULL; 435 436 switch(ldns_rdf_get_type(rd)) { 437 case LDNS_RDF_TYPE_A: 438 /* the length of the buffer is 4 */ 439 buf_4[3] = ldns_rdf_data(rd)[0]; 440 buf_4[2] = ldns_rdf_data(rd)[1]; 441 buf_4[1] = ldns_rdf_data(rd)[2]; 442 buf_4[0] = ldns_rdf_data(rd)[3]; 443 in_addr = ldns_dname_new_frm_str("in-addr.arpa."); 444 if (!in_addr) { 445 return NULL; 446 } 447 /* make a new rdf and convert that back */ 448 rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A, 449 LDNS_IP4ADDRLEN, (void*)&buf_4); 450 if (!rev) { 451 LDNS_FREE(in_addr); 452 return NULL; 453 } 454 455 /* convert rev to a string */ 456 char_dname = ldns_rdf2str(rev); 457 if (!char_dname) { 458 LDNS_FREE(in_addr); 459 ldns_rdf_deep_free(rev); 460 return NULL; 461 } 462 /* transform back to rdf with type dname */ 463 ret_dname = ldns_dname_new_frm_str(char_dname); 464 if (!ret_dname) { 465 LDNS_FREE(in_addr); 466 ldns_rdf_deep_free(rev); 467 LDNS_FREE(char_dname); 468 return NULL; 469 } 470 /* not needed anymore */ 471 ldns_rdf_deep_free(rev); 472 LDNS_FREE(char_dname); 473 break; 474 case LDNS_RDF_TYPE_AAAA: 475 /* some foo magic to reverse the nibbles ... */ 476 477 for (nbit = 127; nbit >= 0; nbit = nbit - 4) { 478 /* calculate octet (8 bit) */ 479 octet = ( ((unsigned int) nbit) & 0x78) >> 3; 480 /* calculate nibble */ 481 nnibble = ( ((unsigned int) nbit) & 0x04) >> 2; 482 /* extract nibble */ 483 nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 - 484 nnibble)) ) ) >> ( 4 * (1 - 485 nnibble)); 486 487 buf_6[(LDNS_IP6ADDRLEN * 2 - 1) - 488 (octet * 2 + nnibble)] = 489 (uint8_t)ldns_int_to_hexdigit((int)nibble); 490 } 491 492 char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4)); 493 if (!char_dname) { 494 return NULL; 495 } 496 char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */ 497 498 /* walk the string and add . 's */ 499 for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) { 500 char_dname[j] = (char)buf_6[i]; 501 if (i != LDNS_IP6ADDRLEN * 2 - 1) { 502 char_dname[j + 1] = '.'; 503 } 504 } 505 in_addr = ldns_dname_new_frm_str("ip6.arpa."); 506 if (!in_addr) { 507 LDNS_FREE(char_dname); 508 return NULL; 509 } 510 511 /* convert rev to a string */ 512 ret_dname = ldns_dname_new_frm_str(char_dname); 513 LDNS_FREE(char_dname); 514 if (!ret_dname) { 515 ldns_rdf_deep_free(in_addr); 516 return NULL; 517 } 518 break; 519 default: 520 break; 521 } 522 /* add the suffix */ 523 rev = ldns_dname_cat_clone(ret_dname, in_addr); 524 525 ldns_rdf_deep_free(ret_dname); 526 ldns_rdf_deep_free(in_addr); 527 return rev; 528 } 529 530 ldns_status 531 ldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg, 532 uint8_t *hit_size, uint8_t** hit, 533 uint16_t *pk_size, uint8_t** pk) 534 { 535 uint8_t *data; 536 size_t rdf_size; 537 538 if (! rdf || ! alg || ! hit || ! hit_size || ! pk || ! pk_size) { 539 return LDNS_STATUS_INVALID_POINTER; 540 } else if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_HIP) { 541 return LDNS_STATUS_INVALID_RDF_TYPE; 542 } else if ((rdf_size = ldns_rdf_size(rdf)) < 6) { 543 return LDNS_STATUS_WIRE_RDATA_ERR; 544 } 545 data = ldns_rdf_data(rdf); 546 *hit_size = data[0]; 547 *alg = data[1]; 548 *pk_size = ldns_read_uint16(data + 2); 549 *hit = data + 4; 550 *pk = data + 4 + *hit_size; 551 if (*hit_size == 0 || *pk_size == 0 || 552 rdf_size < (size_t) *hit_size + *pk_size + 4) { 553 return LDNS_STATUS_WIRE_RDATA_ERR; 554 } 555 return LDNS_STATUS_OK; 556 } 557 558 ldns_status 559 ldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg, 560 uint8_t hit_size, uint8_t *hit, 561 uint16_t pk_size, uint8_t *pk) 562 { 563 uint8_t *data; 564 565 if (! rdf) { 566 return LDNS_STATUS_INVALID_POINTER; 567 } 568 if (4 + hit_size + pk_size > LDNS_MAX_RDFLEN) { 569 return LDNS_STATUS_RDATA_OVERFLOW; 570 } 571 data = LDNS_XMALLOC(uint8_t, 4 + hit_size + pk_size); 572 if (data == NULL) { 573 return LDNS_STATUS_MEM_ERR; 574 } 575 data[0] = hit_size; 576 data[1] = alg; 577 ldns_write_uint16(data + 2, pk_size); 578 memcpy(data + 4, hit, hit_size); 579 memcpy(data + 4 + hit_size, pk, pk_size); 580 *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HIP, 4 + hit_size + pk_size, data); 581 if (! *rdf) { 582 LDNS_FREE(data); 583 return LDNS_STATUS_MEM_ERR; 584 } 585 return LDNS_STATUS_OK; 586 } 587 588 ldns_status 589 ldns_octet(char *word, size_t *length) 590 { 591 char *s; 592 char *p; 593 *length = 0; 594 595 for (s = p = word; *s != '\0'; s++,p++) { 596 switch (*s) { 597 case '.': 598 if (s[1] == '.') { 599 return LDNS_STATUS_EMPTY_LABEL; 600 } 601 *p = *s; 602 (*length)++; 603 break; 604 case '\\': 605 if ('0' <= s[1] && s[1] <= '9' && 606 '0' <= s[2] && s[2] <= '9' && 607 '0' <= s[3] && s[3] <= '9') { 608 /* \DDD seen */ 609 int val = ((s[1] - '0') * 100 + 610 (s[2] - '0') * 10 + (s[3] - '0')); 611 612 if (0 <= val && val <= 255) { 613 /* this also handles \0 */ 614 s += 3; 615 *p = val; 616 (*length)++; 617 } else { 618 return LDNS_STATUS_DDD_OVERFLOW; 619 } 620 } else { 621 /* an espaced character, like \<space> ? 622 * remove the '\' keep the rest */ 623 *p = *++s; 624 (*length)++; 625 } 626 break; 627 case '\"': 628 /* non quoted " Is either first or the last character in 629 * the string */ 630 631 *p = *++s; /* skip it */ 632 (*length)++; 633 /* I'm not sure if this is needed in libdns... MG */ 634 if ( *s == '\0' ) { 635 /* ok, it was the last one */ 636 *p = '\0'; 637 return LDNS_STATUS_OK; 638 } 639 break; 640 default: 641 *p = *s; 642 (*length)++; 643 break; 644 } 645 } 646 *p = '\0'; 647 return LDNS_STATUS_OK; 648 } 649 650 int 651 ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2) 652 { 653 uint16_t i1, i2, i; 654 uint8_t *d1, *d2; 655 656 /* only when both are not NULL we can say anything about them */ 657 if (!rd1 && !rd2) { 658 return 0; 659 } 660 if (!rd1 || !rd2) { 661 return -1; 662 } 663 i1 = ldns_rdf_size(rd1); 664 i2 = ldns_rdf_size(rd2); 665 666 if (i1 < i2) { 667 return -1; 668 } else if (i1 > i2) { 669 return +1; 670 } else { 671 d1 = (uint8_t*)ldns_rdf_data(rd1); 672 d2 = (uint8_t*)ldns_rdf_data(rd2); 673 for(i = 0; i < i1; i++) { 674 if (d1[i] < d2[i]) { 675 return -1; 676 } else if (d1[i] > d2[i]) { 677 return +1; 678 } 679 } 680 } 681 return 0; 682 } 683 684 uint32_t 685 ldns_str2period(const char *nptr, const char **endptr) 686 { 687 int sign = 0; 688 uint32_t i = 0; 689 uint32_t seconds = 0; 690 691 for(*endptr = nptr; **endptr; (*endptr)++) { 692 switch (**endptr) { 693 case ' ': 694 case '\t': 695 break; 696 case '-': 697 if(sign == 0) { 698 sign = -1; 699 } else { 700 return seconds; 701 } 702 break; 703 case '+': 704 if(sign == 0) { 705 sign = 1; 706 } else { 707 return seconds; 708 } 709 break; 710 case 's': 711 case 'S': 712 seconds += i; 713 i = 0; 714 break; 715 case 'm': 716 case 'M': 717 seconds += i * 60; 718 i = 0; 719 break; 720 case 'h': 721 case 'H': 722 seconds += i * 60 * 60; 723 i = 0; 724 break; 725 case 'd': 726 case 'D': 727 seconds += i * 60 * 60 * 24; 728 i = 0; 729 break; 730 case 'w': 731 case 'W': 732 seconds += i * 60 * 60 * 24 * 7; 733 i = 0; 734 break; 735 case '0': 736 case '1': 737 case '2': 738 case '3': 739 case '4': 740 case '5': 741 case '6': 742 case '7': 743 case '8': 744 case '9': 745 i *= 10; 746 i += (**endptr - '0'); 747 break; 748 default: 749 seconds += i; 750 /* disregard signedness */ 751 return seconds; 752 } 753 } 754 seconds += i; 755 /* disregard signedness */ 756 return seconds; 757 } 758