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