[PATCH 1/3] score: Add _IO_Printf() and _IO_Vprintf()

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Nov 3 12:11:26 UTC 2017


The previous vprintk() implementation had a questionable licence header,
lacks support for the 'z' and 'j' format specifiers, is not robust
against invalid format specifiers, uses a global variable for output.
Replace it with a stripped down version of the FreeBSD kernel kvprintf()
function.

The new implementation allows a low overhead rtems_snprintf() if
necessary.

Update #3199.
Close #3216.
---
 cpukit/libcsupport/src/vprintk.c         | 220 ++-----------------
 cpukit/score/Makefile.am                 |   3 +
 cpukit/score/include/rtems/score/io.h    |  46 ++++
 cpukit/score/preinstall.am               |   4 +
 cpukit/score/src/ioprintf.c              |  31 +++
 cpukit/score/src/iovprintf.c             | 365 +++++++++++++++++++++++++++++++
 testsuites/sptests/spprintk/init.c       | 161 +++++++++-----
 testsuites/sptests/spprintk/spprintk.scn |  81 ++++---
 8 files changed, 613 insertions(+), 298 deletions(-)
 create mode 100644 cpukit/score/include/rtems/score/io.h
 create mode 100644 cpukit/score/src/ioprintf.c
 create mode 100644 cpukit/score/src/iovprintf.c

diff --git a/cpukit/libcsupport/src/vprintk.c b/cpukit/libcsupport/src/vprintk.c
index a254934a0d..09b6f0f006 100644
--- a/cpukit/libcsupport/src/vprintk.c
+++ b/cpukit/libcsupport/src/vprintk.c
@@ -6,224 +6,32 @@
  */
 
 /*
- * (C) Copyright 1997 -
- * - NavIST Group - Real-Time Distributed Systems and Industrial Automation
+ * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
  *
- * http://pandora.ist.utl.pt
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
  *
- * Instituto Superior Tecnico * Lisboa * PORTUGAL
- *
- * Disclaimer:
- *
- * This file is provided "AS IS" without warranty of any kind, either
- * expressed or implied.
- *
- * This code is based on code by: Jose Rufino - IST
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
  */
 
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdbool.h>
 #include <rtems/bspIo.h>
+#include <rtems/score/io.h>
 
-static int printNum(
-  long long num,
-  unsigned base,
-  bool sign,
-  unsigned maxwidth,
-  char lead
-);
-
-/**
- *  A simplified version of printf intended for use when the
- *  console is not yet initialized or in ISR's.
- *
- * Arguments:
- *    as in printf: fmt - format string, ... - unnamed arguments.
- */
-int vprintk(
-  const char *fmt,
-  va_list     ap
-)
+static void vprintk_putchar( int c, void *arg )
 {
-  int len_out = 0;
-  for (; *fmt != '\0'; fmt++) {
-    unsigned base = 0;
-    unsigned width = 0;
-    enum {
-      LFLAG_INT,
-      LFLAG_LONG,
-      LFLAG_LONG_LONG
-    } lflag = LFLAG_INT;
-    bool minus = false;
-    bool sign = false;
-    char lead = ' ';
-    char c = *fmt;
-    long long num;
-
-    if (c != '%') {
-      rtems_putc(c);
-      ++len_out;
-      continue;
-    }
-
-    ++fmt; c = *fmt;
-
-    if (c == '0') {
-      lead = '0';
-      ++fmt; c = *fmt;
-    }
-
-    if (c == '-') {
-      minus = true;
-      ++fmt; c = *fmt;
-    }
-
-    while (c >= '0' && c <= '9' ) {
-      width *= 10;
-      width += ((unsigned) c - '0');
-      ++fmt; c = *fmt;
-    }
-
-    if (c == 'l') {
-      lflag = LFLAG_LONG;
-      ++fmt; c = *fmt;
-
-      if (c == 'l') {
-        lflag = LFLAG_LONG_LONG;
-        ++fmt; c = *fmt;
-      }
-    }
-
-    if ( c == 'c' ) {
-      /* need a cast here since va_arg() only takes fully promoted types */
-      char chr = (char) va_arg(ap, int);
-      rtems_putc(chr);
-      ++len_out;
-      continue;
-    }
-
-    if ( c == 's' ) {
-      unsigned i, len;
-      char *s, *str;
-
-      str = va_arg(ap, char *);
-
-      if ( str == NULL ) {
-        str = "";
-      }
-
-      /* calculate length of string */
-      for ( len=0, s=str ; *s ; len++, s++ )
-        ;
-
-      /* leading spaces */
-      if ( !minus )
-        for ( i=len ; i<width ; i++, len_out++ )
-          rtems_putc(' ');
-
-      /* no width option */
-      if (width == 0) {
-          width = len;
-      }
-
-      /* output the string */
-      for ( i=0 ; i<width && *str ; str++, len_out++ )
-        rtems_putc(*str);
-
-      /* trailing spaces */
-      if ( minus )
-        for ( i=len ; i<width ; i++, len_out++ )
-          rtems_putc(' ');
-
-      continue;
-    }
-
-    /* must be a numeric format or something unsupported */
-    if ( c == 'o' || c == 'O' ) {
-      base = 8; sign = false;
-    } else if ( c == 'i' || c == 'I' ||
-                c == 'd' || c == 'D' ) {
-      base = 10; sign = true;
-    } else if ( c == 'u' || c == 'U' ) {
-      base = 10; sign = false;
-    } else if ( c == 'x' || c == 'X' ) {
-      base = 16; sign = false;
-    } else if ( c == 'p' ) {
-      base = 16; sign = false; lflag = LFLAG_LONG;
-    } else {
-      rtems_putc(c);
-      ++len_out;
-      continue;
-    }
-
-    switch (lflag) {
-      case LFLAG_LONG:
-        num = sign ? (long long) va_arg(ap, long)
-          : (long long) va_arg(ap, unsigned long);
-        break;
-      case LFLAG_LONG_LONG:
-        num = va_arg(ap, long long);
-        break;
-      case LFLAG_INT:
-      default:
-        num = sign ? (long long) va_arg(ap, int)
-          : (long long) va_arg(ap, unsigned int);
-        break;
-    }
-
-    len_out += printNum(num, base, sign, width, lead);
-  }
-
-  return len_out;
+  rtems_putc((char) c);
 }
 
