fallback: remove fwprintf and friends fallbacks

All modern operating systems implement fwprintf, including NetBSD (which
introduced them in 2005).

Work on #2999.
This commit is contained in:
David Adam 2016-05-15 22:08:43 +00:00
parent d0aa461587
commit 44757c81af
3 changed files with 1 additions and 444 deletions

View file

@ -310,7 +310,7 @@ AC_STRUCT_DIRENT_D_TYPE
# Check for presense of various functions used by fish
#
AC_CHECK_FUNCS( wcsdup wcsndup wcslen wcscasecmp wcsncasecmp fwprintf )
AC_CHECK_FUNCS( wcsdup wcsndup wcslen wcscasecmp wcsncasecmp )
AC_CHECK_FUNCS( futimes wcwidth wcswidth wcstok fputwc fgetwc )
AC_CHECK_FUNCS( wcstol wcslcat wcslcpy lrand48_r killpg )
AC_CHECK_FUNCS( backtrace backtrace_symbols_fd getifaddrs )

View file

@ -90,417 +90,6 @@ char *tparm_solaris_kludge(char *str, ...) {
#endif
#ifndef HAVE_FWPRINTF
#define INTERNAL_FWPRINTF 1
#endif
#ifdef INTERNAL_FWPRINTF
/// Internal function for the wprintf fallbacks. USed to write the specified number of spaces.
static void pad(void (*writer)(wchar_t), int count) {
int i;
if (count < 0) return;
for (i = 0; i < count; i++) {
writer(L' ');
}
}
/// Generic formatting function. All other string formatting functions are secretly a wrapper around
/// this function. vgprintf does not implement all the filters supported by printf, only those that
/// are currently used by fish. vgprintf internally uses snprintf to implement the number outputs,
/// such as %f and %x.
///
/// Currently supported functionality:
///
/// - precision specification, both through .* and .N
/// - Padding through * and N
/// - Right padding using the - prefix
/// - long versions of all filters thorugh l and ll prefix
/// - Character output using %c
/// - String output through %s
/// - Floating point number output through %f
/// - Integer output through %d, %i, %u, %o, %x and %X
///
/// For a full description on the usage of *printf, see use 'man 3 printf'.
static int vgwprintf(void (*writer)(wchar_t), const wchar_t *filter, va_list va) {
const wchar_t *filter_org = filter;
int count = 0;
for (; *filter; filter++) {
if (*filter == L'%') {
int is_long = 0;
int width = -1;
filter++;
int loop = 1;
int precision = -1;
int pad_left = 1;
if (iswdigit(*filter)) {
width = 0;
while ((*filter >= L'0') && (*filter <= L'9')) {
width = 10 * width + (*filter++ - L'0');
}
}
while (loop) {
switch (*filter) {
case L'l': {
// Long variable.
is_long++;
filter++;
break;
}
case L'*': {
// Set minimum field width.
width = va_arg(va, int);
filter++;
break;
}
case L'-': {
filter++;
pad_left = 0;
break;
}
case L'.': {
// Set precision.
filter++;
if (*filter == L'*') {
precision = va_arg(va, int);
} else {
precision = 0;
while ((*filter >= L'0') && (*filter <= L'9')) {
precision = 10 * precision + (*filter++ - L'0');
}
}
break;
}
default: {
loop = 0;
break;
}
}
}
switch (*filter) {
case L'c': {
wchar_t c;
if ((width >= 0) && pad_left) {
pad(writer, width - 1);
count += maxi(width - 1, 0);
}
c = is_long ? va_arg(va, wint_t) : btowc(va_arg(va, int));
if (precision != 0) writer(c);
if ((width >= 0) && !pad_left) {
pad(writer, width - 1);
count += maxi(width - 1, 0);
}
count++;
break;
}
case L's': {
wchar_t *ss = 0;
wcstring wide_ss;
if (is_long) {
ss = va_arg(va, wchar_t *);
} else {
char *ns = va_arg(va, char *);
if (ns) {
wide_ss = str2wcstring(ns);
ss = wide_ss.c_str();
}
}
if (!ss) {
return -1;
}
if ((width >= 0) && pad_left) {
pad(writer, width - wcslen(ss));
count += maxi(width - wcslen(ss), 0);
}
wchar_t *s = ss;
int precount = count;
while (*s) {
if ((precision > 0) && (precision <= (count - precount))) break;
writer(*(s++));
count++;
}
if ((width >= 0) && !pad_left) {
pad(writer, width - wcslen(ss));
count += maxi(width - wcslen(ss), 0);
}
break;
}
case L'd':
case L'i':
case L'o':
case L'u':
case L'x':
case L'X': {
char str[33];
char *pos;
char format[16];
int len;
format[0] = 0;
strcat(format, "%");
if (precision >= 0) strcat(format, ".*");
switch (is_long) {
case 2: {
strcat(format, "ll");
break;
}
case 1: {
strcat(format, "l");
break;
}
}
len = strlen(format);
format[len++] = (char)*filter;
format[len] = 0;
switch (*filter) {
case L'd':
case L'i': {
switch (is_long) {
case 0: {
int d = va_arg(va, int);
if (precision >= 0)
snprintf(str, 32, format, precision, d);
else
snprintf(str, 32, format, d);
break;
}
case 1: {
long d = va_arg(va, long);
if (precision >= 0)
snprintf(str, 32, format, precision, d);
else
snprintf(str, 32, format, d);
break;
}
case 2: {
long long d = va_arg(va, long long);
if (precision >= 0)
snprintf(str, 32, format, precision, d);
else
snprintf(str, 32, format, d);
break;
}
default: {
debug(0, L"Invalid length modifier in string %ls\n",
filter_org);
return -1;
}
}
break;
}
case L'u':
case L'o':
case L'x':
case L'X': {
switch (is_long) {
case 0: {
unsigned d = va_arg(va, unsigned);
if (precision >= 0)
snprintf(str, 32, format, precision, d);
else
snprintf(str, 32, format, d);
break;
}
case 1: {
unsigned long d = va_arg(va, unsigned long);
if (precision >= 0)
snprintf(str, 32, format, precision, d);
else
snprintf(str, 32, format, d);
break;
}
case 2: {
unsigned long long d = va_arg(va, unsigned long long);
if (precision >= 0)
snprintf(str, 32, format, precision, d);
else
snprintf(str, 32, format, d);
break;
}
default: {
debug(0, L"Invalid length modifier in string %ls\n",
filter_org);
return -1;
}
}
break;
}
default: {
debug(0, L"Invalid filter %ls in string %ls\n", *filter, filter_org);
return -1;
}
}
if ((width >= 0) && pad_left) {
int l = maxi(width - strlen(str), 0);
pad(writer, l);
count += l;
}
pos = str;
while (*pos) {
writer(*(pos++));
count++;
}
if ((width >= 0) && !pad_left) {
int l = maxi(width - strlen(str), 0);
pad(writer, l);
count += l;
}
break;
}
case L'f': {
char str[32];
char *pos;
double val = va_arg(va, double);
if (precision >= 0) {
if (width >= 0) {
snprintf(str, 32, "%*.*f", width, precision, val);
} else {
snprintf(str, 32, "%.*f", precision, val);
}
} else {
if (width >= 0) {
snprintf(str, 32, "%*f", width, val);
} else {
snprintf(str, 32, "%f", val);
}
}
pos = str;
while (*pos) {
writer(*(pos++));
count++;
}
break;
}
case L'n': {
int *n = va_arg(va, int *);
*n = count;
break;
}
case L'%': {
writer('%');
count++;
break;
}
default: {
debug(0, L"Unknown switch %lc in string %ls\n", *filter, filter_org);
return -1;
}
}
} else {
writer(*filter);
count++;
}
}
return count;
}
/// Holds data for swprintf writer.
static struct {
int count;
int max;
wchar_t *pos;
} sw_data;
/// Writers for string output.
static void sw_writer(wchar_t c) {
if (sw_data.count < sw_data.max) *(sw_data.pos++) = c;
sw_data.count++;
}
int vswprintf(wchar_t *out, size_t n, const wchar_t *filter, va_list va) {
int written;
sw_data.pos = out;
sw_data.max = n;
sw_data.count = 0;
written = vgwprintf(&sw_writer, filter, va);
if (written < n) {
*sw_data.pos = 0;
} else {
written = -1;
}
return written;
}
int swprintf(wchar_t *out, size_t n, const wchar_t *filter, ...) {
va_list va;
int written;
va_start(va, filter);
written = vswprintf(out, n, filter, va);
va_end(va);
return written;
}
/// Holds auxiliary data for fwprintf and wprintf writer.
static FILE *fw_data;
static void fw_writer(wchar_t c) { fputwc(c, fw_data); }
/// Writers for file output.
int vfwprintf(FILE *f, const wchar_t *filter, va_list va) {
fw_data = f;
return vgwprintf(&fw_writer, filter, va);
}
int fwprintf(FILE *f, const wchar_t *filter, ...) {
va_list va;
int written;
va_start(va, filter);
written = vfwprintf(f, filter, va);
va_end(va);
return written;
}
int vwprintf(const wchar_t *filter, va_list va) { return vfwprintf(stdout, filter, va); }
int wprintf(const wchar_t *filter, ...) {
va_list va;
int written;
va_start(va, filter);
written = vwprintf(filter, va);
va_end(va);
return written;
}
#endif
#ifndef HAVE_FGETWC
wint_t fgetwc(FILE *stream) {
wchar_t res;

View file

@ -63,38 +63,6 @@ struct winsize {
char *tparm_solaris_kludge(char *str, ...);
#endif
#ifndef HAVE_FWPRINTF
/// Print formated string. Some operating systems (Like NetBSD) do not have wide string formating
/// functions. Therefore we implement our own. Not at all complete. Supports wide and narrow
/// characters, strings and decimal numbers, position (%n), field width and precision.
int fwprintf(FILE *f, const wchar_t *format, ...);
/// Print formated string. Some operating systems (Like NetBSD) do not have wide string formating
/// functions. Therefore we define our own. Not at all complete. Supports wide and narrow
/// characters, strings and decimal numbers, position (%n), field width and precision.
int swprintf(wchar_t *str, size_t l, const wchar_t *format, ...);
/// Print formated string. Some operating systems (Like NetBSD) do not have wide string formating
/// functions. Therefore we define our own. Not at all complete. Supports wide and narrow
/// characters, strings and decimal numbers, position (%n), field width and precision.
int wprintf(const wchar_t *format, ...);
/// Print formated string. Some operating systems (Like NetBSD) do not have wide string formating
/// functions. Therefore we define our own. Not at all complete. Supports wide and narrow
/// characters, strings and decimal numbers, position (%n), field width and precision.
int vwprintf(const wchar_t *filter, va_list va);
/// Print formated string. Some operating systems (Like NetBSD) do not have wide string formating
/// functions. Therefore we define our own. Not at all complete. Supports wide and narrow
/// characters, strings and decimal numbers, position (%n), field width and precision.
int vfwprintf(FILE *f, const wchar_t *filter, va_list va);
/// Print formated string. Some operating systems (Like NetBSD) do not have wide string formating
/// functions. Therefore we define our own. Not at all complete. Supports wide and narrow
/// characters, strings and decimal numbers, position (%n), field width and precision.
int vswprintf(wchar_t *out, size_t n, const wchar_t *filter, va_list va);
#endif
#ifndef HAVE_FGETWC
// Fallback implementation of fgetwc.
wint_t fgetwc(FILE *stream);