/************************************************************************** * * * PROJECT : TMON (Transparent monitor) * * * * MODULE : LIBC.c * * * * AUTHOR : Michael Anburaj * * URL : http://geocities.com/michaelanburaj/ * * EMAIL: michaelanburaj@hotmail.com * * * * PROCESSOR : MIPS 4Kc (32 bit RISC) - ATLAS board * * * * TOOL-CHAIN : SDE & Cygnus * * * * DESCRIPTION : * * This is the LIBC module. Implements most of the standard library * * functions. * * * **************************************************************************/ #include "ministd.h" /* ********************************************************************* */ /* Global definitions */ /* for errno.h */ int errno; /* File local definitions */ /* for _doprintx */ #define BUF 32 #define ARG() \ _ulong = \ (flags & SHORTINT) ? \ (uint32_t)((int16_t)((uint16_t)va_arg(argp, uint32_t))) : \ (uint32_t)va_arg(argp, uint32_t); #define todigit(c) ((c) - '0') #define tochar(n) ((n) + '0') /* have to deal with the negative buffer count kludge */ #define NEGATIVE_COUNT_KLUDGE #define LONGINT 0x01 /* long integer */ #define LONGDBL 0x02 /* long double; unimplemented */ #define SHORTINT 0x04 /* short integer */ #define ALT 0x08 /* alternate form */ #define LADJUST 0x10 /* left adjustment */ #define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ #define HEXPREFIX 0x40 /* add 0x or 0X prefix */ #define SPACE 0x80 /* space if plus */ #define SIGN 0x100 /* unsigned/signed long */ #define PLUS 0x200 /* show plus */ #define CR 0x13 #define LF 0x10 #define _U 0x01 /* upper */ #define _L 0x02 /* lower */ #define _D 0x04 /* digit */ #define _C 0x08 /* cntrl */ #define _P 0x10 /* punct */ #define _S 0x20 /* white space (space/lf/tab) */ #define _X 0x40 /* hex digit */ #define _SP 0x80 /* hard space (0x20) */ extern const unsigned char _ctype[]; /* for strtol */ #define max_allowable(A) (MAXINT/A - 1) #define __ismask(x) (_ctype[(int)(unsigned char)(x)]) #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) #define iscntrl(c) ((__ismask(c)&(_C)) != 0) #define isdigit(c) ((__ismask(c)&(_D)) != 0) #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) #define islower(c) ((__ismask(c)&(_L)) != 0) #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) #define ispunct(c) ((__ismask(c)&(_P)) != 0) #define isspace(c) ((__ismask(c)&(_S)) != 0) #define isupper(c) ((__ismask(c)&(_U)) != 0) #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) #define isascii(c) (((unsigned char)(c))<=0x7f) #define toascii(c) (((unsigned char)(c))&0x7f) long strtol( const char *str, char **endptr, int base); void *memchr( const void *s, int c, size_t n); #ifndef TAB #define TAB_CH 0x09 #else #define TAB_CH TAB #endif #define SPACE_CH 0x20 #ifndef SkipWhiteSpace #define SkipWhiteSpace(z) while (*z == TAB_CH || *z == SPACE_CH) z++; #endif #ifndef toupper int toupper(int c); #endif #ifndef isnum #define isnum(x) (x >= '0' && x <= '9') ? 1 : 0 #endif #ifndef ishexnum #define ishexnum(x) ((x >= '0' && x <= '9') || ((x & 0xDF) >= 'A' && (x & 0xDF) <= 'F')) ? 1 : 0 #endif #ifndef MAXINT #define MAXINT (int)0x7FFFFFFF #endif #ifndef ERANGE #define ERANGE 34 #endif int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); /* ********************************************************************* */ /* Local functions */ #if 0 /* JPF */ static int skip_atoi(const char **s) { int i=0; while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; return i; } /* * No traps on overflows for any of these... */ #define do_div64_32(res, high, low, base) ({ \ unsigned long __quot, __mod; \ unsigned long __cf, __tmp, __tmp2, __i; \ \ __asm__(".set push\n\t" \ ".set noat\n\t" \ ".set noreorder\n\t" \ "move %2, $0\n\t" \ "move %3, $0\n\t" \ "b 1f\n\t" \ " li %4, 0x21\n" \ "0:\n\t" \ "sll $1, %0, 0x1\n\t" \ "srl %3, %0, 0x1f\n\t" \ "or %0, $1, %5\n\t" \ "sll %1, %1, 0x1\n\t" \ "sll %2, %2, 0x1\n" \ "1:\n\t" \ "bnez %3, 2f\n\t" \ "sltu %5, %0, %z6\n\t" \ "bnez %5, 3f\n\t" \ "2:\n\t" \ " addiu %4,%4,-1\n\t" \ "subu %0, %0, %z6\n\t" \ "addiu %2, %2, 1\n" \ "3:\n\t" \ "bnez %4, 0b\n\t" \ " srl %5, %1, 0x1f\n\t" \ ".set pop" \ : "=&r" (__mod), "=&r" (__tmp), "=&r" (__quot), "=&r" (__cf), \ "=&r" (__i), "=&r" (__tmp2) \ : "Jr" (base), "0" (high), "1" (low)); \ \ (res) = __quot; \ __mod; }) #define do_div(n, base) ({ \ unsigned long long __quot; \ unsigned long __upper, __low, __high, __mod; \ \ __quot = (n); \ __high = __quot >> 32; \ __low = __quot; \ __upper = __high; \ \ if (__high) \ __asm__("divu $0,%z2,%z3" \ : "=h" (__upper), "=l" (__high) \ : "Jr" (__high), "Jr" (base)); \ \ __mod = do_div64_32(__low, __upper, __low, base); \ \ __quot = __high; \ __quot = __quot << 32 | __low; \ (n) = __quot; \ __mod; }) static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type) { char c,sign,tmp[66]; const char *digits; int i; digits = (type & LONGDBL) ? large_digits : small_digits; if (type & LADJUST) type &= ~ZEROPAD; if (base < 2 || base > 36) return 0; c = (type & ZEROPAD) ? '0' : ' '; sign = 0; if (type & SIGN) { if (num < 0) { sign = '-'; num = -num; size--; } else if (type & PLUS) { sign = '+'; size--; } else if (type & SPACE) { sign = ' '; size--; } } if (type & HEXPREFIX) { if (base == 16) size -= 2; else if (base == 8) size--; } i = 0; if (num == 0) tmp[i++]='0'; else while (num != 0) tmp[i++] = digits[do_div(num,base)]; if (i > precision) precision = i; size -= precision; if (!(type&(ZEROPAD+LADJUST))) { while(size-->0) { if (buf <= end) *buf = ' '; ++buf; } } if (sign) { if (buf <= end) *buf = sign; ++buf; } if (type & HEXPREFIX) { if (base==8) { if (buf <= end) *buf = '0'; ++buf; } else if (base==16) { if (buf <= end) *buf = '0'; ++buf; if (buf <= end) *buf = digits[33]; ++buf; } } if (!(type & LADJUST)) { while (size-- > 0) { if (buf <= end) *buf = c; ++buf; } } while (i < precision--) { if (buf <= end) *buf = '0'; ++buf; } while (i-- > 0) { if (buf <= end) *buf = tmp[i]; ++buf; } while (size-- > 0) { if (buf <= end) *buf = ' '; ++buf; } return buf; } /* ********************************************************************************************* * _doprntx * * Description: * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ static int _doprntx( char *fmt0, va_list argp, void (*putc)(), char **pca) { uint8_t *fmt; /* format string */ int ch; /* character from fmt */ int cnt; /* return value accumulator */ int n; /* random handy integer */ char *t; /* buffer pointer */ uint32_t _ulong; /* integer arguments %[diouxX] */ int base; /* base for [diouxX] conversion */ int dprec; /* decimal precision in [diouxX] */ int fieldsz; /* field size expanded by sign, etc */ int flags; /* flags as above */ int fpprec; /* `extra' floating precision in [eEfgG]*/ int prec; /* precision from format (%.3d), or -1 */ int realsz; /* field size expanded by decimal precision */ int size; /* size of converted field or string */ int width; /* width from format (%8d), or 0 */ char sign; /* sign prefix (' ', '+', '-', or \0) */ char *digs; /* digits for [diouxX] conversion */ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ fmt = (uint8_t*)fmt0; digs = "0123456789abcdef"; for (cnt = 0;; ++fmt) { for (; (ch = *fmt) && ch != '%'; ++cnt, ++fmt) if(ch!='\n') putc(ch, pca); else { putc(CR, pca); putc(LF, pca); ++cnt; }; if (!ch) return (cnt); flags = 0; dprec = 0; fpprec = 0; width = 0; prec = -1; sign = '\0'; rflag: switch (*++fmt) { case ' ': /* * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 */ if (!sign) sign = ' '; goto rflag; case '#': flags |= ALT; goto rflag; case '*': /* * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ if ((width = va_arg(argp, int)) >= 0) goto rflag; width = -width; /* FALLTHROUGH */ case '-': flags |= LADJUST; goto rflag; case '+': sign = '+'; goto rflag; case '.': if (*++fmt == '*') n = va_arg(argp, int); else { n = 0; while (isascii(*fmt) && isdigit(*fmt)) n = 10 * n + todigit(*fmt++); --fmt; } prec = n < 0 ? -1 : n; goto rflag; case '0': /* * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 */ flags |= ZEROPAD; goto rflag; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 0; do { n = 10 * n + todigit(*fmt); } while (isascii(*++fmt) && isdigit(*fmt)); width = n; --fmt; goto rflag; case 'L': flags |= LONGDBL; goto rflag; case 'h': flags |= SHORTINT; goto rflag; case 'l': flags |= LONGINT; goto rflag; case 'c': *(t = buf) = va_arg(argp, int); size = 1; sign = '\0'; goto pforw; case 'D': flags |= LONGINT; /*FALLTHROUGH*/ case 'd': case 'i': ARG(); if ((long)_ulong < 0) { _ulong = -_ulong; sign = '-'; } base = 10; goto number; case 'n': if (flags & LONGINT) *va_arg(argp, long *) = cnt; else if (flags & SHORTINT) *va_arg(argp, short *) = cnt; else *va_arg(argp, int *) = cnt; break; case 'O': flags |= LONGINT; /*FALLTHROUGH*/ case 'o': ARG(); base = 8; goto nosign; case 'p': /* * ``The argument shall be a pointer to void. The * value of the pointer is converted to a sequence * of printable characters, in an implementation- * defined manner.'' * -- ANSI X3J11 */ /* NOSTRICT */ _ulong = (uint32_t)va_arg(argp, void *); base = 16; goto nosign; case 's': if (!(t = va_arg(argp, char *))) t = "(null)"; if (prec >= 0) { /* * can't use strlen; can only look for the * NUL in the first `prec' characters, and * strlen() will go further. */ char *p; if ((p = memchr(t, 0, prec))) { size = p - t; if (size > prec) size = prec; } else size = prec; } else size = strlen(t); sign = '\0'; goto pforw; case 'U': flags |= LONGINT; /*FALLTHROUGH*/ case 'u': ARG(); base = 10; goto nosign; case 'X': digs = "0123456789ABCDEF"; /* FALLTHROUGH */ case 'x': ARG(); base = 16; /* leading 0x/X only if non-zero */ if (flags & ALT && _ulong != 0) flags |= HEXPREFIX; /* unsigned conversions */ nosign: sign = '\0'; /* * ``... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored.'' * -- ANSI X3J11 */ number: if ((dprec = prec) >= 0) flags &= ~ZEROPAD; /* * ``The result of converting a zero value with an * explicit precision of zero is no characters.'' * -- ANSI X3J11 */ t = buf + BUF; if (_ulong != 0 || prec != 0) { do { *--t = digs[_ulong % base]; _ulong /= base; } while (_ulong); digs = "0123456789abcdef"; if (flags & ALT && base == 8 && *t != '0') *--t = '0'; /* octal leading 0 */ } size = buf + BUF - t; pforw: /* * All reasonable formats wind up here. At this point, * `t' points to a string which (if not flags&LADJUST) * should be padded out to `width' places. If * flags&ZEROPAD, it should first be prefixed by any * sign or other prefix; otherwise, it should be blank * padded before the prefix is emitted. After any * left-hand padding and prefixing, emit zeroes * required by a decimal [diouxX] precision, then print * the string proper, then emit zeroes required by any * leftover floating precision; finally, if LADJUST, * pad with blanks. */ /* * compute actual size, so we know how much to pad * fieldsz excludes decimal prec; realsz includes it */ fieldsz = size + fpprec; if (sign) fieldsz++; if (flags & HEXPREFIX) fieldsz += 2; realsz = dprec > fieldsz ? dprec : fieldsz; /* right-adjusting blank padding */ if ((flags & (LADJUST|ZEROPAD)) == 0 && width) for (n = realsz; n < width; n++) putc(' ', pca); /* prefix */ if (sign) putc(sign, pca); if (flags & HEXPREFIX) { putc('0', pca); putc((char)*fmt, pca); } /* right-adjusting zero padding */ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) for (n = realsz; n < width; n++) putc('0', pca); /* leading zeroes from decimal precision */ for (n = fieldsz; n < dprec; n++) putc('0', pca); /* the string or number proper */ n=size; while (--n >= 0) putc(*t++, pca); /* trailing f.p. zeroes */ while (--fpprec >= 0) putc('0', pca); /* left-adjusting padding (always blank) */ if (flags & LADJUST) for (n = realsz; n < width; n++) putc(' ', pca); /* finally, adjust cnt */ cnt += width > realsz ? width : realsz; break; case '\0': /* "%?" prints ?, unless ? is NULL */ return (cnt); default: putc((char)*fmt, pca); cnt++; } } /* NOTREACHED */ } /* ********************************************************************* */ /* Global functions */ /* ********************************************************************************************* * atoi * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ int atoi(char *s) { return (int) strtol ((const char *)s, (char **) 0, 10); } #endif /* ********************************************************************************************* * memchr * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ void *memchr( const void *s, int c, size_t n) { char *mys = (char *)s; while ((int)--n >= 0) if (*mys++ == c) return (void *) --mys; return NULL; } #if 0 /* JPF */ /* ********************************************************************************************* * putch * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ static void putch(char ch, char **pca) { *(*pca)++ = ch; } /* ********************************************************************************************* * printf * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ static void _putc(char ch, char **pca) { CONSOL_SendCh(ch); } int printf(const char *fmt, ...) { int ret; va_list args; va_start(args,fmt); ret = _doprntx((char *)fmt, args, (void (*)())_putc, 0); va_end(args); return ret; } int vprintf(const char *fmt, va_list ap) { int ret; ret = _doprntx((char *)fmt, ap, (void (*)())_putc, 0); return ret; } /* ********************************************************************************************* * vsprintf * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ int vsprintf(char *buf, char *fmt, va_list ap) { int len = _doprntx(fmt, ap, (void (*)())putch, &buf); putch(0, &buf); return len; } #endif /* ********************************************************************************************* * sprintf * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ int sprintf(char* buf, ...) { va_list args; char *fmt; int len; va_start(args, buf); fmt = va_arg(args, char *); len = vsnprintf(buf, 256, fmt, args); va_end(args); return len; } /* ********************************************************************************************* * strcpy * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ #if 0 /* JPF */ char *strcpy(char *s1, const char *s2) { char *s = s1; while ((*s1++ = *s2++)); return s; } /* ********************************************************************************************* * strlen * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ int strlen(const char *s) { int l = 0; while (*s++) l++; return l; } #endif /* ********************************************************************************************* * strtol * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ long strtol( const char *str, char **endptr, int base) { long i = 0; int s = 1; int c; /* skip white space */ while(isspace(*str)) { str++; } /* sign flag check */ if (*str == '+') str++; else if (*str == '-') { s = -1; str++; } if (*str == '0') { if (toupper(*++str) == 'X') base = 16,str++; else if (base == 0) base = 8; } if (base == 0) base = 10; if (base <= 10) /* digit str to number */ for (; isdigit(*str); str++) { if (i < max_allowable(base)) i = i * base + (*str - '0'); else { i = MAXINT; errno = ERANGE; } } else if (base > 10) { for (; (c = *str); str++) { if (isdigit(c)) c = c - '0'; else { c = toupper(c); if (c >= 'A' && c < ('A' - 10 + base)) c = c - 'A' + 10; else break; } if (i < max_allowable(base)) i = i * base + c; else { i = MAXINT; errno = ERANGE; } } } else return 0; /* negative base is not allowed */ if (endptr) *endptr = (char *) str; if (s == -1) i = -i; return i; } /* ********************************************************************************************* * tolower * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ int tolower(int c) { if (isupper(c)) return c + ('a' - 'A'); else return c; } /* ********************************************************************************************* * toupper * * Description: Look in the standard headers. * * Arguments : * * Return : * * Note(s) : ********************************************************************************************* */ int toupper(int c) { if (islower(c)) return c - ('a' - 'A'); else return c; } /* ********************************************************************************************* * memcmp * * Description: Look in the standard headers. * The memcmp() function returns an integer less than, equal to, or * greater than zero if the first n bytes of s1 is found, respectively, to * be less than, to match, or be greater than the first n bytes of s2. * * Arguments : * s1 pointer to first memory address to compare * s2 pointer to 2nd memory address to compare * n number of bytes to compare * Return : * * Note(s) : ********************************************************************************************* */ #if 0 /* JPF */ int memcmp(const void *s1, const void *s2, size_t n) { register unsigned char c1, c2; for (; n--; s1++, s2++) { c1 = *(unsigned char *)s1; c2 = *(unsigned char *)s2; if (c1 != c2) return (c1 - c2); } return 0; } /* ********************************************************************************************* * strcmp * * The strcmp() function compares the two strings s1 and s2. It returns * an integer less than, equal to, or greater than zero if s1 is found, * respectively, to be less than, to match, or be greater than s2. * * Arguments : * s1 pointer to first string address to compare * s2 pointer to 2nd string address to compare * Return : * * Note(s) : ********************************************************************************************* */ int strcmp(const char *s1, const char *s2) { while (*s1 == *s2++) { if ('\0' == *s1++) return 0; }; return (*s1 - *s2); } #endif /* ********************************************************************************************* * strncmp * * The strncmp() function is similar, except it only compares the first * (at most) n characters of s1 and s2. * * Arguments : * s1 pointer to first string address to compare * s2 pointer to 2nd string address to compare * n number of bytes to compare * Return : * * Note(s) : ********************************************************************************************* */ #if 0 int strncmp(const char *s1, const char *s2, size_t n) { register unsigned char c1, c2; while (n-- > 0) { c1 = (unsigned char)*s1++; c2 = (unsigned char)*s2++; if (c1 != c2) return (c1 - c2); if ('\0' == c1) return 0; } return 0; } #endif /* ********************************************************************************************* * strncpy * * The strncpy() function is similar, except that not more than n bytes of * src are copied. Thus, if there is no null byte among the first n bytes * of src, the result will not be null-terminated. * * Arguments : * dest pointer to destination address to copy * src pointer to source address to copy * n number of bytes to compare * Return : * * Note(s) : ********************************************************************************************* */ #if 0 /* JPF */ char *strncpy(char *dest, const char *src, size_t n) { if (n != 0) { register char *d = dest; register const char *s = src; do { if ((*d++ = *s++) == 0) { /* NUL pad the remaining n-1 bytes */ while (--n != 0) *d++ = 0; break; } } while (--n != 0); } return (dest); } #endif /* ********************************************************************************************* * strcat * * The strcat() function appends the src string to the dest string over- * writing the `\0' character at the end of dest, and then adds a termi- * nating `\0' character. The strings may not overlap, and the dest * string must have enough space for the result. * * Arguments : * dest pointer to destination address to concatenate * src pointer to source address to concatenate * Return : * * Note(s) : ********************************************************************************************* */ char *strcat(char *dest, const char *src) { register char *s1 = dest; while (*dest++); --dest; while ((*dest++ = *src++)); return s1; } /* ********************************************************************************************* * strcat * * The strcat() function appends the src string to the dest string over- * writing the `\0' character at the end of dest, and then adds a termi- * nating `\0' character. The strings may not overlap, and the dest * string must have enough space for the result. * * Arguments : * dest pointer to destination address to concatenate * src pointer to source address to concatenate * Return : * * Note(s) : ********************************************************************************************* */ char *strncat(char *dest, const char *src,int n) { register char *s1 = dest; while (*dest++); --dest; while ((*dest++ = *src++)); return s1; } /* ********************************************************************************************* * memmove * * The memmove() function copies n bytes from memory area src to memory * area dest. The memory areas may overlap. * * Arguments : * dest pointer to destination address to move * src pointer to source address to move * n n bytes to move * Return : * * Note(s) : ********************************************************************************************* */ void *memmove(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } /* ********************************************************************************************* * strchr * * * The strchr() function returns a pointer to the first occurrence of the * character c in the string s. * * Arguments : * s pointer to string to search for * c charactor to search for * Return : * * Note(s) : ********************************************************************************************* */ char *strchr(register const char *s, int c) { do { if ((int)(*s) == c) { return (char *)s; } } while (*s++); return 0; } /* ********************************************************************************************* * sscanf * * * The scanf family of functions scans input according to a format as * described below. This format may contain conversion specifiers; the * results from such conversions, if any, are stored through the pointer * arguments. The scanf function reads input from the standard input * stream stdin, fscanf reads input from the stream pointer stream, and * sscanf reads its input from the character string pointed to by str. * * Arguments : * buf pointer to string to scan for * fmt format string to scan for * arg arguments. Note that only one parameter is used. * Return : * * Note(s) : ********************************************************************************************* */ #if 0 /* JPF */ int sscanf (char* buf, const char* fmt, unsigned int * arg) { int valid; unsigned int result, base; char * pbuf; if (!buf || !fmt || !arg) return 0; SkipWhiteSpace(fmt); SkipWhiteSpace(buf); pbuf = buf; if (*fmt != '%') return 0; fmt++; if (*fmt == 'x' || *fmt == 'X') base = 16; else if (*fmt == 'd' || *fmt == 'D') base = 10; else return 0; for (valid=0,result=0,pbuf=buf; ishexnum(*pbuf); pbuf++) { result *= base; if (isnum (*pbuf)) result += (unsigned long) (*pbuf - 0x30); else if (base == 16) result += (unsigned long) (toupper(*pbuf) - 0x37); else return 0; valid=1; } if (valid) *arg = result; return valid; } size_t strnlen(const char * s, size_t count) { const char *sc; for (sc = s; count-- && *sc != '\0'; ++sc) /* nothing */; return sc - s; } int perror(const char *str) { printf(str); printf("\n"); return 0; } #endif /** * vsnprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @size: The size of the buffer, including the trailing null space * @fmt: The format string to use * @args: Arguments for the format string * * Call this function if you are already dealing with a va_list. * You probably want snprintf instead. */ #if 0 /* JPF */ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { int len; unsigned long long num; int i, base; char *str, *end, c; const char *s; int flags; /* flags to number() */ int field_width; /* width of output field */ int precision; /* min. # of digits for integers; max number of chars for from string */ int qualifier; /* 'h', 'l', or 'L' for integer fields */ /* 'z' support added 23/7/1999 S.H. */ /* 'z' changed to 'Z' --davidm 1/25/99 */ str = buf; end = buf + size - 1; if (end < buf - 1) { end = ((void *) -1); size = end - buf + 1; } for (; *fmt ; ++fmt) { if (*fmt != '%') { if (str <= end) *str = *fmt; ++str; continue; } /* process flags */ flags = 0; repeat: ++fmt; /* this also skips first '%' */ switch (*fmt) { case '-': flags |= LADJUST; goto repeat; case '+': flags |= PLUS; goto repeat; case ' ': flags |= SPACE; goto repeat; case '#': flags |= HEXPREFIX; goto repeat; case '0': flags |= ZEROPAD; goto repeat; } /* get field width */ field_width = -1; if (isdigit(*fmt)) field_width = skip_atoi(&fmt); else if (*fmt == '*') { ++fmt; /* it's the next argument */ field_width = va_arg(args, int); if (field_width < 0) { field_width = -field_width; flags |= LADJUST; } } /* get the precision */ precision = -1; if (*fmt == '.') { ++fmt; if (isdigit(*fmt)) precision = skip_atoi(&fmt); else if (*fmt == '*') { ++fmt; /* it's the next argument */ precision = va_arg(args, int); } if (precision < 0) precision = 0; } /* get the conversion qualifier */ qualifier = -1; if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') { qualifier = *fmt; ++fmt; if (qualifier == 'l' && *fmt == 'l') { qualifier = 'L'; ++fmt; } } /* default base */ base = 10; switch (*fmt) { case 'c': if (!(flags & LADJUST)) { while (--field_width > 0) { if (str <= end) *str = ' '; ++str; } } c = (unsigned char) va_arg(args, int); if (str <= end) *str = c; ++str; while (--field_width > 0) { if (str <= end) *str = ' '; ++str; } continue; case 's': s = va_arg(args, char *); if (!s) s = ""; len = strnlen(s, precision); len = strnlen(s, precision); if (!(flags & LADJUST)) { while (len < field_width--) { if (str <= end) *str = ' '; ++str; } } for (i = 0; i < len; ++i) { if (str <= end) *str = *s; ++str; ++s; } while (len < field_width--) { if (str <= end) *str = ' '; ++str; } continue; case 'p': if (field_width == -1) { field_width = 2*sizeof(void *); flags |= ZEROPAD; } str = number(str, end, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); continue; case 'n': /* FIXME: * What does C99 say about the overflow case here? */ if (qualifier == 'l') { long * ip = va_arg(args, long *); *ip = (str - buf); } else if (qualifier == 'Z') { size_t * ip = va_arg(args, size_t *); *ip = (str - buf); } else { int * ip = va_arg(args, int *); *ip = (str - buf); } continue; case '%': if (str <= end) *str = '%'; ++str; continue; /* integer number formats - set up the flags and "break" */ case 'o': base = 8; break; case 'X': flags |= LONGDBL; case 'x': base = 16; break; case 'd': case 'i': flags |= SIGN; case 'u': break; default: if (str <= end) *str = '%'; ++str; if (*fmt) { if (str <= end) *str = *fmt; ++str; } else { --fmt; } continue; } if (qualifier == 'L') num = va_arg(args, long long); else if (qualifier == 'l') { num = va_arg(args, unsigned long); if (flags & SIGN) num = (signed long) num; } else if (qualifier == 'Z') { num = va_arg(args, size_t); } else if (qualifier == 'h') { num = (unsigned short) va_arg(args, int); if (flags & SIGN) num = (signed short) num; } else { num = va_arg(args, unsigned int); if (flags & SIGN) num = (signed int) num; } str = number(str, end, num, base, field_width, precision, flags); } if (str <= end) *str = '\0'; else if (size > 0) /* don't write out a null byte if the buf size is zero */ *end = '\0'; /* the trailing null byte doesn't count towards the total * ++str; */ return str-buf; } #endif /** * strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ unsigned long strtoul(const char *cp,char **endp,int base) { unsigned long result = 0,value; if (!base) { base = 10; if (*cp == '0') { base = 8; cp++; if ((*cp == 'x') && isxdigit(cp[1])) { cp++; base = 16; } } } while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { result = result*base + value; cp++; } if (endp) *endp = (char *)cp; return result; } char* strtok(char *s, const char *delim) { const char *spanp; int c, sc; char *tok; static char *last; if (s == NULL && (s = last) == NULL) return (NULL); /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). */ cont: c = *s++; for (spanp = delim; (sc = *spanp++) != 0;) { if (c == sc) goto cont; } if (c == 0) { /* no non-delimiter characters */ last = NULL; return (NULL); } tok = s - 1; /* * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for (;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; last = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } /* * The strspn() function calculates the length of the initial segment of s * which consists entirely of characters in accept. */ int strspn (const char *string, const char *accept) { size_t count = 0; while (strchr (accept, *string)) { ++count, ++string; } return count; } /* * The strcspn() function calculates the length of the initial segment of * s which consists entirely of characters not in reject. * which contains no characters from REJECT. */ int strcspn (const char *s, const char *reject) { size_t count = 0; while (*s != '\0') if (strchr (reject, *s++) == NULL) ++count; else return count; return count; } /* * The strstr() function finds the first occurrence of the substring nee- * dle in the string haystack. The terminating `\0' characters are not * compared. */ char * strstr (const char *buf, const char *sub) { register char *bp; register char *sp; if (!*sub) return (char *)buf; while (*buf) { bp = (char *)buf; sp = (char *)sub; do { if (!*sp) return (char *)buf; } while (*bp++ == *sp++); buf += 1; } return NULL; } void exit(int stat) { __asm__("sdbbp"); } void abort(int stat) { __asm__("sdbbp"); } int abs(int j) { if (j < 0) return -j; return j; } /* ministd.c also defined this function */ #if 0 void *realloc(void *ptr,int size) { void *nptr; if (!ptr) return malloc(size); nptr = malloc(size); if (!nptr) return NULL; memcpy(nptr,ptr,size); free(ptr); return nptr; } #endif /* bdbg.c also defined this function */ #if 0 char* strrchr(char *s,int c) { int len = strlen(s); char* lptr = &s[len]; while (len) { if (*lptr == (char)c) { return lptr; } len--; lptr--; } return NULL; } #endif char * strpbrk (const char *s, const char *accept) { while (*s != '\0') { const char *a = accept; while (*a != '\0') if (*a++ == *s) return (char *) s; ++s; } return NULL; } typedef struct div_t { int q; int rem; }div_t; div_t div(int num, int den) { static div_t q; q.q = num/den; q.rem = num % den; return q; } extern int atoi(char *s); long atol(char* s) { return (long)atoi(s); } char *strerror(int errnum) { static char s_errstr[64]; snprintf(s_errstr,64,"%s = %d\n",__FUNCTION__,errnum); return s_errstr; } /* ********************************************************************* */