-/**
- *  @brief Print Number in a Given Base
- *  @param[in] num is the number to print
- *  @param[in] base is the base used to print the number
- */
-static int printNum(
-  long long num,
-  unsigned base,
-  bool sign,
-  unsigned maxwidth,
-  char lead
-)
+int vprintk( const char *fmt, va_list ap )
 {
-  unsigned long long unsigned_num;
-  unsigned long long n;
-  unsigned count;
-  #define UINT64_MAX_IN_OCTAL_FORMAT "1777777777777777777777"
-  char toPrint[sizeof(UINT64_MAX_IN_OCTAL_FORMAT)];
-  int len_out = 0;
-
-  if ( sign && (num <  0) ) {
-    rtems_putc('-');
-    ++len_out;
-    unsigned_num = (unsigned long long) -num;
-    if (maxwidth) maxwidth--;
-  } else {
-    unsigned_num = (unsigned long long) num;
-  }
-
-  count = 0;
-  while ((n = unsigned_num / base) > 0) {
-    toPrint[count++] = (char) (unsigned_num - (n * base));
-    unsigned_num = n;
-  }
-  toPrint[count++] = (char) unsigned_num;
-
-  for (n=maxwidth ; n > count; n--, len_out++ )
-    rtems_putc(lead);
-
-  for (n = 0; n < count; n++, len_out++) {
-    rtems_putc("0123456789ABCDEF"[(int)(toPrint[count-(n+1)])]);
-  }
-
-  return len_out;
+  return _IO_Vprintf( vprintk_putchar, NULL, fmt, ap );
 }
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index 7ff1f41684..11bf59cca8 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -46,6 +46,7 @@ include_rtems_score_HEADERS += include/rtems/score/heap.h
 include_rtems_score_HEADERS += include/rtems/score/heapimpl.h
 include_rtems_score_HEADERS += include/rtems/score/protectedheap.h
 include_rtems_score_HEADERS += include/rtems/score/interr.h
+include_rtems_score_HEADERS += include/rtems/score/io.h
 include_rtems_score_HEADERS += include/rtems/score/isr.h
 include_rtems_score_HEADERS += include/rtems/score/isrlevel.h
 include_rtems_score_HEADERS += include/rtems/score/isrlock.h
