mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
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:
parent
d0aa461587
commit
44757c81af
3 changed files with 1 additions and 444 deletions
|
@ -310,7 +310,7 @@ AC_STRUCT_DIRENT_D_TYPE
|
||||||
# Check for presense of various functions used by fish
|
# 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( futimes wcwidth wcswidth wcstok fputwc fgetwc )
|
||||||
AC_CHECK_FUNCS( wcstol wcslcat wcslcpy lrand48_r killpg )
|
AC_CHECK_FUNCS( wcstol wcslcat wcslcpy lrand48_r killpg )
|
||||||
AC_CHECK_FUNCS( backtrace backtrace_symbols_fd getifaddrs )
|
AC_CHECK_FUNCS( backtrace backtrace_symbols_fd getifaddrs )
|
||||||
|
|
411
src/fallback.cpp
411
src/fallback.cpp
|
@ -90,417 +90,6 @@ char *tparm_solaris_kludge(char *str, ...) {
|
||||||
|
|
||||||
#endif
|
#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
|
#ifndef HAVE_FGETWC
|
||||||
wint_t fgetwc(FILE *stream) {
|
wint_t fgetwc(FILE *stream) {
|
||||||
wchar_t res;
|
wchar_t res;
|
||||||
|
|
|
@ -63,38 +63,6 @@ struct winsize {
|
||||||
char *tparm_solaris_kludge(char *str, ...);
|
char *tparm_solaris_kludge(char *str, ...);
|
||||||
#endif
|
#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
|
#ifndef HAVE_FGETWC
|
||||||
// Fallback implementation of fgetwc.
|
// Fallback implementation of fgetwc.
|
||||||
wint_t fgetwc(FILE *stream);
|
wint_t fgetwc(FILE *stream);
|
||||||
|
|
Loading…
Reference in a new issue