diff options
author | Amar Takhar <amar@rtems.org> | 2015-04-16 15:26:21 -0400 |
---|---|---|
committer | Amar Takhar <amar@rtems.org> | 2015-04-16 15:26:21 -0400 |
commit | 87db514f2dfff5ad67863a30f075b718706de346 (patch) | |
tree | 31edc1b1700de9f3d4825822534928f8a213d53f /main/common/mprintf.c | |
download | umon-87db514f2dfff5ad67863a30f075b718706de346.tar.bz2 |
Initial commit of the umon repository.
Prior to this three changes were made:
* Remove umon_ prefix from parent directories.
* Collapse main/target/ into main/
* Remove ports/template/flashtest.scr.ucon script.
Diffstat (limited to 'main/common/mprintf.c')
-rw-r--r-- | main/common/mprintf.c | 691 |
1 files changed, 691 insertions, 0 deletions
diff --git a/main/common/mprintf.c b/main/common/mprintf.c new file mode 100644 index 0000000..c178253 --- /dev/null +++ b/main/common/mprintf.c @@ -0,0 +1,691 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * vmprintf.c: + * + * Same as mprintf, but this uses stdarg.h. + * Cleaner and simpler. I have some targets using this and will probably + * convert all targets to use this eventually. + * + * Note that this requires that the CFLAGS used in the building of this + * file should omit the "-nostdinc" option, so that the standard header + * (stdarg.h) can be pulled in. + * + * Public functions: + * vsnprintf(), snprintf(), sprintf(), printf(), cprintf() + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include <stdarg.h> +#include "stddefs.h" +#include "cli.h" + +extern long abs(long); +extern void puts(char *); +extern int atoi(char *), putchar(char); +int printf(char *fmt, ...); + +static char *hexdigits = "0123456789abcdef"; +static char *Hexdigits = "0123456789ABCDEF"; + +#define MAX_NUMBER_SIZE 18 +#define HDRSIZE 4 +#define NEGATIVE 1 +#define POSITIVE 2 +#define SCREENWIDTH 80 + +/* PROCCHARP(), PROCCHAR(), BUFDEC() & BUFINC(): + * Macros used to conveniently distinguish between buffer-bound + * and console-bound characters during the formatting process. + */ +#define PROCCHARP(bp,eob,cp) \ + if (bp) { \ + if (eob && (bp >= eob)) { \ + puts("s_printf buffer overflow"); \ + return(-1); \ + } \ + *bp++ = *cp++; \ + } \ + else { \ + putchar(*cp++); \ + } + +#define PROCCHAR(bp,eob,c) \ + if (bp) { \ + if (eob && (bp >= eob)) { \ + puts("s_printf buffer overflow"); \ + return(-1); \ + } \ + *bp++ = c; \ + } \ + else { \ + if (c) \ + putchar(c); \ + } + +#define BUFDEC(bp,val) \ + if (bp) { \ + bp -= val; \ + } + +#define BUFINC(bp,val) \ + if (bp) { \ + bp += val; \ + } + + +/* isdigit(): + * Copied here to avoid inclusion of ctype.h + */ +static int +isdigit(char ch) +{ + return ((ch >= '0') && (ch <= '9')); +} + +/* proc_d_prefix(): + * Deal with the characters prior to the 'd' format designator. + * For example, hdr would be '8' in the format %8d. + */ +static int +proc_d_prefix(char *hdr, char *lbp) +{ + char fill; + int minsize, i; + + minsize = 0; + if (hdr[0]) { + if (hdr[0] == '0') + fill = '0'; + else + fill = ' '; + minsize = (short)atoi(hdr); + for(i=0;i<minsize;i++) + *lbp++ = fill; + } + return(minsize); +} + + +/* long_to_dec(): + * Convert an incoming long value to ASCII decimal notation. + */ +int +long_to_dec(long lval,char *buf,char *bufend,char *hdr) +{ + unsigned long value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_d_prefix(hdr,lbuf); + + /* First determine how many ascii digits are needed. */ + value = abs(lval); + size = 0; + while (value > 0) { + size++; + value /= 10; + } + if (lval < 0) + size++; + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + value = abs(lval); + if (value == 0) { + if (minsize==0) { + lbuf[0] = '0'; + size = 1; + } + else + *--lbp = '0'; + } + else { + while (value > 0) { + *--lbp = (char)((value % 10) + '0'); + value /= 10; + } + } + if (lval < 0) + *--lbp = '-'; + lbuf[size] = 0; + + /* At this point, lbuf[] contains the ascii decimal string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + return((int)size); +} + +/* llong_to_dec(): + * Convert an incoming long long value to ASCII decimal notation. + * This is essentially identical to long_to_dec, but we use longlong. + */ +static int +llong_to_dec(int64_t llval,char *buf,char *bufend,char *hdr) +{ + uint64_t value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_d_prefix(hdr, lbuf); + + /* First determine how many ascii digits are needed. */ + value = llval < 0 ? -llval : llval; + size = 0; + while (value > 0) { + size++; + value /= 10; + } + if (llval < 0) + size++; + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + value = llval < 0 ? -llval : llval; + if (value == 0) { + if (minsize==0) { + lbuf[0] = '0'; + size = 1; + } + else + *--lbp = '0'; + } + else { + while (value > 0) { + *--lbp = (char)((value % 10) + '0'); + value /= 10; + } + } + if (llval < 0) + *--lbp = '-'; + lbuf[size] = 0; + + /* At this point, lbuf[] contains the ascii decimal string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + return((int)size); +} + +/* long_to_ip(): + * Convert an incoming long value to an ascii IP formatted + * string (i.e. 0x01020304 is converted to "1.2.3.4") + */ +static int +long_to_ip(long lval,char *buf,char *bufend,char *hdr) +{ + int i, j, len; + unsigned char *lp; + + len = 0; + lp = (unsigned char *)&lval; + for(j=0;j<4;j++) { + i = long_to_dec(*lp++,buf,bufend,hdr); + BUFINC(buf,i); + if (j < 3) { + PROCCHAR(buf,bufend,'.'); + } + len += (i + 1); + } + BUFDEC(buf,1); + len--; + return(len); +} + +/* proc_x_prefix(): + * Deal with the characters prior to the 'x' format designator. + * For example, hdr would be '02' in the format %02x. + */ +static int +proc_x_prefix(char *hdr, char *lbp) +{ + int i, minsize; + + minsize = 0; + if (hdr[0]) { + if (hdr[1]) { + minsize = (short)(hdr[1]&0xf); + for(i=0;i<minsize;i++) + *lbp++ = hdr[0]; + } + else { + minsize = (short)(hdr[0]&0xf); + for(i=0;i<minsize;i++) + *lbp++ = ' '; + } + } + return(minsize); +} + +/* long_to_hex(): + * Convert an incoming long value to ASCII hexadecimal notation. + */ +static int +long_to_hex(ulong lval,char *buf,char *bufend,char *hdr, char x) +{ + ulong value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_x_prefix(hdr,lbuf); + + /* First determine how many ascii digits are needed. */ + value = lval; + size = 0; + while (value > 0) { + size++; + value /= 16; + } + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + if (lval == 0) { + if (size == 0) + size = 1; + else + lbp--; + *lbp = '0'; + } + else { + while (lval > 0) { + if (x == 'X') + *--lbp = Hexdigits[(int)(lval % 16)]; + else + *--lbp = hexdigits[(int)(lval % 16)]; + lval /= 16; + } + } + lbp[size] = 0; + + /* At this point, lbuf[] contains the ascii hex string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + + return((int)size); +} + +/* llong_to_hex(): + * Convert an incoming long long value to ASCII hexadecimal notation. + */ +static int +llong_to_hex(uint64_t llval,char *buf,char *bufend,char *hdr, char x) +{ + uint64_t value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_x_prefix(hdr,lbuf); + + /* First determine how many ascii digits are needed. */ + value = llval; + size = 0; + while (value > 0) { + size++; + value /= 16; + } + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + if (llval == 0) { + if (size == 0) + size = 1; + else + lbp--; + *lbp = '0'; + } + else { + while (llval > 0) { + if (x == 'X') + *--lbp = Hexdigits[(int)(llval % 16)]; + else + *--lbp = hexdigits[(int)(llval % 16)]; + llval /= 16; + } + } + lbp[size] = 0; + + /* At this point, lbuf[] contains the ascii hex string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + + return((int)size); +} + +/* bin_to_mac(): + * Convert an incoming buffer to an ascii MAC formatted + * string (i.e. buf[] = 010203040506 is converted to "01:02:03:04:05:06") + */ +static int +bin_to_mac(uchar *ibin,char *buf,char *bufend) +{ + int i, j, len; + + len = 0; + for(j=0;j<6;j++) { + i = long_to_hex(*ibin++,buf,bufend,"02",'x'); + BUFINC(buf,i); + if (j < 5) { + PROCCHAR(buf,bufend,':'); + } + len += (i + 1); + } + BUFDEC(buf,1); + len--; + return(len); +} + +/* build_string(): + * Build a string from 'src' to 'dest' based on the hdr and sign + * values. Return the size of the string (may include left or right + * justified padding). + */ +static int +build_string(char *src,char *dest,char *bufend,char *hdr,int sign) +{ + char *cp1; + short minsize, i, j; + + if (!src) { + cp1 = "NULL_POINTER"; + while(*cp1) { + PROCCHARP(dest,bufend,cp1); + } + return(12); + } + if (!*src) + return(0); + if (!hdr[0]) { + j = 0; + while(*src) { + PROCCHARP(dest,bufend,src); + j++; + } + return(j); + } + minsize = (short)atoi(hdr); + i = 0; + cp1 = (char *)src; + while(*cp1) { + i++; + cp1++; + } + cp1 = (char *)src; + j = 0; + if (minsize > i) { + if (sign == POSITIVE) { + while(minsize > i) { + j++; + PROCCHAR(dest,bufend,' '); + minsize--; + } + while(*cp1) { + j++; + PROCCHARP(dest,bufend,cp1); + } + } + else { + while(*cp1) { + j++; + PROCCHARP(dest,bufend,cp1); + } + while(minsize > i) { + j++; + PROCCHAR(dest,bufend,' '); + minsize--; + } + } + } + else { + while(*cp1) { + j++; + PROCCHARP(dest,bufend,cp1); + } + } + return(j); +} + +/* vsnprintf(): + * Backend to all the others below it. + * Formats incoming argument list based on format string. + * Terminates population of buffer if it is to exceed the + * specified buffer size. + */ +int +vsnprintf(char *buf,int bsize, char *fmt, va_list argp) +{ + long arg_l; + long long arg_ll; + int i, sign, tot; + char *cp, hdr[HDRSIZE], *base, *bufend, arg_c, *arg_cp, ll; + + ll = 0; + tot = 0; + base = buf; + + if (bsize == 0) + bufend = 0; + else + bufend = base+(bsize-1); + + cp = fmt; + for(i=0;i<HDRSIZE;i++) + hdr[i] = 0; + while(*cp) { + if (*cp != '%') { + PROCCHARP(buf,bufend,cp); + tot++; + continue; + } + cp++; + if (*cp == '%') { + PROCCHARP(buf,bufend,cp); + tot++; + continue; + } + sign = POSITIVE; + if (*cp == '-') { + sign = NEGATIVE; + cp++; + } + if (isdigit(*cp)) { + for(i=0;i<(HDRSIZE-1);i++) { + if (isdigit(*cp)) + hdr[i] = *cp++; + else + break; + } + } + + ll = 0; + if (*cp == 'l') { /* Ignore the 'long' designator */ + cp++; + if (*cp == 'l') { /* unless its the longlong designator */ + cp++; + ll = 1; + } + } + + switch(*cp) { + case 'c': /* Character conversion */ + arg_c = (char)va_arg(argp,int); + PROCCHAR(buf,bufend,arg_c); + tot++; + break; + case 's': /* String conversion */ + arg_cp = (char *)va_arg(argp,int); + i = build_string(arg_cp,buf,bufend,hdr,sign); + BUFINC(buf,i); + tot += i; + break; + case 'M': /* MAC address conversion */ + arg_cp = (char *)va_arg(argp,int); + i = bin_to_mac((uchar *)arg_cp,buf,bufend); + BUFINC(buf,i); + tot += i; + break; + case 'I': /* IP address conversion */ + arg_l = (long)va_arg(argp,int); + i = long_to_ip(arg_l,buf,bufend,hdr); + BUFINC(buf,i); + tot += i; + break; + case 'd': /* Decimal conversion */ + case 'u': + if (ll) { + arg_ll = (long long)va_arg(argp,long long); + i = llong_to_dec(arg_ll,buf,bufend,hdr); + } + else { + arg_l = (long)va_arg(argp,int); + i = long_to_dec(arg_l,buf,bufend,hdr); + } + BUFINC(buf,i); + tot += i; + break; + case 'p': /* Hex conversion */ + case 'x': + case 'X': + if (*cp == 'p') { + PROCCHAR(buf,bufend,'0'); + PROCCHAR(buf,bufend,'x'); + } + if (ll) { + arg_ll = (long long)va_arg(argp,long long); + i = llong_to_hex(arg_ll,buf,bufend,hdr,*cp); + } + else { + arg_l = (long)va_arg(argp,int); + i = long_to_hex((ulong)arg_l,buf,bufend,hdr,*cp); + } + BUFINC(buf,i); + tot += i; + break; + default: + PROCCHARP(buf,bufend,cp); + tot++; + break; + } + cp++; + + if (hdr[0]) { + for(i=0;i<HDRSIZE;i++) + hdr[i] = 0; + } + } + PROCCHAR(buf,bufend,0); + return(tot); +} + +/* snprintf(), sprintf(), printf() & cprintf(): + * All functions use vsnprintf() to format a string. + * The string is either transferred to a buffer or transferred + * directly to this target's console through putchar (refer to + * the macros at the top of this file). + * + * - sprintf() formats to a buffer. + * - printf() formats to stdio. + * - cprintf() formats to a buffer, then centers the content of + * the buffer based on its size and a console screen with of + * SCREENWIDTH characters. + */ +int +snprintf(char *buf, int bsize, char *fmt, ...) +{ + int tot; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(buf,bsize,fmt,argp); + va_end(argp); + return(tot); +} + +int +sprintf(char *buf, char *fmt, ...) +{ + int tot; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(buf,0,fmt,argp); + va_end(argp); + return(tot); +} + +int +printf(char *fmt, ...) +{ + int tot; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(0,0,fmt,argp); + va_end(argp); + return(tot); +} + +int +cprintf(char *fmt, ...) +{ + int i, tot, spaces; + char pbuf[CMDLINESIZE]; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(pbuf,CMDLINESIZE,fmt,argp); + va_end(argp); + + if (tot < SCREENWIDTH) { + spaces = (SCREENWIDTH-tot)/2; + for(i=0;i<spaces;i++) + putchar(' '); + } + else + spaces = 0; + + for(i=0;i<tot;i++) + putchar(pbuf[i]); + + return(tot+spaces); +} |