@@ -333,6 +334,8 @@ libscore_a_SOURCES += src/chain.c \
     src/chainnodecount.c \
     src/debugisthreaddispatchingallowed.c \
     src/interr.c src/isr.c src/wkspace.c src/wkstringduplicate.c
+libscore_a_SOURCES += src/ioprintf.c
+libscore_a_SOURCES += src/iovprintf.c
 libscore_a_SOURCES += src/isrisinprogress.c
 libscore_a_SOURCES += src/condition.c
 libscore_a_SOURCES += src/debugisownerofallocator.c
diff --git a/cpukit/score/include/rtems/score/io.h b/cpukit/score/include/rtems/score/io.h
new file mode 100644
index 0000000000..ae3c57f031
--- /dev/null
+++ b/cpukit/score/include/rtems/score/io.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef _RTEMS_SCORE_IO_H
+#define _RTEMS_SCORE_IO_H
+
+#include <rtems/score/basedefs.h>
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef void ( *IO_Put_char )(int c, void *arg);
+
+int _IO_Printf(
+  IO_Put_char  put_char,
+  void        *arg,
+  char const  *fmt,
+  ...
+) RTEMS_PRINTFLIKE( 3, 4 );
+
+int _IO_Vprintf(
+  IO_Put_char  put_char,
+  void        *arg,
+  char const  *fmt,
+  va_list      ap
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_IO_H */
diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am
index 0329b9ce92..3d70ec311f 100644
--- a/cpukit/score/preinstall.am
+++ b/cpukit/score/preinstall.am
@@ -152,6 +152,10 @@ $(PROJECT_INCLUDE)/rtems/score/interr.h: include/rtems/score/interr.h $(PROJECT_
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/interr.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/interr.h
 
+$(PROJECT_INCLUDE)/rtems/score/io.h: include/rtems/score/io.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/io.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/io.h
+
 $(PROJECT_INCLUDE)/rtems/score/isr.h: include/rtems/score/isr.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/isr.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/isr.h
diff --git a/cpukit/score/src/ioprintf.c b/cpukit/score/src/ioprintf.c
new file mode 100644
index 0000000000..05e31566e7
--- /dev/null
+++ b/cpukit/score/src/ioprintf.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/io.h>
+
+int _IO_Printf( IO_Put_char put_char, void *arg, char const  *fmt, ... )
+{
+  va_list ap;
+  int     len;
+
+  va_start( ap, fmt );
+  len = _IO_Vprintf( put_char, arg, fmt, ap );
+  va_end( ap );
+
+  return len;
+}
diff --git a/cpukit/score/src/iovprintf.c b/cpukit/score/src/iovprintf.c
new file mode 100644
index 0000000000..cf54ecbbc7
--- /dev/null
+++ b/cpukit/score/src/iovprintf.c
@@ -0,0 +1,365 @@
+/*-
+ * Copyright (c) 1986, 1988, 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
+ */
+
+#include <rtems/score/io.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/kern/subr_prf.c 320908 2017-07-12 07:30:14Z rlibby $");
+
+#include <sys/param.h>
+#include <string.h>
+
+/* Max number conversion buffer length: a intmax_t in base 8, plus NUL byte. */
+#define MAXNBUF	(howmany(sizeof(intmax_t) * NBBY, 3) + 1)
+
+static inline int imax(int a, int b) { return (a > b ? a : b); }
+
+static char const hex2ascii_data[2][16] = {
+    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+      'a', 'b', 'c', 'd', 'e', 'f' },
+    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+      'A', 'B', 'C', 'D', 'E', 'F' }
+};
+
+static inline char
+hex2ascii(int hex)
+{
+
+	return (hex2ascii_data[0][hex]);
+}
+
+/*
+ * Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse
+ * order; return an optional length and a pointer to the last character
+ * written in the buffer (i.e., the first character of the string).
+ * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
+ */
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
+{
+	char *p;
+
+	p = nbuf;
+	*p = '\0';
+	do {
+		*++p = hex2ascii_data[upper][num % base];
+	} while (num /= base);
+	if (lenp)
+		*lenp = p - nbuf;
+	return (p);
+}
+
+int
+_IO_Vprintf(IO_Put_char put_char, void *arg, char const *fmt, va_list ap)
+{
+#define PCHAR(c) {int cc=(c); (*put_char)(cc, arg); retval++; }
+	char nbuf[MAXNBUF];
+	const char *p, *percent, *q;
+	u_char *up;
+	int ch, n;
+	uintmax_t num;
+	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
+	int cflag, hflag, jflag;
+	RTEMS_STATIC_ASSERT(sizeof(intmax_t) == sizeof(long long), _IO_Vprintf_j);
+#if __SIZEOF_PTRDIFF_T__ == __SIZEOF_LONG__
+#define	tflag lflag
+#else
+	int tflag;
+#endif
+#if __SIZEOF_SIZE_T__ == __SIZEOF_LONG__
+#define	zflag lflag
+#else
+	int zflag;
+#endif
+	int dwidth, upper;
+	char padc;
+	int stop = 0, retval = 0;
+
+	num = 0;
+
+	if (fmt == NULL)
+		fmt = "(fmt null)\n";
+
+	for (;;) {
+		padc = ' ';
+		width = 0;
+		while ((ch = (u_char)*fmt++) != '%' || stop) {
+			if (ch == '\0')
+				return (retval);
+			PCHAR(ch);
+		}
+		percent = fmt - 1;
+		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
+		sign = 0; dot = 0; dwidth = 0; upper = 0;
+		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
+reswitch:	switch (ch = (u_char)*fmt++) {
+		case '.':
+			dot = 1;
+			goto reswitch;
+		case '#':
+			sharpflag = 1;
+			goto reswitch;
+		case '+':
+			sign = 1;
+			goto reswitch;
+		case '-':
+			ladjust = 1;
+			goto reswitch;
+		case '%':
+			PCHAR(ch);
+			break;
+		case '*':
+			if (!dot) {
+				width = va_arg(ap, int);
+				if (width < 0) {
+					ladjust = !ladjust;
+					width = -width;
+				}
+			} else {
+				dwidth = va_arg(ap, int);
+			}
+			goto reswitch;
+		case '0':
+			if (!dot) {
+				padc = '0';
+				goto reswitch;
+			}
+		case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+				for (n = 0;; ++fmt) {
+					n = n * 10 + ch - '0';
+					ch = *fmt;
+					if (ch < '0' || ch > '9')
+						break;
+				}
+			if (dot)
+				dwidth = n;
+			else
+				width = n;
+			goto reswitch;
+		case 'c':
+			width -= 1;
+
+			if (!ladjust && width > 0)
+				while (width--)
+					PCHAR(padc);
+			PCHAR(va_arg(ap, int));
+			if (ladjust && width > 0)
+				while (width--)
+					PCHAR(padc);
+			break;
+		case 'D':
+			up = va_arg(ap, u_char *);
+			p = va_arg(ap, char *);
+			if (!width)
+				width = 16;
+			while(width--) {
+				PCHAR(hex2ascii(*up >> 4));
+				PCHAR(hex2ascii(*up & 0x0f));
+				up++;
+				if (width)
+					for (q=p;*q;q++)
+						PCHAR(*q);
+			}
+			break;
+		case 'd':
+		case 'i':
+			base = 10;
+			sign = 1;
+			goto handle_sign;
+		case 'h':
+			if (hflag) {
+				hflag = 0;
+				cflag = 1;
+			} else
+				hflag = 1;
+			goto reswitch;
+		case 'j':
+			jflag = 1;
+			goto reswitch;
+		case 'l':
+			if (lflag) {
+				jflag = 1;
+			} else
+				lflag = 1;
+			goto reswitch;
+		case 'o':
+			base = 8;
+			goto handle_nosign;
+		case 'p':
+			base = 16;
+			sharpflag = (width == 0);
+			sign = 0;
+			num = (uintptr_t)va_arg(ap, void *);
+			goto number;
+		case 's':
+			p = va_arg(ap, char *);
+			if (p == NULL)
+				p = "(null)";
+			if (!dot)
+				n = strlen (p);
+			else
+				for (n = 0; n < dwidth && p[n]; n++)
+					continue;
+
+			width -= n;
+
+			if (!ladjust && width > 0)
+				while (width--)
+					PCHAR(padc);
+			while (n--)
+				PCHAR(*p++);
+			if (ladjust && width > 0)
+				while (width--)
+					PCHAR(padc);
+			break;
+		case 't':
+			tflag = 1;
+			goto reswitch;
+		case 'u':
+			base = 10;
+			goto handle_nosign;
+		case 'X':
+			upper = 1;
+		case 'x':
+			base = 16;
+			goto handle_nosign;
+		case 'y':
+			base = 16;
+			sign = 1;
+			goto handle_sign;
+		case 'z':
+			zflag = 1;
+			goto reswitch;
+handle_nosign:
+			sign = 0;
+			if (jflag)
+				num = va_arg(ap, uintmax_t);
+#if __SIZEOF_PTRDIFF_T__ != __SIZEOF_LONG__
+			else if (tflag)
+				num = va_arg(ap, ptrdiff_t);
+#endif
+			else if (lflag)
+				num = va_arg(ap, u_long);
+#if __SIZEOF_SIZE_T__ != __SIZEOF_LONG__
+			else if (zflag)
+				num = va_arg(ap, size_t);
+#endif
+			else if (hflag)
+				num = (u_short)va_arg(ap, int);
+			else if (cflag)
+				num = (u_char)va_arg(ap, int);
+			else
+				num = va_arg(ap, u_int);
+			goto number;
+handle_sign:
+			if (jflag)
+				num = va_arg(ap, intmax_t);
+#if __SIZEOF_PTRDIFF_T__ == __SIZEOF_LONG__
+			else if (tflag)
+				num = va_arg(ap, ptrdiff_t);
+#endif
+			else if (lflag)
+				num = va_arg(ap, long);
+#if __SIZEOF_SIZE_T__ == __SIZEOF_LONG__
+			else if (zflag)
+				num = va_arg(ap, ssize_t);
+#endif
+			else if (hflag)
+				num = (short)va_arg(ap, int);
+			else if (cflag)
+				num = (char)va_arg(ap, int);
+			else
+				num = va_arg(ap, int);
+number:
+			if (sign && (intmax_t)num < 0) {
+				neg = 1;
+				num = -(intmax_t)num;
+			}
+			p = ksprintn(nbuf, num, base, &n, upper);
+			tmp = 0;
+			if (sharpflag && num != 0) {
+				if (base == 8)
+					tmp++;
+				else if (base == 16)
+					tmp += 2;
+			}
+			if (neg)
+				tmp++;
+
+			if (!ladjust && padc == '0')
+				dwidth = width - tmp;
+			width -= tmp + imax(dwidth, n);
+			dwidth -= n;
+			if (!ladjust)
+				while (width-- > 0)
+					PCHAR(' ');
+			if (neg)
+				PCHAR('-');
+			if (sharpflag && num != 0) {
+				if (base == 8) {
+					PCHAR('0');
+				} else if (base == 16) {
+					PCHAR('0');
+					PCHAR('x');
+				}
+			}
+			while (dwidth-- > 0)
+				PCHAR('0');
+
+			while (*p)
+				PCHAR(*p--);
+
+			if (ladjust)
+				while (width-- > 0)
+					PCHAR(' ');
+
+			break;
+		default:
+			while (percent < fmt)
+				PCHAR(*percent++);
+			/*
+			 * Since we ignore a formatting argument it is no
+			 * longer safe to obey the remaining formatting
+			 * arguments as the arguments will no longer match
+			 * the format specs.
+			 */
+			stop = 1;
+			break;
+		}
+	}
+#undef PCHAR
+}
diff --git a/testsuites/sptests/spprintk/init.c b/testsuites/sptests/spprintk/init.c
index e956c76ff3..4ef28daf5d 100644
--- a/testsuites/sptests/spprintk/init.c
+++ b/testsuites/sptests/spprintk/init.c
@@ -13,7 +13,7 @@
 #include "config.h"
 #endif
 
