kern

changeset 5:633e35c64772

- added printf family in stdio.c - added atoi/atol in stdlib.c - added nonstandard itoa/utoa in stdlib.c - added strlen/strchr/strrchr in string.c
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 19 Dec 2010 15:07:07 +0200
parents 0489a34ab348
children 7e40f14617ed
files src/klibc/stdio.c src/klibc/stdio.h src/klibc/stdlib.h src/klibc/string.c src/klibc/string.h
diffstat 5 files changed, 302 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- a/src/klibc/stdio.c	Fri Dec 10 03:44:34 2010 +0200
     1.2 +++ b/src/klibc/stdio.c	Sun Dec 19 15:07:07 2010 +0200
     1.3 @@ -1,4 +1,9 @@
     1.4  #include <stdio.h>
     1.5 +#include <string.h>
     1.6 +#include <ctype.h>
     1.7 +
     1.8 +static void bwrite(char *buf, size_t buf_sz, char *str, int sz);
     1.9 +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap);
    1.10  
    1.11  /* putchar is defined in term.c */
    1.12  
    1.13 @@ -10,3 +15,243 @@
    1.14  	putchar('\n');
    1.15  	return 0;
    1.16  }
    1.17 +
    1.18 +/* -- printf and friends -- */
    1.19 +
    1.20 +static char *convc = "dioxXucsfeEgGpn%";
    1.21 +
    1.22 +#define IS_CONV(c)	strchr(convc, c)
    1.23 +
    1.24 +int printf(const char *fmt, ...)
    1.25 +{
    1.26 +	int res;
    1.27 +	va_list ap;
    1.28 +
    1.29 +	va_start(ap, fmt);
    1.30 +	res = intern_printf(0, 0, fmt, ap);
    1.31 +	va_end(ap);
    1.32 +	return res;
    1.33 +}
    1.34 +
    1.35 +int vprintf(const char *fmt, va_list ap)
    1.36 +{
    1.37 +	return intern_printf(0, 0, fmt, ap);
    1.38 +}
    1.39 +
    1.40 +int sprintf(char *buf, const char *fmt, ...)
    1.41 +{
    1.42 +	int res;
    1.43 +	va_list ap;
    1.44 +
    1.45 +	va_start(ap, fmt);
    1.46 +	res = intern_printf(buf, 0, fmt, ap);
    1.47 +	va_end(ap);
    1.48 +	return res;
    1.49 +}
    1.50 +
    1.51 +int vsprintf(char *buf, const char *fmt, va_list ap)
    1.52 +{
    1.53 +	return intern_printf(buf, 0, fmt, ap);
    1.54 +}
    1.55 +
    1.56 +int snprintf(char *buf, size_t sz, const char *fmt, ...)
    1.57 +{
    1.58 +	int res;
    1.59 +	va_list ap;
    1.60 +
    1.61 +	va_start(ap, fmt);
    1.62 +	res = intern_printf(buf, sz, fmt, ap);
    1.63 +	va_end(ap);
    1.64 +	return res;
    1.65 +}
    1.66 +
    1.67 +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
    1.68 +{
    1.69 +	return intern_printf(buf, sz, fmt, ap);
    1.70 +}
    1.71 +
    1.72 +
    1.73 +/* intern_printf provides all the functionality needed by all the printf
    1.74 + * variants.
    1.75 + * - buf: optional buffer onto which the formatted results are written. If null
    1.76 + *   then the output goes to the terminal through putchar calls. This is used
    1.77 + *   by the (v)sprintf variants which write to an array of char.
    1.78 + * - sz: optional maximum size of the output, 0 means unlimited. This is used
    1.79 + *   by the (v)snprintf variants to avoid buffer overflows.
    1.80 + * The rest are obvious, format string and variable argument list.
    1.81 + */
    1.82 +
    1.83 +#define BUF(x)	((x) ? (x) + cnum : (x))
    1.84 +#define SZ(x)	((x) ? (x) - cnum : (x))
    1.85 +
    1.86 +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap)
    1.87 +{
    1.88 +	char conv_buf[32];
    1.89 +	char *str;
    1.90 +	int i, slen;
    1.91 +	const char *fstart = 0;
    1.92 +
    1.93 +	/* state */
    1.94 +	int cnum = 0;
    1.95 +	int base = 10;
    1.96 +	int alt = 0;
    1.97 +	int fwidth = 0;
    1.98 +	int padc = ' ';
    1.99 +	int sign = 0;
   1.100 +	int left_align = 0;	/* not implemented yet */
   1.101 +	int hex_caps = 0;
   1.102 +	int unsig = 0;
   1.103 +
   1.104 +	while(*fmt) {
   1.105 +		if(*fmt == '%') {
   1.106 +			fstart = fmt++;
   1.107 +			continue;
   1.108 +		}
   1.109 +
   1.110 +		if(fstart) {
   1.111 +			if(IS_CONV(*fmt)) {
   1.112 +				switch(*fmt) {
   1.113 +				case 'X':
   1.114 +					hex_caps = 1;
   1.115 +
   1.116 +				case 'x':
   1.117 +				case 'p':
   1.118 +					base = 16;
   1.119 +
   1.120 +					if(alt) {
   1.121 +						bwrite(BUF(buf), SZ(sz), "0x", 2);
   1.122 +					}
   1.123 +
   1.124 +				case 'u':
   1.125 +					unsig = 1;
   1.126 +
   1.127 +					if(0) {
   1.128 +				case 'o':
   1.129 +						base = 8;
   1.130 +
   1.131 +						if(alt) {
   1.132 +							bwrite(BUF(buf), SZ(sz), "0", 1);
   1.133 +						}
   1.134 +					}
   1.135 +
   1.136 +				case 'd':
   1.137 +				case 'i':
   1.138 +					if(unsig) {
   1.139 +						utoa(va_arg(ap, unsigned int), conv_buf, base);
   1.140 +					} else {
   1.141 +						itoa(va_arg(ap, int), conv_buf, base);
   1.142 +					}
   1.143 +					if(hex_caps) {
   1.144 +						for(i=0; conv_buf[i]; i++) {
   1.145 +							conv_buf[i] = toupper(conv_buf[i]);
   1.146 +						}
   1.147 +					}
   1.148 +
   1.149 +					slen = strlen(conv_buf);
   1.150 +					for(i=slen; i<fwidth; i++) {
   1.151 +						bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
   1.152 +						cnum++;
   1.153 +					}
   1.154 +
   1.155 +					bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
   1.156 +					cnum += slen;
   1.157 +					break;
   1.158 +
   1.159 +				case 'c':
   1.160 +					{
   1.161 +						char c = va_arg(ap, int);
   1.162 +						bwrite(BUF(buf), SZ(sz), &c, 1);
   1.163 +						cnum++;
   1.164 +					}
   1.165 +					break;
   1.166 +
   1.167 +				case 's':
   1.168 +					str = va_arg(ap, char*);
   1.169 +					slen = strlen(str);
   1.170 +
   1.171 +					for(i=slen; i<fwidth; i++) {
   1.172 +						bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
   1.173 +						cnum++;
   1.174 +					}
   1.175 +					bwrite(BUF(buf), SZ(sz), str, slen);
   1.176 +					cnum += slen;
   1.177 +					break;
   1.178 +
   1.179 +				case 'n':
   1.180 +					*va_arg(ap, int*) = cnum;
   1.181 +					break;
   1.182 +
   1.183 +				default:
   1.184 +					break;
   1.185 +				}
   1.186 +
   1.187 +				/* restore default conversion state */
   1.188 +				base = 10;
   1.189 +				alt = 0;
   1.190 +				fwidth = 0;
   1.191 +				padc = ' ';
   1.192 +				hex_caps = 0;
   1.193 +
   1.194 +				fstart = 0;
   1.195 +				fmt++;
   1.196 +			} else {
   1.197 +				switch(*fmt) {
   1.198 +				case '#':
   1.199 +					alt = 1;
   1.200 +					break;
   1.201 +
   1.202 +				case '+':
   1.203 +					sign = 1;
   1.204 +					break;
   1.205 +
   1.206 +				case '-':
   1.207 +					left_align = 1;
   1.208 +					break;
   1.209 +
   1.210 +				case 'l':
   1.211 +				case 'L':
   1.212 +					break;
   1.213 +
   1.214 +				case '0':
   1.215 +					padc = '0';
   1.216 +					break;
   1.217 +
   1.218 +				default:
   1.219 +					if(isdigit(*fmt)) {
   1.220 +						const char *fw = fmt;
   1.221 +						while(*fmt && isdigit(*fmt)) fmt++;
   1.222 +
   1.223 +						fwidth = atoi(fw);
   1.224 +						continue;
   1.225 +					}
   1.226 +				}
   1.227 +				fmt++;
   1.228 +			}
   1.229 +		} else {
   1.230 +			bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
   1.231 +			cnum++;
   1.232 +		}
   1.233 +	}
   1.234 +
   1.235 +	return 0;
   1.236 +}
   1.237 +
   1.238 +
   1.239 +/* bwrite is called by intern_printf to transparently handle writing into a
   1.240 + * buffer (if buf is non-null) or to the terminal (if buf is null).
   1.241 + */
   1.242 +static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
   1.243 +{
   1.244 +	if(buf) {
   1.245 +		if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
   1.246 +		memcpy(buf, str, sz);
   1.247 +
   1.248 +		buf[sz] = 0;
   1.249 +	} else {
   1.250 +		int i;
   1.251 +		for(i=0; i<sz; i++) {
   1.252 +			putchar(*str++);
   1.253 +		}
   1.254 +	}
   1.255 +}
   1.256 +
     2.1 --- a/src/klibc/stdio.h	Fri Dec 10 03:44:34 2010 +0200
     2.2 +++ b/src/klibc/stdio.h	Sun Dec 19 15:07:07 2010 +0200
     2.3 @@ -1,7 +1,19 @@
     2.4  #ifndef STDIO_H_
     2.5  #define STDIO_H_
     2.6  
     2.7 +#include <stdlib.h>
     2.8 +#include <stdarg.h>
     2.9 +
    2.10  int putchar(int c);
    2.11  int puts(const char *s);
    2.12  
    2.13 +int printf(const char *fmt, ...);
    2.14 +int vprintf(const char *fmt, va_list ap);
    2.15 +
    2.16 +int sprintf(char *buf, const char *fmt, ...);
    2.17 +int vsprintf(char *buf, const char *fmt, va_list ap);
    2.18 +
    2.19 +int snprintf(char *buf, size_t sz, const char *fmt, ...);
    2.20 +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap);
    2.21 +
    2.22  #endif	/* STDIO_H_ */
     3.1 --- a/src/klibc/stdlib.h	Fri Dec 10 03:44:34 2010 +0200
     3.2 +++ b/src/klibc/stdlib.h	Sun Dec 19 15:07:07 2010 +0200
     3.3 @@ -6,4 +6,10 @@
     3.4  typedef int32_t ssize_t;
     3.5  typedef uint32_t size_t;
     3.6  
     3.7 +int atoi(const char *str);
     3.8 +long atol(const char *str);
     3.9 +
    3.10 +void itoa(int val, char *buf, int base);
    3.11 +void utoa(unsigned int val, char *buf, int base);
    3.12 +
    3.13  #endif	/* STDLIB_H_ */
     4.1 --- a/src/klibc/string.c	Fri Dec 10 03:44:34 2010 +0200
     4.2 +++ b/src/klibc/string.c	Sun Dec 19 15:07:07 2010 +0200
     4.3 @@ -54,3 +54,37 @@
     4.4  
     4.5  	return dest;
     4.6  }
     4.7 +
     4.8 +size_t strlen(const char *s)
     4.9 +{
    4.10 +	size_t len = 0;
    4.11 +	while(*s++) len++;
    4.12 +	return len;
    4.13 +}
    4.14 +
    4.15 +char *strchr(const char *s, int c)
    4.16 +{
    4.17 +	while(*s) {
    4.18 +		if(*s == c) {
    4.19 +			return s;
    4.20 +		}
    4.21 +		s++;
    4.22 +	}
    4.23 +	return 0;
    4.24 +}
    4.25 +
    4.26 +char *strrchr(const char *s, int c)
    4.27 +{
    4.28 +	char *ptr = s;
    4.29 +
    4.30 +	/* find the end */
    4.31 +	while(*ptr) ptr++;
    4.32 +
    4.33 +	/* go back checking for c */
    4.34 +	while(*--ptr >= s) {
    4.35 +		if(*ptr == c) {
    4.36 +			return ptr;
    4.37 +		}
    4.38 +	}
    4.39 +	return 0;
    4.40 +}
     5.1 --- a/src/klibc/string.h	Fri Dec 10 03:44:34 2010 +0200
     5.2 +++ b/src/klibc/string.h	Sun Dec 19 15:07:07 2010 +0200
     5.3 @@ -9,4 +9,9 @@
     5.4  void *memcpy(void *dest, const void *src, size_t n);
     5.5  void *memmove(void *dest, const void *src, size_t n);
     5.6  
     5.7 +size_t strlen(const char *s);
     5.8 +
     5.9 +char *strchr(const char *s, int c);
    5.10 +char *strrchr(const char *s, int c);
    5.11 +
    5.12  #endif	/* STRING_H_ */