1/* 2 * stdlib support routines for self-contained images. 3 * 4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: bcmstdlib.c,v 1.51.20.1 2010/03/23 01:20:17 Exp $ 19 */ 20 21/* 22 * bcmstdlib.c file should be used only to construct an OSL or alone without any OSL 23 * It should not be used with any orbitarary OSL's as there could be a conflict 24 * with some of the routines defined here. 25*/ 26 27#include <typedefs.h> 28#if defined(NDIS) || defined(_MINOSL_) || defined(__vxworks) || defined(PCBIOS) || \ 29 defined(EFI) 30/* debatable */ 31#include <osl.h> 32#elif 1 33#include <stdio.h> 34#endif 35 36/* 37 * Define BCMSTDLIB_WIN32_APP if this is a Win32 Application compile 38 */ 39#if defined(_WIN32) && !defined(NDIS) && !defined(EFI) 40#define BCMSTDLIB_WIN32_APP 1 41#endif /* _WIN32 && !NDIS */ 42 43/* 44 * Define BCMSTDLIB_SNPRINTF_ONLY if we only want snprintf & vsnprintf implementations 45 */ 46#if (defined(_WIN32) && !defined(EFI)) || defined(__vxworks) || defined(_CFE_) 47#define BCMSTDLIB_SNPRINTF_ONLY 1 48#endif 49 50#include <stdarg.h> 51#include <bcmstdlib.h> 52#ifndef BCMSTDLIB_WIN32_APP 53#include <bcmutils.h> 54#endif 55 56#ifdef MSGTRACE 57#include <msgtrace.h> 58#endif 59 60#ifdef BCMSTDLIB_WIN32_APP 61 62/* for a WIN32 application, use _vsnprintf as basis of vsnprintf/snprintf to 63 * support full set of format specifications. 64 */ 65 66int 67vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap) 68{ 69 int r; 70 71 r = _vsnprintf(buf, bufsize, fmt, ap); 72 73 /* Microsoft _vsnprintf() will not null terminate on overflow, 74 * so null terminate at buffer end on error 75 */ 76 if (r < 0 && bufsize > 0) 77 buf[bufsize - 1] = '\0'; 78 79 return r; 80} 81 82int 83snprintf(char *buf, size_t bufsize, const char *fmt, ...) 84{ 85 va_list ap; 86 int r; 87 88 va_start(ap, fmt); 89 r = vsnprintf(buf, bufsize, fmt, ap); 90 va_end(ap); 91 92 return r; 93} 94 95#else /* BCMSTDLIB_WIN32_APP */ 96 97 98static const char digits[17] = "0123456789ABCDEF"; 99static const char ldigits[17] = "0123456789abcdef"; 100 101static int 102__atox(char *buf, char * end, unsigned int num, unsigned int radix, int width, 103 const char *digits) 104{ 105 char buffer[16]; 106 char *op; 107 int retval; 108 109 op = &buffer[0]; 110 retval = 0; 111 112 do { 113 *op++ = digits[num % radix]; 114 retval++; 115 num /= radix; 116 } while (num != 0); 117 118 if (width && (width > retval)) { 119 width = width - retval; 120 while (width) { 121 *op++ = '0'; 122 retval++; 123 width--; 124 } 125 } 126 127 while (op != buffer) { 128 op--; 129 if (buf <= end) 130 *buf = *op; 131 buf++; 132 } 133 134 return retval; 135} 136 137int 138BCMROMFN(vsnprintf)(char *buf, size_t size, const char *fmt, va_list ap) 139{ 140 char *optr; 141 char *end; 142 const char *iptr; 143 unsigned char *tmpptr; 144 unsigned int x; 145 int i; 146 int leadingzero; 147 int leadingnegsign; 148 int islong; 149 int width; 150 int width2 = 0; 151 int hashash = 0; 152 153 optr = buf; 154 end = buf + size - 1; 155 iptr = fmt; 156 157 if (end < buf - 1) { 158 end = ((void *) -1); 159 size = end - buf + 1; 160 } 161 162 while (*iptr) { 163 if (*iptr != '%') { 164 if (optr <= end) 165 *optr = *iptr; 166 ++optr; 167 ++iptr; 168 continue; 169 } 170 171 iptr++; 172 173 if (*iptr == '#') { 174 hashash = 1; 175 iptr++; 176 } 177 if (*iptr == '-') { 178 leadingnegsign = 1; 179 iptr++; 180 } else 181 leadingnegsign = 0; 182 183 if (*iptr == '0') 184 leadingzero = 1; 185 else 186 leadingzero = 0; 187 188 width = 0; 189 while (*iptr && bcm_isdigit(*iptr)) { 190 width += (*iptr - '0'); 191 iptr++; 192 if (bcm_isdigit(*iptr)) 193 width *= 10; 194 } 195 if (*iptr == '.') { 196 iptr++; 197 width2 = 0; 198 while (*iptr && bcm_isdigit(*iptr)) { 199 width2 += (*iptr - '0'); 200 iptr++; 201 if (bcm_isdigit(*iptr)) width2 *= 10; 202 } 203 } 204 205 islong = 0; 206 if (*iptr == 'l') { 207 islong++; 208 iptr++; 209 } 210 211 switch (*iptr) { 212 case 's': 213 tmpptr = (unsigned char *) va_arg(ap, unsigned char *); 214 if (!tmpptr) tmpptr = (unsigned char *) "(null)"; 215 if ((width == 0) & (width2 == 0)) { 216 while (*tmpptr) { 217 if (optr <= end) 218 *optr = *tmpptr; 219 ++optr; 220 ++tmpptr; 221 } 222 break; 223 } 224 while (width && *tmpptr) { 225 if (optr <= end) 226 *optr = *tmpptr; 227 ++optr; 228 ++tmpptr; 229 width--; 230 } 231 while (width) { 232 if (optr <= end) 233 *optr = ' '; 234 ++optr; 235 width--; 236 } 237 break; 238 case 'd': 239 case 'i': 240 i = va_arg(ap, int); 241 if (i < 0) { 242 if (optr <= end) 243 *optr = '-'; 244 ++optr; 245 i = -i; 246 } 247 optr += __atox(optr, end, i, 10, width, digits); 248 break; 249 case 'u': 250 x = va_arg(ap, unsigned int); 251 optr += __atox(optr, end, x, 10, width, digits); 252 break; 253 case 'X': 254 case 'x': 255 x = va_arg(ap, unsigned int); 256 optr += __atox(optr, end, x, 16, width, 257 (*iptr == 'X') ? digits : ldigits); 258 break; 259 case 'p': 260 case 'P': 261 x = va_arg(ap, unsigned int); 262 optr += __atox(optr, end, x, 16, 8, 263 (*iptr == 'P') ? digits : ldigits); 264 break; 265 case 'c': 266 x = va_arg(ap, int); 267 if (optr <= end) 268 *optr = x & 0xff; 269 optr++; 270 break; 271 272 default: 273 if (optr <= end) 274 *optr = *iptr; 275 optr++; 276 break; 277 } 278 iptr++; 279 } 280 281 if (optr <= end) { 282 *optr = '\0'; 283 return (int)(optr - buf); 284 } else { 285 *end = '\0'; 286 return (int)(end - buf); 287 } 288} 289 290 291int 292BCMROMFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...) 293{ 294 va_list ap; 295 int r; 296 297 va_start(ap, fmt); 298 r = vsnprintf(buf, bufsize, fmt, ap); 299 va_end(ap); 300 301 return r; 302} 303 304#endif /* BCMSTDLIB_WIN32_APP */ 305 306#ifndef BCMSTDLIB_SNPRINTF_ONLY 307 308 309int 310BCMROMFN(vsprintf)(char *buf, const char *fmt, va_list ap) 311{ 312 return (vsnprintf(buf, INT_MAX, fmt, ap)); 313} 314 315 316int 317BCMROMFN(sprintf)(char *buf, const char *fmt, ...) 318{ 319 va_list ap; 320 int count; 321 322 va_start(ap, fmt); 323 count = vsprintf(buf, fmt, ap); 324 va_end(ap); 325 326 return count; 327} 328 329 330void * 331BCMROMFN(memmove)(void *dest, const void *src, size_t n) 332{ 333 /* only use memcpy if there is no overlap. otherwise copy each byte in a safe sequence */ 334 if (((const char *)src >= (char *)dest + n) || ((const char *)src + n <= (char *)dest)) { 335 return memcpy(dest, src, n); 336 } 337 338 /* Overlapping copy forward or backward */ 339 if (src < dest) { 340 unsigned char *d = (unsigned char *)dest + (n - 1); 341 const unsigned char *s = (const unsigned char *)src + (n - 1); 342 while (n) { 343 *d-- = *s--; 344 n--; 345 } 346 } else if (src > dest) { 347 unsigned char *d = (unsigned char *)dest; 348 const unsigned char *s = (const unsigned char *)src; 349 while (n) { 350 *d++ = *s++; 351 n--; 352 } 353 } 354 355 return dest; 356} 357 358#ifndef EFI 359int 360BCMROMFN(memcmp)(const void *s1, const void *s2, size_t n) 361{ 362 const unsigned char *ss1; 363 const unsigned char *ss2; 364 365 ss1 = (const unsigned char *)s1; 366 ss2 = (const unsigned char *)s2; 367 368 while (n) { 369 if (*ss1 < *ss2) 370 return -1; 371 if (*ss1 > *ss2) 372 return 1; 373 ss1++; 374 ss2++; 375 n--; 376 } 377 378 return 0; 379} 380 381/* Skip over functions that are being used from DriverLibrary to save space */ 382char * 383BCMROMFN(strcpy)(char *dest, const char *src) 384{ 385 char *ptr = dest; 386 387 while ((*ptr++ = *src++) != '\0') 388 ; 389 390 return dest; 391} 392 393char * 394BCMROMFN(strncpy)(char *dest, const char *src, size_t n) 395{ 396 char *endp; 397 char *p; 398 399 p = dest; 400 endp = p + n; 401 402 while (p != endp && (*p++ = *src++) != '\0') 403 ; 404 405 /* zero fill remainder */ 406 while (p != endp) 407 *p++ = '\0'; 408 409 return dest; 410} 411 412size_t 413BCMROMFN(strlen)(const char *s) 414{ 415 size_t n = 0; 416 417 while (*s) { 418 s++; 419 n++; 420 } 421 422 return n; 423} 424 425int 426BCMROMFN(strcmp)(const char *s1, const char *s2) 427{ 428 while (*s2 && *s1) { 429 if (*s1 < *s2) 430 return -1; 431 if (*s1 > *s2) 432 return 1; 433 s1++; 434 s2++; 435 } 436 437 if (*s1 && !*s2) 438 return 1; 439 if (!*s1 && *s2) 440 return -1; 441 return 0; 442} 443#endif /* EFI */ 444 445int 446BCMROMFN(strncmp)(const char *s1, const char *s2, size_t n) 447{ 448 while (*s2 && *s1 && n) { 449 if (*s1 < *s2) 450 return -1; 451 if (*s1 > *s2) 452 return 1; 453 s1++; 454 s2++; 455 n--; 456 } 457 458 if (!n) 459 return 0; 460 if (*s1 && !*s2) 461 return 1; 462 if (!*s1 && *s2) 463 return -1; 464 return 0; 465} 466 467char * 468BCMROMFN(strchr)(const char *str, int c) 469{ 470 char *x = (char *)str; 471 472 while (*x != (char)c) { 473 if (*x++ == '\0') 474 return (NULL); 475 } 476 return (x); 477} 478 479char * 480BCMROMFN(strrchr)(const char *str, int c) 481{ 482 char *save = NULL; 483 484 do { 485 if (*str == (char) c) 486 save = (char*)(str); 487 } while (*str++ != '\0'); 488 489 return (save); 490} 491 492/* Skip over functions that are being used from DriverLibrary to save space */ 493#ifndef EFI 494char * 495BCMROMFN(strcat)(char *d, const char *s) 496{ 497 strcpy(&d[strlen(d)], s); 498 return (d); 499} 500#endif /* EFI */ 501 502char * 503BCMROMFN(index)(const char *s, int c) 504{ 505 /* Terminating NUL is considered part of string */ 506 507 for (; *s != c; s++) 508 if (!*s) 509 return NULL; 510 511 return (char *)s; 512} 513 514/* Skip over functions that are being used from DriverLibrary to save space */ 515#ifndef EFI 516char * 517BCMROMFN(strstr)(const char *s, const char *substr) 518{ 519 int substr_len = strlen(substr); 520 521 for (; *s; s++) 522 if (strncmp(s, substr, substr_len) == 0) 523 return (char *)s; 524 525 return NULL; 526} 527#endif /* EFI */ 528 529size_t 530BCMROMFN(strspn)(const char *s, const char *accept) 531{ 532 uint count = 0; 533 534 while (s[count] && index(accept, s[count])) 535 count++; 536 537 return count; 538} 539 540size_t 541BCMROMFN(strcspn)(const char *s, const char *reject) 542{ 543 uint count = 0; 544 545 while (s[count] && !index(reject, s[count])) 546 count++; 547 548 return count; 549} 550 551void * 552BCMROMFN(memchr)(const void *s, int c, size_t n) 553{ 554 if (n != 0) { 555 const unsigned char *ptr = s; 556 557 do { 558 if (*ptr == (unsigned char)c) 559 return (void *)ptr; 560 ptr++; 561 n--; 562 } while (n != 0); 563 } 564 return NULL; 565} 566 567unsigned long 568BCMROMFN(strtoul)(const char *cp, char **endp, int base) 569{ 570 ulong result, value; 571 bool minus; 572 573 minus = FALSE; 574 575 while (bcm_isspace(*cp)) 576 cp++; 577 578 if (cp[0] == '+') 579 cp++; 580 else if (cp[0] == '-') { 581 minus = TRUE; 582 cp++; 583 } 584 585 if (base == 0) { 586 if (cp[0] == '0') { 587 if ((cp[1] == 'x') || (cp[1] == 'X')) { 588 base = 16; 589 cp = &cp[2]; 590 } else { 591 base = 8; 592 cp = &cp[1]; 593 } 594 } else 595 base = 10; 596 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { 597 cp = &cp[2]; 598 } 599 600 result = 0; 601 602 while (bcm_isxdigit(*cp) && 603 (value = bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) < 604 (ulong) base) { 605 result = result * base + value; 606 cp++; 607 } 608 609 if (minus) 610 result = (ulong)(result * -1); 611 612 if (endp) 613 *endp = (char *)cp; 614 615 return (result); 616} 617 618#ifndef EFI 619/* memset is not in ROM offload because it is used directly by the compiler in 620 * structure assignments/character array initialization with "". 621 */ 622void * 623memset(void *dest, int c, size_t n) 624{ 625 uint32 w, *dw; 626 unsigned char *d; 627 628 629 dw = (uint32 *)dest; 630 631 /* 8 min because we have to create w */ 632 if ((n >= 8) && (((uintptr)dest & 3) == 0)) { 633 if (c == 0) 634 w = 0; 635 else { 636 unsigned char ch; 637 638 ch = (unsigned char)(c & 0xff); 639 w = (ch << 8) | ch; 640 w |= w << 16; 641 } 642 while (n >= 4) { 643 *dw++ = w; 644 n -= 4; 645 } 646 } 647 d = (unsigned char *)dw; 648 649 while (n) { 650 *d++ = (unsigned char)c; 651 n--; 652 } 653 654 return d; 655} 656 657/* memcpy is not in ROM offload because it is used directly by the compiler in 658 * structure assignments. 659 */ 660void * 661memcpy(void *dest, const void *src, size_t n) 662{ 663 uint32 *dw; 664 const uint32 *sw; 665 unsigned char *d; 666 const unsigned char *s; 667 668 sw = (const uint32 *)src; 669 dw = (uint32 *)dest; 670 if ((n >= 4) && (((uintptr)src & 3) == 0) && (((uintptr)dest & 3) == 0)) { 671 while (n >= 4) { 672 *dw++ = *sw++; 673 n -= 4; 674 } 675 } 676 d = (unsigned char *)dw; 677 s = (const unsigned char *)sw; 678 while (n) { 679 *d++ = *s++; 680 n--; 681 } 682 683 return dest; 684} 685#endif /* EFI */ 686 687/* Include printf if it has already not been defined as NULL */ 688#ifndef printf 689int 690printf(const char *fmt, ...) 691{ 692 va_list ap; 693 int count, i; 694 char buffer[PRINTF_BUFLEN + 1]; 695 696 va_start(ap, fmt); 697 count = vsnprintf(buffer, sizeof(buffer), fmt, ap); 698 va_end(ap); 699 700 for (i = 0; i < count; i++) { 701 putc(buffer[i]); 702 703#ifdef EFI 704 if (buffer[i] == '\n') 705 putc('\r'); 706#endif 707 } 708 709#ifdef MSGTRACE 710 msgtrace_put(buffer, count); 711#endif 712 713 return count; 714} 715#endif /* printf */ 716 717 718#if !defined(_WIN32) && !defined(_CFE_) && !defined(EFI) 719int 720fputs(const char *s, FILE *stream /* UNUSED */) 721{ 722 char c; 723 while ((c = *s++)) 724 putchar(c); 725 return 0; 726} 727 728int 729puts(const char *s) 730{ 731 fputs(s, stdout); 732 putchar('\n'); 733 return 0; 734} 735 736int 737fputc(int c, FILE *stream /* UNUSED */) 738{ 739 putc(c); 740 return (int)(unsigned char)c; 741} 742 743 744unsigned long 745rand(void) 746{ 747 static unsigned long seed = 1; 748 long x, hi, lo, t; 749 750 x = seed; 751 hi = x / 127773; 752 lo = x % 127773; 753 t = 16807 * lo - 2836 * hi; 754 if (t <= 0) t += 0x7fffffff; 755 seed = t; 756 return t; 757} 758#endif 759#endif /* BCMSTDLIB_SNPRINTF_ONLY */ 760