// 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 __SHARC__
-#pragma nosharc
-#endif
-
#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,
}
}
-// Main function to format and print a string.
-#ifdef __DEPUTY__
-void printfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *fmt, ...);
-#else
void printfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...);
-#endif
-#ifdef __DEPUTY__
-void vprintfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *fmt, va_list ap)
-#else
void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
-#endif
{
- register const char *NTS p;
- const char *NTS last_fmt;
+ 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;
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]);
- break;
-
case 'E': // ENET MAC
if ((mac = va_arg(ap, uint8_t *)) == NULL){
char *s = "00:00:00:00:00:00";
base = 16;
goto number;
+ // qid
+ case 'Q':
+ printqid(putch, putdat, va_arg(ap, void*));
+ break;
number:
printnum(putch, putdat, num, base, width, padc);
break;
}
}
-#ifdef __DEPUTY__
-void printfmt(void (*putch)(int, TV(t)), TV(t) putdat, const char *fmt, ...)
-#else
void printfmt(void (*putch)(int, void**), void **putdat, const char *fmt, ...)
-#endif
{
va_list ap;
va_start(ap, fmt);
vprintfmt(putch, putdat, fmt, ap);
va_end(ap);
- check_poison("printfmt");
}
typedef struct sprintbuf {
- char *BND(__this,ebuf) buf;
- char *SNT ebuf;
+ char *buf;
+ char *ebuf;
int cnt;
} sprintbuf_t;
-static void sprintputch(int ch, sprintbuf_t *NONNULL *NONNULL b)
+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 *COUNT(1) NONNULL bp = &b;
-
- if (buf == NULL || n < 1)
- return -EINVAL;
+ sprintbuf_t *bp = &b;
+
+ /* 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;
- // print the string to the buffer
- #ifdef __DEPUTY__
- vprintfmt((void*)sprintputch, (sprintbuf_t *NONNULL*NONNULL)&bp, fmt, ap);
- #else
vprintfmt((void*)sprintputch, (void*)&bp, fmt, ap);
- #endif
// 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;
rc = vsnprintf(buf, n, fmt, ap);
va_end(ap);
- check_poison("snprintf");
return rc;
}
-/* convenience function: do a print, return the pointer to the end. */
+/* 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;
- int n = end - buf;
-
- if (n <= 0)
- return buf;
+ size_t n = end - buf;
va_start(ap, fmt);
rc = vsnprintf(buf, n, fmt, ap);
va_end(ap);
- check_poison("seprintf");
- if (rc >= 0)
- return buf + rc;
- else
+ /* 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;
}