Package: gnuvd Version: 1.0.3-1 Followup-For: Bug #368736
Well, here's a patch. I forgot how nasty C could be :(
diff -urw gnuvd-1.0.3/src/main.c gnuvd-pdw/src/main.c --- gnuvd-1.0.3/src/main.c 2005-11-05 15:44:30.000000000 +0100 +++ gnuvd-pdw/src/main.c 2006-06-02 15:29:55.000000000 +0200 @@ -21,10 +21,18 @@ #include <config.h> #endif /*HAVE_CONFIG*/ +#define _GNU_SOURCE /*for vasprintf*/ + #include <ctype.h> +#include <stdarg.h> #include <stdio.h> #include <string.h> #include <unistd.h> +#include <iconv.h> +#include <errno.h> +#include <stdlib.h> +#include <locale.h> +#include <langinfo.h> #include "gnuvd.h" @@ -37,6 +45,8 @@ /* internal functions */ static void show_results (Buffer *results, int keep_entities); static char get_special_char (char *str); +static int iconv_str (iconv_t cd, char **output, char *input); +static void fprintf_iconv (FILE *f, iconv_t cd, const char *fmt, ...); static void help (); int @@ -44,10 +54,13 @@ { int keep_entities = 0; char *word = NULL; + iconv_t cd; VDQuery *vd_query = NULL; VDError vd_ex; + setlocale(LC_CTYPE, ""); + while (1) { int c = getopt (argc, argv, "kh"); @@ -73,10 +86,17 @@ break; } + cd = iconv_open("ISO-8859-1", nl_langinfo(CODESET)); + if (cd != (iconv_t)(-1)) { + iconv_str(cd, &word, argv[optind]); + iconv_close(cd); + } + if (!word) + /* let's hope for the best */ word = argv[optind]; - vd_ex = VD_ERR_OK; /* prepare query */ + vd_ex = VD_ERR_OK; vd_query = vd_query_new (word, &vd_ex); if (!vd_query) { if (vd_ex != VD_ERR_OK) @@ -116,9 +136,18 @@ char s_kars[S_KARS_MAX + 2]; int skip_spc = 1; int stress_pos; + iconv_t cd; FILE *out = stdout; + cd = iconv_open(nl_langinfo(CODESET), "ISO-8859-1"); + if (cd == (iconv_t)(-1)) { + fprintf(stderr, + "Can't convert from ISO-8859-1 to your locale's charset. " + "Complain to your\noperating system vendor."); + exit(1); + } + /* output to PAGER or to STDOUT? */ if (isatty(fileno(stdin)) && isatty(fileno(stdout))) { char *pager = getenv("PAGER"); @@ -129,7 +158,6 @@ } } - /* strip superfluous space after */ for (i = buffer_end (buffer) - 1; i >= buffer_begin(buffer) + 3; --i) if ((buffer_at (buffer, i-3) == 'D') && @@ -144,7 +172,7 @@ /* Keep <=> */ if (buffer_end(buffer) - j > 3) { if ((strncmp (buffer_data_pos(buffer,j), "<=>", 3) == 0)) { - fprintf (out, "<=>"); + fprintf_iconv (out, cd, "<=>"); j+= 2; continue; } @@ -161,7 +189,7 @@ /* SMALL -> */ if (buffer_end(buffer) - j > 7) { if ((strncmp (buffer_data_pos(buffer,j),"<SMALL>", 7) == 0)) { - fprintf (out, " ("); + fprintf_iconv (out, cd, " ("); j += 6; continue; } @@ -170,7 +198,7 @@ /* /SMALL -> */ if (buffer_end(buffer) - j > 8) { if ((strncmp (buffer_data_pos(buffer,j),"</SMALL>", 8) == 0)) { - fprintf (out, ")"); + fprintf_iconv (out, cd, ")"); j += 7; continue; } @@ -181,7 +209,7 @@ if (buffer_end(buffer) - j > 8 && strncmp(buffer_data_pos(buffer,j), "<DD><B>", 7) == 0) { j += 6; - fprintf (out, "\n"); + fprintf_iconv (out, cd, "\n"); continue; } @@ -202,7 +230,7 @@ m_pos = buffer_find_offset (buffer,j,"·",6); if (stress_pos!=buffer_end(buffer) && stress_pos < dd_pos && stress_pos < m_pos) { - fprintf (out, "`"); + fprintf_iconv (out, cd, "`"); j += (strncmp(buffer_data_pos(buffer,j),"<BIG>", 5) == 0) ? 4 : 5; continue; } @@ -228,7 +256,7 @@ k = get_special_char (s_kars); if (k) - fprintf (out, "%c", k); + fprintf_iconv (out, cd, "%c", k); } continue; } @@ -240,9 +268,16 @@ else skip_spc = 0; } - fprintf (out, "%c", buffer_at(buffer,j)); + + /* convert DOS-style CR/LF line-endings to Unix-style LF */ + if (buffer_at(buffer,j) == 13) + continue; + + fprintf_iconv (out, cd, "%c", buffer_at(buffer,j)); } + iconv_close(cd); + /* if we were outputing to PAGER, close it */ if (out != stdout) { fflush (out); @@ -364,6 +399,77 @@ return '?'; } +static int +iconv_str (iconv_t cd, char **output, char *input) +{ + size_t inleft; + size_t outsize, outleft; + size_t result; + char *outbuf; + + if (!input) + return -1; + + outsize = outleft = 16; + *output = outbuf = malloc(outsize); + if (!*output) + return -1; + + inleft = strlen(input) + 1; + while (inleft > 0) { + result = iconv(cd, &input, &inleft, &outbuf, &outleft); + if (result == (size_t)(-1)) { + /* iconv might error out because the output buffer is + * full, or because there's something wrong with the + * input (an incomplete multibyte character, for + * example). We only deal with the first case. + */ + if (errno == E2BIG) { + char *new; + outleft += outsize; + outsize *= 2; + new = realloc(*output, outsize); + if (!new) + goto fail; + *output = new; + outbuf = *output + outsize - outleft; + } else + goto fail; + } + } + + return outsize - outleft; + +fail: + /* Something went wrong. Reset iconv and free the output buffer */ + iconv(cd, 0, 0, 0, 0); + free(*output); + *output = 0; + return -1; +} + +static void +fprintf_iconv (FILE *f, iconv_t cd, const char *fmt, ...) +{ + va_list va; + char *str, *converted; + int result; + + va_start(va, fmt); + result = vasprintf(&str, fmt, va); + if (result < 0) + return; /*out of memory...*/ + va_end(va); + + result = iconv_str(cd, &converted, str); + free(str); + if (result < 0) + return; /*out or memory, or something even nastier...*/ + + fputs(converted, f); + free(converted); +} + static void help()