-#include <rtems/score/basedefs.h>
+#include <rtems/score/io.h>
 
 /*
  * Undefined the RTEMS_PRINTFLIKE and make it nothing. The test code
@@ -27,19 +27,12 @@
 
 const char rtems_test_name[] = "SPPRINTK";
 
-/* forward declarations to avoid warnings */
-rtems_task Init(rtems_task_argument argument);
-int test_getchar(void);
-void do_getchark(void);
-void do_putk(void);
-void do_printk(void);
-
-int test_getchar(void)
+static int test_getchar(void)
 {
   return 0x35;
 }
 
-void do_getchark(void)
+static void do_getchark(void)
 {
   int                                sc;
   BSP_polling_getchar_function_type  poll_char;
@@ -60,52 +53,49 @@ void do_getchark(void)
   BSP_poll_char = poll_char;
 }
 
-void do_putk(void)
+static void do_putk(void)
 {
   putk( "This is a test of putk" );
 }
 
-void do_printk(void)
+static void do_printk(void)
 {
   long lm = 2147483647L;
   unsigned long ulm = 4294967295UL;
   long long llm = 9223372036854775807LL;
   long long ullm = 18446744073709551615ULL;
 
-  printk( "bad format -- %%q in parentheses (%q)\n" );
+  printk( "bad format                   -- %%q in parentheses (%q)\n" );
 
-  printk( "bad format -- %%lq in parentheses (%lq)\n", 0x1234 );
+  printk( "bad format                   -- %%lq in parentheses (%lq)\n" );
 
-  printk( "%%O octal upper case 16 -- %O\n", 16 );
-  printk( "%%o octal lower case of 16 -- %O\n", 16 );
-  printk( "%%I of 16 -- %I\n", 16 );
-  printk( "%%i of 16 -- %i\n", 16 );
-  printk( "%%D of 16 -- %D\n", 16 );
-  printk( "%%d of 16 -- %d\n", 16 );
-  printk( "%%-3d of 16 -- %-3d\n", 16 );
-  printk( "%%U of 16 -- %U\n", 16 );
-  printk( "%%u of 16 -- %u\n", 16 );
-  printk( "%%X of 16 -- %X\n", 16 );
-  printk( "%%x of 16 -- %x\n", 16 );
-  printk( "%%p of 0x1234 -- %p\n", (void *)0x1234 );
+  printk( "%%o of 16                     -- %o\n", 16 );
+  printk( "%%i of 16                     -- %i\n", 16 );
+  printk( "%%d of 16                     -- %d\n", 16 );
+  printk( "'%%-3d' of 16                 -- '%-3d'\n", 16 );
+  printk( "'%%3d' of 16                  -- '%3d'\n", 16 );
+  printk( "%%u of 16                     -- %u\n", 16 );
+  printk( "%%X of 16                     -- %X\n", 16 );
+  printk( "%%x of 16                     -- %x\n", 16 );
+  printk( "%%p of 0x1234                 -- %p\n", (void *)0x1234 );
 
   /* long */
-  printk( "%%lo of 2147483647 -- %lo\n", lm );
-  printk( "%%li of 2147483647 -- %li\n", lm );
-  printk( "%%lu of 2147483647 -- %lu\n", lm );
-  printk( "%%lx of 2147483647 -- %lx\n", lm );
-  printk( "%%lo of -2147483648 -- %lo\n", -lm - 1L );
-  printk( "%%li of -2147483648 -- %li\n", -lm - 1L );
-  printk( "%%lx of -2147483648 -- %lx\n", -lm - 1L );
-  printk( "%%lo of 4294967295 -- %lo\n", ulm );
-  printk( "%%lu of 4294967295 -- %lu\n", ulm );
-  printk( "%%lx of 4294967295 -- %lx\n", ulm );
+  printk( "%%lo of 2147483647            -- %lo\n", lm );
+  printk( "%%li of 2147483647            -- %li\n", lm );
+  printk( "%%lu of 2147483647            -- %lu\n", lm );
+  printk( "%%lx of 2147483647            -- %lx\n", lm );
+  printk( "%%lo of -2147483648           -- %lo\n", -lm - 1L );
+  printk( "%%li of -2147483648           -- %li\n", -lm - 1L );
+  printk( "%%lx of -2147483648           -- %lx\n", -lm - 1L );
+  printk( "%%lo of 4294967295            -- %lo\n", ulm );
+  printk( "%%lu of 4294967295            -- %lu\n", ulm );
+  printk( "%%lx of 4294967295            -- %lx\n", ulm );
 
   /* long long */
-  printk( "%%llo of 9223372036854775807 -- %llo\n", llm );
-  printk( "%%lli of 9223372036854775807 -- %lli\n", llm );
-  printk( "%%llu of 9223372036854775807 -- %llu\n", llm );
-  printk( "%%llx of 9223372036854775807 -- %llx\n", llm );
+  printk( "%%llo of 9223372036854775807  -- %llo\n", llm );
+  printk( "%%lli of 9223372036854775807  -- %lli\n", llm );
+  printk( "%%llu of 9223372036854775807  -- %llu\n", llm );
+  printk( "%%llx of 9223372036854775807  -- %llx\n", llm );
   printk( "%%llo of -9223372036854775808 -- %llo\n", -llm - 1LL );
   printk( "%%lli of -9223372036854775808 -- %lli\n", -llm - 1LL );
   printk( "%%llx of -9223372036854775808 -- %llx\n", -llm - 1LL );
@@ -114,22 +104,90 @@ void do_printk(void)
   printk( "%%llx of 18446744073709551615 -- %llx\n", ullm );
 
   /* negative numbers */
-  printk( "%%d of -16 -- %d\n", -16 );
-  printk( "%%d of -16 -- %-3d\n", -16 );
-  printk( "%%u of -16 -- %u\n", -16 );
+  printk( "%%d of -16                    -- %d\n", -16 );
+  printk( "%%d of -16                    -- %-3d\n", -16 );
+  printk( "%%u of -16                    -- %u\n", -16 );
 
   /* string formats */
-  printk( "%%s of Mary Had a Little Lamb -- (%s)\n",
+  printk( "%%s of Mary Had a Little Lamb -- '%s'\n",
           "Mary Had a Little Lamb" );
-  printk( "%%s of NULL -- (%s)\n", NULL );
-  printk( "%%12s of joel -- (%20s)\n", "joel" );
-  printk( "%%4s of joel -- (%4s)\n", "joel" );
-  printk( "%%-12s of joel -- (%-20s)\n", "joel" );
-  printk( "%%-4s of joel -- (%-4s)\n", "joel" );
-  printk( "%%c of X -- (%c)\n", 'X' );
+  printk( "%%s of NULL                   -- '%s'\n", NULL );
+  printk( "%%12s of joel                 -- '%20s'\n", "joel" );
+  printk( "%%4s of joel                  -- '%4s'\n", "joel" );
+  printk( "%%-12s of joel                -- '%-20s'\n", "joel" );
+  printk( "%%-4s of joel                 -- '%-4s'\n", "joel" );
+  printk( "%%c of X                      -- '%c'\n", 'X' );
+  printk( "%%hhu of X                    -- %hhu\n", 'X' );
+}
+
+typedef struct {
+  char buf[128];
+  size_t i;
+} test_context;
+
+static test_context test_instance;
+
+static void clear( test_context *ctx )
+{
+  ctx->i = 0;
+  memset( ctx->buf, 0, sizeof( ctx->buf ) );
+}
+
+static void put_char( int c, void *arg )
+{
+  test_context *ctx;
+
+  ctx = arg;
+
+  if ( ctx->i < sizeof( ctx->buf ) ) {
+    ctx->buf[ ctx->i ] = (char) c;
+    ++ctx->i;
+  }
+}
+
+static test_context test_instance;
+
+static void test_io_printf( test_context *ctx )
+{
+  int i;
+  intmax_t j;
+  long long ll;
+  long l;
+  size_t z;
+  ptrdiff_t t;
+
+  clear( ctx );
+  i = 123;
+  _IO_Printf( put_char, ctx, "%i", i );
+  rtems_test_assert( strcmp( ctx->buf, "123" ) == 0 );
+
+  clear( ctx );
+  j = 456;
+  _IO_Printf( put_char, ctx, "%ji", j );
+  rtems_test_assert( strcmp( ctx->buf, "456" ) == 0 );
+
+  clear( ctx );
+  ll = 789;
+  _IO_Printf( put_char, ctx, "%lli", ll );
+  rtems_test_assert( strcmp( ctx->buf, "789" ) == 0 );
+
+  clear( ctx );
+  l = 101112;
+  _IO_Printf( put_char, ctx, "%li", l );
+  rtems_test_assert( strcmp( ctx->buf, "101112" ) == 0 );
+
+  clear( ctx );
+  z = 131415;
+  _IO_Printf( put_char, ctx, "%zi", z );
+  rtems_test_assert( strcmp( ctx->buf, "131415" ) == 0 );
+
+  clear( ctx );
+  t = 161718;
+  _IO_Printf( put_char, ctx, "%ti", t );
+  rtems_test_assert( strcmp( ctx->buf, "161718" ) == 0 );
 }
 
-rtems_task Init(
+static rtems_task Init(
   rtems_task_argument argument
 )
 {
@@ -142,6 +200,7 @@ rtems_task Init(
   putk("");
 
   do_getchark();
+  test_io_printf(&test_instance);
 
   TEST_END();
   rtems_test_exit( 0 );
diff --git a/testsuites/sptests/spprintk/spprintk.scn b/testsuites/sptests/spprintk/spprintk.scn
index 4b8130b75c..d537750472 100644
--- a/testsuites/sptests/spprintk/spprintk.scn
+++ b/testsuites/sptests/spprintk/spprintk.scn
@@ -1,51 +1,50 @@
-*** TEST PRINTK ***
+*** BEGIN OF TEST SPPRINTK ***
 This is a test of putk
 
-bad format -- %q in parentheses (q)
-bad format -- %lq in parentheses (q)
-%O octal upper case 16 -- 20
-%o octal lower case of 16 -- 20
-%I of 16 -- 16
-%i of 16 -- 16
-%D of 16 -- 16
-%d of 16 -- 16
-%-3d of 16 --  16
-%U of 16 -- 16
-%u of 16 -- 16
-%X of 16 -- 10
-%x of 16 -- 10
-%p of 0x1234 -- 1234
-%lo of 2147483647 -- 17777777777
-%li of 2147483647 -- 2147483647
-%lu of 2147483647 -- 2147483647
-%lx of 2147483647 -- 7FFFFFFF
-%lo of -2147483648 -- 20000000000
-%li of -2147483648 -- -2147483648
-%lx of -2147483648 -- 80000000
-%lo of 4294967295 -- 37777777777
-%lu of 4294967295 -- 4294967295
-%lx of 4294967295 -- FFFFFFFF
-%llo of 9223372036854775807 -- 777777777777777777777
-%lli of 9223372036854775807 -- 9223372036854775807
-%llu of 9223372036854775807 -- 9223372036854775807
-%llx of 9223372036854775807 -- 7FFFFFFFFFFFFFFF
+bad format                   -- %q in parentheses (%q)
+bad format                   -- %lq in parentheses (%lq)
+%o of 16                     -- 20
+%i of 16                     -- 16
+%d of 16                     -- 16
+'%-3d' of 16                 -- '16 '
+'%3d' of 16                  -- ' 16'
+%u of 16                     -- 16
+%X of 16                     -- 10
+%x of 16                     -- 10
+%p of 0x1234                 -- 0x1234
+%lo of 2147483647            -- 17777777777
+%li of 2147483647            -- 2147483647
+%lu of 2147483647            -- 2147483647
+%lx of 2147483647            -- 7fffffff
+%lo of -2147483648           -- 20000000000
+%li of -2147483648           -- -2147483648
+%lx of -2147483648           -- 80000000
+%lo of 4294967295            -- 37777777777
+%lu of 4294967295            -- 4294967295
+%lx of 4294967295            -- ffffffff
+%llo of 9223372036854775807  -- 777777777777777777777
+%lli of 9223372036854775807  -- 9223372036854775807
+%llu of 9223372036854775807  -- 9223372036854775807
+%llx of 9223372036854775807  -- 7fffffffffffffff
 %llo of -9223372036854775808 -- 1000000000000000000000
 %lli of -9223372036854775808 -- -9223372036854775808
 %llx of -9223372036854775808 -- 8000000000000000
 %llo of 18446744073709551615 -- 1777777777777777777777
 %llu of 18446744073709551615 -- 18446744073709551615
-%llx of 18446744073709551615 -- FFFFFFFFFFFFFFFF
-%d of -16 -- -16
-%d of -16 -- -16
-%u of -16 -- 4294967280
-%s of Mary Had a Little Lamb -- (Mary Had a Little Lamb)
-%s of NULL -- ()
-%12s of joel -- (                joel)
-%4s of joel -- (joel)
-%-12s of joel -- (joel                )
-%-4s of joel -- (joel)
-%c of X -- (X)
+%llx of 18446744073709551615 -- ffffffffffffffff
+%d of -16                    -- -16
+%d of -16                    -- -16
+%u of -16                    -- 4294967280
+%s of Mary Had a Little Lamb -- 'Mary Had a Little Lamb'
+%s of NULL                   -- '(null)'
+%12s of joel                 -- '                joel'
+%4s of joel                  -- 'joel'
+%-12s of joel                -- 'joel                '
+%-4s of joel                 -- 'joel'
+%c of X                      -- 'X'
+%hhu of X                    -- 88
 
 getchark - NULL getchar method - return -1
 getchark - test getchar method - returns 0x35
-*** END OF TEST PRINTK ***
+
+*** END OF TEST SPPRINTK ***
-- 
2.12.3



More information about the devel mailing list