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