// Stripped-down primitive printf-style formatting routines,
// used in common by printf, sprintf, fprintf, etc.
// This code is also used by both the kernel and user programs.
-
-#ifdef __DEPUTY__
-#pragma nodeputy
-#endif
-
-#include <arch/types.h>
-#include <ros/error.h>
+#include <ros/common.h>
+#include <error.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <kthread.h>
+#include <syscall.h>
+#include <ns.h>
-/*
- * Print a number (base <= 16) in reverse order,
- * using specified putch function and associated pointer putdat.
- */
+/* Print a number (base <= 16) in reverse order,
+ * using specified putch function and associated pointer putdat. */
void printnum(void (*putch)(int, void**), void **putdat,
- unsigned long long num, unsigned base, int width, int padc)
+ unsigned long long num, unsigned base, int width, int padc)
{
- // first recursively print all preceding (more significant) digits
- if (num >= base) {
- printnum(putch, putdat, num / base, base, width - 1, padc);
- } else {
- // print any needed pad characters before first digit
- while (--width > 0)
- putch(padc, putdat);
+ unsigned long long temp = num;
+ int nr_digits = 1;
+ /* Determine how many leading zeros we need.
+ * For every digit/nibble beyond base, we do one less width padding */
+ while ((temp /= base)) {
+ nr_digits++;
+ width--;
+ }
+ /* And another one less, since we'll always print the last digit */
+ while (--width > 0)
+ putch(padc, putdat);
+ for (int i = nr_digits; i > 0; i--) {
+ temp = num;
+ /* To get digit i, we only div (i-1) times */
+ for (int j = 0; j < i - 1; j++) {
+ temp /= base;
+ }
+ putch("0123456789abcdef"[temp % base], putdat);
}
-
- // then print this (the least significant) digit
- putch("0123456789abcdef"[num % base], putdat);
-}
-
-// Get an unsigned int of various possible sizes from a varargs list,
-// depending on the lflag parameter.
-static unsigned long long getuint(va_list *ap, int lflag)
-{
- if (lflag >= 2)
- return va_arg(*ap, unsigned long long);
- else if (lflag)
- return va_arg(*ap, unsigned long);
- else
- return va_arg(*ap, unsigned int);
-}
-
-// Same as getuint but signed - can't use getuint
-// because of sign extension
-static long long getint(va_list *ap, int lflag)
-{
- if (lflag >= 2)
- return va_arg(*ap, long long);
- else if (lflag)
- return va_arg(*ap, long);
- else
- return va_arg(*ap, int);
}
-
-// Main function to format and print a string.
void printfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...);
void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
{
register const char *p;
+ const char *last_fmt;
register int ch, err;
unsigned long long num;
int base, lflag, width, precision, altflag;
char padc;
+ uint8_t *mac, *ip, *mask;
+ struct Gas *g;
+ int i;
+ uint32_t *lp;
while (1) {
- while ((ch = *(unsigned char *) fmt++) != '%') {
+ while ((ch = *(unsigned char *) fmt) != '%') {
if (ch == '\0')
return;
+ fmt++;
putch(ch, putdat);
}
+ fmt++;
// Process a %-escape sequence
+ last_fmt = fmt;
padc = ' ';
width = -1;
precision = -1;
case '-':
padc = '-';
goto reswitch;
-
+
// flag to pad with 0's instead of spaces
case '0':
padc = '0';
lflag++;
goto reswitch;
+ // chan
+ case 'C':
+ printchan(putch, putdat, va_arg(ap, void*));
+ break;
+
// character
case 'c':
putch(va_arg(ap, int), putdat);
break;
- // error message
- case 'e':
- err = va_arg(ap, int);
- if (err < 0)
- err = -err;
- if (err >= NUMERRORS)
- printfmt(putch, putdat, "error %d", err);
- else
- printfmt(putch, putdat, "%s", error_string[err]);
+ case 'E': // ENET MAC
+ if ((mac = va_arg(ap, uint8_t *)) == NULL){
+ char *s = "00:00:00:00:00:00";
+ while(*s)
+ putch(*s++, putdat);
+ }
+ printemac(putch, putdat, mac);
+ break;
+ case 'i':
+ /* what to do if they screw up? */
+ if ((lp = va_arg(ap, uint32_t *)) != NULL){
+ uint32_t hostfmt;
+ for(i = 0; i < 4; i++){
+ hnputl(&hostfmt, lp[i]);
+ printfmt(putch, putdat, "%08lx", hostfmt);
+ }
+ }
+ break;
+ case 'I':
+ /* what to do if they screw up? */
+ if ((ip = va_arg(ap, uint8_t *)) != NULL)
+ printip(putch, putdat, ip);
+ break;
+ case 'M':
+ /* what to do if they screw up? */
+ if ((mask = va_arg(ap, uint8_t *)) != NULL)
+ printipmask(putch, putdat, mask);
+ break;
+ case 'V':
+ /* what to do if they screw up? */
+ if ((ip = va_arg(ap, uint8_t *)) != NULL)
+ printipv4(putch, putdat, ip);
break;
// string
if (width > 0 && padc != '-')
for (width -= strnlen(p, precision); width > 0; width--)
putch(padc, putdat);
- for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--)
+ for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) {
if (altflag && (ch < ' ' || ch > '~'))
putch('?', putdat);
else
putch(ch, putdat);
+ // zra: make sure *p isn't '\0' before inc'ing
+ p++;
+ }
for (; width > 0; width--)
putch(' ', putdat);
break;
- // (signed) decimal
- case 'd':
- num = getint(&ap, lflag);
+ case 'd': /* (signed) decimal */
+ if (lflag >= 2)
+ num = va_arg(ap, long long);
+ else if (lflag)
+ num = va_arg(ap, long);
+ else
+ num = va_arg(ap, int);
if ((long long) num < 0) {
putch('-', putdat);
num = -(long long) num;
base = 10;
goto number;
- // unsigned decimal
- case 'u':
- num = getuint(&ap, lflag);
- base = 10;
- goto number;
-
- // (unsigned) octal
- case 'o':
- // should do something with padding so it's always 3 octits
- num = getuint(&ap, lflag);
- base = 8;
+ case 'u': /* unsigned decimal */
+ case 'o': /* (unsigned) octal */
+ case 'x': /* (unsigned) hexadecimal */
+ if (lflag >= 2)
+ num = va_arg(ap, unsigned long long);
+ else if (lflag)
+ num = va_arg(ap, unsigned long);
+ else
+ num = va_arg(ap, unsigned int);
+ if (ch == 'u')
+ base = 10;
+ else if (ch == 'o')
+ base = 8;
+ else /* x */
+ base = 16;
goto number;
// pointer
case 'p':
putch('0', putdat);
putch('x', putdat);
+ /* automatically zero-pad pointers, out to the length of a ptr */
+ padc = '0';
+ width = sizeof(void*) * 2; /* 8 bits per byte / 4 bits per char */
num = (unsigned long long)
(uintptr_t) va_arg(ap, void *);
base = 16;
goto number;
- // (unsigned) hexadecimal
- case 'x':
- num = getuint(&ap, lflag);
- base = 16;
+ // qid
+ case 'Q':
+ printqid(putch, putdat, va_arg(ap, void*));
+ break;
number:
printnum(putch, putdat, num, base, width, padc);
break;
case '%':
putch(ch, putdat);
break;
-
+
// unrecognized escape sequence - just print it literally
default:
putch('%', putdat);
- for (fmt--; fmt[-1] != '%'; fmt--)
+ fmt = last_fmt;
+ //for (fmt--; fmt[-1] != '%'; fmt--)
/* do nothing */;
break;
}
static void sprintputch(int ch, sprintbuf_t **b)
{
- (*b)->cnt++;
if ((*b)->buf < (*b)->ebuf)
*((*b)->buf++) = ch;
+ (*b)->cnt++;
}
-int vsnprintf(char *buf, int n, const char *fmt, va_list ap)
+int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap)
{
- sprintbuf_t b = {buf, buf+n-1, 0};
+ sprintbuf_t b;// = {buf, buf+n-1, 0};
sprintbuf_t *bp = &b;
- if (buf == NULL || n < 1)
- return -EINVAL;
-
- // print the string to the buffer
- vprintfmt((void*)sprintputch, (void**)&bp, fmt, ap);
+ /* this isn't quite the snprintf 'spec', but errors aren't helpful */
+ assert(buf);
+ /* We might get large, 'negative' values for code that repeatedly calls
+ * snprintf(), e.g.:
+ * len += snprintf(buf + len, bufsz - len, "foo");
+ * len += snprintf(buf + len, bufsz - len, "bar");
+ * If len > bufsz, that will appear as a large value. This is not quite the
+ * glibc semantics (we aren't returning the size we would have printed), but
+ * it short circuits the rest of the function and avoids potential errors in
+ * the putch() functions. */
+ if (!n || (n > INT32_MAX))
+ return 0;
+
+ b.buf = NULL; // zra : help out the Deputy optimizer a bit
+ b.ebuf = buf+n-1;
+ b.cnt = 0;
+ b.buf = buf;
+
+ vprintfmt((void*)sprintputch, (void*)&bp, fmt, ap);
// null terminate the buffer
*b.buf = '\0';
return b.cnt;
}
-int snprintf(char *buf, int n, const char *fmt, ...)
+int snprintf(char *buf, size_t n, const char *fmt, ...)
{
va_list ap;
int rc;
return rc;
}
+/* Convenience function: do a print, return the pointer to the null at the end.
+ *
+ * Unlike snprintf(), when we overflow, this doesn't return the 'end' where we
+ * would have written to. Instead, we'll return 'end - 1', which is the last
+ * byte, and enforce the null-termination. */
+char *seprintf(char *buf, char *end, const char *fmt, ...)
+{
+ va_list ap;
+ int rc;
+ size_t n = end - buf;
+ va_start(ap, fmt);
+ rc = vsnprintf(buf, n, fmt, ap);
+ va_end(ap);
+
+ /* Some error - leave them where they were. */
+ if (rc < 0)
+ return buf;
+ /* Overflow - put them at the end */
+ if (rc >= n) {
+ *(end - 1) = '\0';
+ return end - 1;
+ }
+ assert(buf[rc] == '\0');
+ return buf + rc;
+}