summaryrefslogtreecommitdiff
path: root/src/xprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xprintf.c')
-rw-r--r--src/xprintf.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/xprintf.c b/src/xprintf.c
new file mode 100644
index 0000000..8fbfab6
--- /dev/null
+++ b/src/xprintf.c
@@ -0,0 +1,217 @@
+/*
+ * extended printf functions and specifiers
+ *
+ * Copyright (C) 2010 by James Maki
+ *
+ * Author: James Maki <jmaki@multitech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <alloca.h>
+#include "xprintf.h"
+
+#include "log.h"
+
+#if HAVE_REGISTER_PRINTF_SPECIFIER
+int print_buffer_inspect_arginfo(const struct printf_info *info, size_t n, int *argtypes, int *size)
+#else
+int print_buffer_inspect_arginfo(const struct printf_info *info, size_t n, int *argtypes)
+#endif
+{
+ if (n > 0) {
+ argtypes[0] = PA_POINTER;
+#if HAVE_REGISTER_PRINTF_SPECIFIER
+ size[0] = sizeof(void *);
+#endif
+ }
+ return 1;
+}
+
+static const char *__char_inspect[] = {
+ "\\x00", "\\x01", "\\x02", "\\x03",
+ "\\x04", "\\x05", "\\x06", "\\a",
+ "\\b", "\\t", "\\n", "\\v",
+ "\\f", "\\r", "\\x0E", "\\x0F",
+ "\\x10", "\\x11", "\\x12", "\\x13",
+ "\\x14", "\\x15", "\\x16", "\\x17",
+ "\\x18", "\\x19", "\\x1A", "\\x1B",
+ "\\x1C", "\\x1D", "\\x1E", "\\x1F",
+ " ", "!", "\\\"", "#",
+ "$", "%", "&", "'",
+ "(", ")", "*", "+",
+ ",", "-", ".", "/",
+ "0", "1", "2", "3",
+ "4", "5", "6", "7",
+ "8", "9", ":", ";",
+ "<", "=", ">", "?",
+ "@", "A", "B", "C",
+ "D", "E", "F", "G",
+ "H", "I", "J", "K",
+ "L", "M", "N", "O",
+ "P", "Q", "R", "S",
+ "T", "U", "V", "W",
+ "X", "Y", "Z", "[",
+ "\\\\", "]", "^", "_",
+ "`", "a", "b", "c",
+ "d", "e", "f", "g",
+ "h", "i", "j", "k",
+ "l", "m", "n", "o",
+ "p", "q", "r", "s",
+ "t", "u", "v", "w",
+ "x", "y", "z", "{",
+ "|", "}", "~", "\\x7F",
+ "\\x80", "\\x81", "\\x82", "\\x83",
+ "\\x84", "\\x85", "\\x86", "\\x87",
+ "\\x88", "\\x89", "\\x8A", "\\x8B",
+ "\\x8C", "\\x8D", "\\x8E", "\\x8F",
+ "\\x90", "\\x91", "\\x92", "\\x93",
+ "\\x94", "\\x95", "\\x96", "\\x97",
+ "\\x98", "\\x99", "\\x9A", "\\x9B",
+ "\\x9C", "\\x9D", "\\x9E", "\\x9F",
+ "\\xA0", "\\xA1", "\\xA2", "\\xA3",
+ "\\xA4", "\\xA5", "\\xA6", "\\xA7",
+ "\\xA8", "\\xA9", "\\xAA", "\\xAB",
+ "\\xAC", "\\xAD", "\\xAE", "\\xAF",
+ "\\xB0", "\\xB1", "\\xB2", "\\xB3",
+ "\\xB4", "\\xB5", "\\xB6", "\\xB7",
+ "\\xB8", "\\xB9", "\\xBA", "\\xBB",
+ "\\xBC", "\\xBD", "\\xBE", "\\xBF",
+ "\\xC0", "\\xC1", "\\xC2", "\\xC3",
+ "\\xC4", "\\xC5", "\\xC6", "\\xC7",
+ "\\xC8", "\\xC9", "\\xCA", "\\xCB",
+ "\\xCC", "\\xCD", "\\xCE", "\\xCF",
+ "\\xD0", "\\xD1", "\\xD2", "\\xD3",
+ "\\xD4", "\\xD5", "\\xD6", "\\xD7",
+ "\\xD8", "\\xD9", "\\xDA", "\\xDB",
+ "\\xDC", "\\xDD", "\\xDE", "\\xDF",
+ "\\xE0", "\\xE1", "\\xE2", "\\xE3",
+ "\\xE4", "\\xE5", "\\xE6", "\\xE7",
+ "\\xE8", "\\xE9", "\\xEA", "\\xEB",
+ "\\xEC", "\\xED", "\\xEE", "\\xEF",
+ "\\xF0", "\\xF1", "\\xF2", "\\xF3",
+ "\\xF4", "\\xF5", "\\xF6", "\\xF7",
+ "\\xF8", "\\xF9", "\\xFA", "\\xFB",
+ "\\xFC", "\\xFD", "\\xFE", "\\xFF",
+};
+
+int print_buffer_inspect(FILE *stream, const struct printf_info *info, const void *const *args)
+{
+ int i;
+ int total;
+ char *arg;
+ char *buf;
+ int prec = info->prec;
+
+ arg = (char *) *((const char **) (args[0]));
+
+ if (prec < 0) {
+ prec = strlen(arg);
+ }
+
+ total = 0;
+ for (i = 0; i < prec; i++) {
+ total += strlen(__char_inspect[((unsigned char *) arg)[i]]);
+ }
+
+ buf = alloca(total + 1);
+ if (!buf) {
+ return -1;
+ }
+
+ *buf = '\0';
+ for (i = 0; i < prec; i++) {
+ strcat(buf, __char_inspect[((unsigned char *) arg)[i]]);
+ }
+
+ total = fprintf(stream, "%*s", (info->left ? -info->width : info->width), buf);
+
+ return total;
+}
+
+#if HAVE_REGISTER_PRINTF_SPECIFIER
+int print_buffer_bin_arginfo(const struct printf_info *info, size_t n, int *argtypes, int *size)
+#else
+int print_buffer_bin_arginfo(const struct printf_info *info, size_t n, int *argtypes)
+#endif
+{
+ if (n > 0) {
+ argtypes[0] = PA_POINTER;
+#if HAVE_REGISTER_PRINTF_SPECIFIER
+ size[0] = sizeof(void *);
+#endif
+ }
+ return 1;
+}
+
+int print_buffer_bin(FILE *stream, const struct printf_info *info, const void *const *args)
+{
+ int i;
+ int j;
+ int total;
+ char *arg;
+ unsigned char c;
+ int prec = info->prec;
+ char *buf;
+
+ arg = (char *) *((const char **) (args[0]));
+
+ if (prec < 0) {
+ prec = strlen(arg);
+ }
+
+ buf = alloca(prec * 8 + 1);
+ if (!buf) {
+ return -1;
+ }
+
+ total = 0;
+ for (i = 0; i < prec; i++) {
+ c = ((unsigned char *) arg)[i];
+ for (j = 7; j >= 0; j--) {
+ buf[total++] = (c & (1 << j)) ? '1' : '0';
+ }
+ }
+ if (total) {
+ buf[total] = '\0';
+ }
+
+ total = fprintf(stream, "%*s", (info->left ? -info->width : info->width), buf);
+
+ return total;
+}
+
+int xprintf_init()
+{
+#if HAVE_REGISTER_PRINTF_SPECIFIER
+ register_printf_specifier(XPRINTF_INSPECT_SPEC, print_buffer_inspect,
+ print_buffer_inspect_arginfo);
+ register_printf_specifier(XPRINTF_BIN_SPEC, print_buffer_bin,
+ print_buffer_bin_arginfo);
+#else
+ register_printf_function(XPRINTF_INSPECT_SPEC, print_buffer_inspect,
+ print_buffer_inspect_arginfo);
+ register_printf_function(XPRINTF_BIN_SPEC, print_buffer_bin,
+ print_buffer_bin_arginfo);
+#endif
+
+ return 0;
+}