mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 06:05:39 +08: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
|
@ -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 )
|
||||
|
|
411
src/fallback.cpp
411
src/fallback.cpp
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user