summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Tkac <atkac@redhat.com>2008-12-03 14:13:36 +0000
committerAdam Tkac <atkac@redhat.com>2008-12-03 14:13:36 +0000
commit241e9009710f205fb95273a9bed9684285a2ef0d (patch)
tree087a595ebd923bdf23968012e4ca105a067e24f0
parent8ace9157de31f768504d8b80ab49adcc88b25329 (diff)
downloadtigervnc-241e9009710f205fb95273a9bed9684285a2ef0d.tar.gz
tigervnc-241e9009710f205fb95273a9bed9684285a2ef0d.zip
[Portability] Reimplement vsnprintf to be C89 compatible
Main problem is that C89 doesn't have va_copy macro thus you can't parse va_list twice. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3289 3789f03b-4d11-0410-bbf8-ca57d06f2519
-rw-r--r--common/os/print.c75
-rw-r--r--common/os/print.h11
2 files changed, 64 insertions, 22 deletions
diff --git a/common/os/print.c b/common/os/print.c
index a38ea2fe..f24717fb 100644
--- a/common/os/print.c
+++ b/common/os/print.c
@@ -21,38 +21,71 @@
#endif
#include <os/print.h>
+
#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
#ifndef HAVE_VSNPRINTF
-int vsnprintf(char *str, size_t n, const char *format, va_list ap) {
- static FILE *fp = NULL;
- va_list ap_new;
- int len, written;
+size_t internal_memcpy(char *dest, const char *src, size_t destsize,
+ size_t srcsize) {
+ size_t copied;
- if (n < 1)
- return 0;
+ copied = ((destsize) < (srcsize)) ? (destsize) : (srcsize);
+ memcpy(dest, src, copied);
- str[0] = '\0';
- if (fp == NULL) {
- fp = fopen("/dev/null","w");
- if (fp == NULL)
- return 0;
- }
+ return copied;
+}
- va_copy(ap_new, ap);
- len = vfprintf(fp, format, ap_new);
- va_end(ap_new);
+int tight_vsnprintf(char *str, size_t n, const char *format, va_list ap) {
+ int written = 0;
+ int tmpint, len;
+ char buf[64]; /* Is it enough? */
+ char *tmpstr;
- if (len <= 0)
+ if (format == NULL || n < 1)
return 0;
- CharArray s(len+1);
- vsprintf(s.buf, format, ap);
+ while (*format != '\0' && written < n - 1) {
+ if (*format != '%') {
+ if (written < n) {
+ str[written++] = *format++;
+ continue;
+ } else
+ break;
+ }
+
+ format++;
+ switch (*format) {
+ case '\0':
+ str[written++] = '%';
+ continue;
+ case 'd':
+ tmpint = va_arg(ap, int);
+ sprintf(buf, "%d", tmpint);
+ len = strlen(buf);
+ written += internal_memcpy (&str[written], buf,
+ len, n - written);
+ break;
+ case 's':
+ tmpstr = va_arg(ap, char *);
+ len = strlen(tmpstr);
+ written += internal_memcpy (&str[written],
+ tmpstr, len,
+ n - written);
+ break;
+ /* Catch unimplemented stuff */
+ default:
+ fprintf(stderr, "Unimplemented format: %c\n",
+ *format);
+ abort();
+ }
+ format++;
+ }
- written = (len < (n - 1)) ? len : (n - 1);
- memcpy(str, s.buf, written);
str[written] = '\0';
- return len;
+
+ return written;
}
#endif /* HAVE_VSNPRINTF */
diff --git a/common/os/print.h b/common/os/print.h
index ea550411..47893adf 100644
--- a/common/os/print.h
+++ b/common/os/print.h
@@ -36,7 +36,16 @@ extern "C" {
#endif
#ifndef HAVE_VSNPRINTF
-int vsnprintf(char *str, size_t n, const char *format, va_list ap);
+/* NOTE:
+ *
+ * This is only very limited implementation for our internal purposes. It
+ * doesn't conform to C99/POSIX
+ * - limited conversion specifiers
+ * - returns written number of characters instead of number what would be
+ * written
+ */
+int tight_vsnprintf(char *str, size_t n, const char *format, va_list ap);
+#define vsnprintf tight_vsnprintf
#endif
#ifdef __cplusplus