--- err.c.orig 2009-05-12 11:21:55.000000000 -0700 +++ err.c 2009-05-23 13:27:52.000000000 -0700 @@ -44,12 +44,105 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/err #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <vis.h> #include "un-namespace.h" +#ifdef __BLOCKS__ +#include <Block.h> +#endif /* __BLOCKS__ */ #include "libc_private.h" -static FILE *err_file; /* file to use for error output */ -static void (*err_exit)(int); +#define ERR_EXIT_UNDEF 0 +#ifdef __BLOCKS__ +#define ERR_EXIT_BLOCK 1 +#endif /* __BLOCKS__ */ +#define ERR_EXIT_FUNC 2 +struct _e_err_exit { + unsigned int type; +#ifdef __BLOCKS__ + union { +#endif /* __BLOCKS__ */ + void (*func)(int); +#ifdef __BLOCKS__ + void (^block)(int); + }; +#endif /* __BLOCKS__ */ +}; + +#ifdef BUILDING_VARIANT + +__private_extern__ FILE *_e_err_file; /* file to use for error output */ +__private_extern__ struct _e_err_exit _e_err_exit; +__private_extern__ void _e_visprintf(FILE * __restrict, const char * __restrict, va_list); + +#else /* !BUILDING_VARIANT */ + +__private_extern__ FILE *_e_err_file = NULL; /* file to use for error output */ +__private_extern__ struct _e_err_exit _e_err_exit = {ERR_EXIT_UNDEF}; + +/* + * zero means pass as is + * 255 means use \nnn (octal) + * otherwise use \x (x is value) + * (NUL isn't used) + */ +static unsigned char escape[256] = { + /* NUL SOH STX ETX EOT ENQ ACK BEL */ + 0 , 255, 255, 255, 255, 255, 255, 'a', + /* BS HT NL VT NP CR SO SI */ + 'b', 't', 'n', 'v', 'f', 'r', 255, 255, + /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + 255, 255, 255, 255, 255, 255, 255, 255, + /* CAN EM SUB ESC FS GS RS US */ + 255, 255, 255, 255, 255, 255, 255, 255, + /* the rest are zero */ +}; + +/* + * Make characters visible. If we can't allocate enough + * memory, we fall back on vfprintf(). + */ +__private_extern__ void +_e_visprintf(FILE * __restrict stream, const char * __restrict format, va_list ap) +{ + int failed = 0; + char *str, *visstr; + va_list backup; + + va_copy(backup, ap); + vasprintf(&str, format, ap); + if (str != NULL) { + if ((visstr = malloc(4 * strlen(str) + 1)) != NULL) { + unsigned char *fp = (unsigned char *)str; + unsigned char *tp = (unsigned char *)visstr; + while(*fp) { + switch(escape[*fp]) { + case 0: + *tp++ = *fp; + break; + case 255: + sprintf(tp, "\\%03o", *fp); + tp += 4; + break; + default: + *tp++ = '\\'; + *tp++ = escape[*fp]; + break; + } + fp++; + } + *tp = 0; + fputs(visstr, stream); + free(visstr); + } else + failed = 1; + free(str); + } else + failed = 1; + if (failed) + vfprintf(stream, format, backup); + va_end(backup); +} /* * This is declared to take a `void *' so that the caller is not required @@ -60,16 +153,27 @@ void err_set_file(void *fp) { if (fp) - err_file = fp; + _e_err_file = fp; else - err_file = stderr; + _e_err_file = stderr; } void err_set_exit(void (*ef)(int)) { - err_exit = ef; + _e_err_exit.type = ERR_EXIT_FUNC; + _e_err_exit.func = ef; +} + +#ifdef __BLOCKS__ +void +err_set_exit_b(void (^ef)(int)) +{ + _e_err_exit.type = ERR_EXIT_BLOCK; + _e_err_exit.block = Block_copy(ef); } +#endif /* __BLOCKS__ */ +#endif /* !BUILDING_VARIANT */ __weak_reference(_err, err); @@ -107,16 +211,21 @@ verrc(eval, code, fmt, ap) const char *fmt; va_list ap; { - if (err_file == 0) + if (_e_err_file == 0) err_set_file((FILE *)0); - fprintf(err_file, "%s: ", _getprogname()); + fprintf(_e_err_file, "%s: ", _getprogname()); if (fmt != NULL) { - vfprintf(err_file, fmt, ap); - fprintf(err_file, ": "); + _e_visprintf(_e_err_file, fmt, ap); + fprintf(_e_err_file, ": "); } - fprintf(err_file, "%s\n", strerror(code)); - if (err_exit) - err_exit(eval); + fprintf(_e_err_file, "%s\n", strerror(code)); + if (_e_err_exit.type) +#ifdef __BLOCKS__ + if (_e_err_exit.type == ERR_EXIT_BLOCK) + _e_err_exit.block(eval); + else +#endif /* __BLOCKS__ */ + _e_err_exit.func(eval); exit(eval); } @@ -135,14 +244,19 @@ verrx(eval, fmt, ap) const char *fmt; va_list ap; { - if (err_file == 0) + if (_e_err_file == 0) err_set_file((FILE *)0); - fprintf(err_file, "%s: ", _getprogname()); + fprintf(_e_err_file, "%s: ", _getprogname()); if (fmt != NULL) - vfprintf(err_file, fmt, ap); - fprintf(err_file, "\n"); - if (err_exit) - err_exit(eval); + _e_visprintf(_e_err_file, fmt, ap); + fprintf(_e_err_file, "\n"); + if (_e_err_exit.type) +#ifdef __BLOCKS__ + if (_e_err_exit.type == ERR_EXIT_BLOCK) + _e_err_exit.block(eval); + else +#endif /* __BLOCKS__ */ + _e_err_exit.func(eval); exit(eval); } @@ -180,14 +294,14 @@ vwarnc(code, fmt, ap) const char *fmt; va_list ap; { - if (err_file == 0) + if (_e_err_file == 0) err_set_file((FILE *)0); - fprintf(err_file, "%s: ", _getprogname()); + fprintf(_e_err_file, "%s: ", _getprogname()); if (fmt != NULL) { - vfprintf(err_file, fmt, ap); - fprintf(err_file, ": "); + _e_visprintf(_e_err_file, fmt, ap); + fprintf(_e_err_file, ": "); } - fprintf(err_file, "%s\n", strerror(code)); + fprintf(_e_err_file, "%s\n", strerror(code)); } void @@ -204,10 +318,10 @@ vwarnx(fmt, ap) const char *fmt; va_list ap; { - if (err_file == 0) + if (_e_err_file == 0) err_set_file((FILE *)0); - fprintf(err_file, "%s: ", _getprogname()); + fprintf(_e_err_file, "%s: ", _getprogname()); if (fmt != NULL) - vfprintf(err_file, fmt, ap); - fprintf(err_file, "\n"); + _e_visprintf(_e_err_file, fmt, ap); + fprintf(_e_err_file, "\n"); }