summaryrefslogtreecommitdiffstats
path: root/main/common/mprintf.c
diff options
context:
space:
mode:
authorAmar Takhar <amar@rtems.org>2015-04-16 15:26:21 -0400
committerAmar Takhar <amar@rtems.org>2015-04-16 15:26:21 -0400
commit87db514f2dfff5ad67863a30f075b718706de346 (patch)
tree31edc1b1700de9f3d4825822534928f8a213d53f /main/common/mprintf.c
downloadumon-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.c691
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);
+}