# Add "--replace" option to iconv utility. --- glibc-2.5.orig/iconv/iconv_prog.c +++ glibc-2.5/iconv/iconv_prog.c @@ -63,6 +63,7 @@ static const struct argp_option options[ { "list", 'l', NULL, 0, N_("list all known coded character sets") }, { NULL, 0, NULL, 0, N_("Output control:") }, { NULL, 'c', NULL, 0, N_("omit invalid characters from output") }, + { "replace", 'r', "SYMBOL", OPTION_ARG_OPTIONAL, N_("replace invalid characters with specified symbol") }, { "output", 'o', "FILE", 0, N_("output file") }, { "silent", 's', NULL, 0, N_("suppress warnings") }, { "verbose", OPT_VERBOSE, NULL, 0, N_("print progress information") }, @@ -106,6 +107,9 @@ static int list; /* If nonzero omit invalid character from output. */ int omit_invalid; +/* If nonzero replace invalid character. */ +static char replace_invalid; + /* Prototypes for the functions doing the actual work. */ static int process_block (iconv_t cd, char *addr, size_t len, FILE *output); static int process_fd (iconv_t cd, int fd, FILE *output); @@ -304,7 +308,7 @@ #endif #ifdef _POSIX_MAPPED_FILES /* We have possibilities for reading the input file. First try to mmap() it since this will provide the fastest solution. */ - if (fstat (fd, &st) == 0 + if (!replace_invalid && fstat (fd, &st) == 0 && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != MAP_FAILED)) { @@ -387,6 +391,10 @@ parse_opt (int key, char *arg, struct ar /* Omit invalid characters from output. */ omit_invalid = 1; break; + case 'r': + /* Replace invalid characters. */ + replace_invalid = (arg && *arg) ? *arg : '?'; + break; case OPT_VERBOSE: verbose = 1; break; @@ -430,6 +438,23 @@ warranty; not even for MERCHANTABILITY o fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); } +static int +write_invalid( iconv_t cd, char **addr, size_t *len, FILE *output ) +{ + int errno_save = errno; + int needed_from = ((__gconv_t) cd)->__steps->__min_needed_from; + if ( fwrite( &replace_invalid, 1, 1, output ) < 1 || ferror( output ) ) + { + /* Error occurred while printing replace symbol. */ + error (0, 0, _("conversion stopped due to problem in writing the output")); + return -1; + } + + errno = errno_save; + *addr += needed_from; + *len -= needed_from; + return 0; +} static int process_block (iconv_t cd, char *addr, size_t len, FILE *output) @@ -517,12 +542,27 @@ conversion stopped due to problem in wri switch (errno) { case EILSEQ: + if (replace_invalid) + { + if (write_invalid (cd, &addr, &len, output)) + return -1; + else + continue; + } if (! omit_invalid) error (0, 0, _("illegal input sequence at position %ld"), (long int) (addr - start)); break; case EINVAL: - error (0, 0, _("\ + if (replace_invalid) + { + if (write_invalid (cd, &addr, &len, output)) + return -1; + else + continue; + } + if (! omit_invalid) + error (0, 0, _("\ incomplete character or shift sequence at end of buffer")); break; case EBADF: