48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross/*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * This file and its contents are supplied under the terms of the
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * You may only use this file in accordance with the terms of version
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * 1.0 of the CDDL.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross *
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * A full copy of the text of the CDDL should have accompanied this
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * source. A copy of the CDDL is also available via the Internet at
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * http://www.illumos.org/license/CDDL.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross/*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross/*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * iconv(1) command.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <stdio.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <stdlib.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <string.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <unistd.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <errno.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <limits.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <iconv.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <libintl.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <langinfo.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <locale.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include "charmap.h"
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#include <assert.h>
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossconst char *progname;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rosschar *from_cs;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rosschar *to_cs;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossint debug;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossint cflag; /* skip invalid characters */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossint sflag; /* silent */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossint lflag; /* list conversions */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossvoid iconv_file(FILE *, const char *);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossextern int list_codesets(void);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossiconv_t ich; /* iconv(3c) lib handle */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rosssize_t (*pconv)(const char **iptr, size_t *ileft,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross char **optr, size_t *oleft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rosssize_t
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rosslib_iconv(const char **iptr, size_t *ileft, char **optr, size_t *oleft)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross{
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross return (iconv(ich, iptr, ileft, optr, oleft));
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross}
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossvoid
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossusage(void)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross{
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr, gettext(
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross "usage: %s [-cs] [-f from-codeset] [-t to-codeset] "
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross "[file ...]\n"), progname);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr, gettext("\t%s -l\n"), progname);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(1);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross}
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossint
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossmain(int argc, char **argv)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross{
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross FILE *fp;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross char *fslash, *tslash;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross int c;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross yydebug = 0;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross progname = getprogname();
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) setlocale(LC_ALL, "");
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#if !defined(TEXT_DOMAIN)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#define TEXT_DOMAIN "SYS_TEST"
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#endif
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) textdomain(TEXT_DOMAIN);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross while ((c = getopt(argc, argv, "cdlsf:t:")) != EOF) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross switch (c) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case 'c':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross cflag++;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case 'd':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross debug++;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case 'l':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross lflag++;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case 's':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross sflag++;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case 'f':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross from_cs = optarg;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case 't':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross to_cs = optarg;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case '?':
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross usage();
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (lflag) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (from_cs != NULL || to_cs != NULL || optind != argc)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross usage();
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(list_codesets());
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (from_cs == NULL)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross from_cs = nl_langinfo(CODESET);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (to_cs == NULL)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross to_cs = nl_langinfo(CODESET);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * If either "from" or "to" contains a slash,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * then we're using charmaps.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross fslash = strchr(from_cs, '/');
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross tslash = strchr(to_cs, '/');
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (fslash != NULL || tslash != NULL) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross charmap_init(to_cs, from_cs);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross pconv = cm_iconv;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (debug)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross charmap_dump();
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross } else {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ich = iconv_open(to_cs, from_cs);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (ich == ((iconv_t)-1)) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross switch (errno) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case EINVAL:
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross _("Not supported %s to %s\n"),
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross from_cs, to_cs);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross default:
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross _("iconv_open failed: %s\n"),
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross strerror(errno));
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(1);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross pconv = lib_iconv;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (optind == argc ||
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (optind == argc - 1 && 0 == strcmp(argv[optind], "-"))) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iconv_file(stdin, "stdin");
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(warnings ? 1 : 0);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross for (; optind < argc; optind++) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross fp = fopen(argv[optind], "r");
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (fp == NULL) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross perror(argv[optind]);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(1);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iconv_file(fp, argv[optind]);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fclose(fp);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(warnings ? 1 : 0);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross}
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross/*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Conversion buffer sizes:
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross *
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * The input buffer has room to prepend one mbs character if needed for
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * handling a left-over at the end of a previous conversion buffer.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross *
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Conversions may grow or shrink data, so using a larger output buffer
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * to reduce the likelihood of leftover input buffer data in each pass.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#define IBUFSIZ (MB_LEN_MAX + BUFSIZ)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross#define OBUFSIZ (2 * BUFSIZ)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossvoid
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Rossiconv_file(FILE *fp, const char *fname)
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross{
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross static char ibuf[IBUFSIZ];
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross static char obuf[OBUFSIZ];
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross const char *iptr;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross char *optr;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross off64_t offset;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross size_t ileft, oleft, ocnt;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross int iconv_errno;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross int nr, nw, rc;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross offset = 0;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ileft = 0;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr = ibuf + MB_LEN_MAX;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross while ((nr = fread(ibuf+MB_LEN_MAX, 1, BUFSIZ, fp)) > 0) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross assert(iptr <= ibuf+MB_LEN_MAX);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross assert(ileft <= MB_LEN_MAX);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ileft += nr;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross offset += nr;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross optr = obuf;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross oleft = OBUFSIZ;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Note: the *pconv function is either iconv(3c) or our
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * private equivalent when using charmaps. Both update
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * ileft, oleft etc. even when conversion stops due to
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * an illegal sequence or whatever, so we need to copy
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * the partially converted buffer even on error.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iconv_again:
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross rc = (*pconv)(&iptr, &ileft, &optr, &oleft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iconv_errno = errno;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ocnt = OBUFSIZ - oleft;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (ocnt > 0) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross nw = fwrite(obuf, 1, ocnt, stdout);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (nw != ocnt) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross perror("fwrite");
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(1);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross optr = obuf;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross oleft = OBUFSIZ;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (rc == (size_t)-1) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross switch (iconv_errno) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case E2BIG: /* no room in output buffer */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross goto iconv_again;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case EINVAL: /* incomplete sequence on input */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (debug) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross _("Incomplete sequence in %s at offset %lld\n"),
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross fname, offset - ileft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Copy the remainder to the space reserved
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * at the start of the input buffer.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross assert(ileft > 0);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (ileft <= MB_LEN_MAX) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross char *p = ibuf+MB_LEN_MAX-ileft;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) memmove(p, iptr, ileft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr = p;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross continue; /* read again */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Should not see ileft > MB_LEN_MAX,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * but if we do, handle as EILSEQ.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /* FALLTHROUGH */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross case EILSEQ: /* invalid sequence on input */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (!sflag) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross _("Illegal sequence in %s at offset %lld\n"),
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross fname, offset - ileft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross _("bad seq: \\x%02x\\x%02x\\x%02x\n"),
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr[0] & 0xff,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr[1] & 0xff,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr[2] & 0xff);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross assert(ileft > 0);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /* skip one */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr++;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ileft--;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross assert(oleft > 0);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (!cflag) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross *optr++ = '?';
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross oleft--;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross goto iconv_again;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross default:
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (void) fprintf(stderr,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross _("iconv error (%s) in file $s at offset %lld\n"),
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross strerror(iconv_errno), fname,
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross offset - ileft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross break;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /* normal iconv return */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ileft = 0;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr = ibuf + MB_LEN_MAX;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross /*
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * End of file
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross * Flush any shift encodings.
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross */
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross iptr = NULL;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ileft = 0;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross optr = obuf;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross oleft = OBUFSIZ;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross (*pconv)(&iptr, &ileft, &optr, &oleft);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross ocnt = OBUFSIZ - oleft;
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (ocnt > 0) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross nw = fwrite(obuf, 1, ocnt, stdout);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross if (nw != ocnt) {
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross perror("fwrite");
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross exit(1);
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross }
48edc7cf07b5dccc3ad84bf2dafe4150bd666d60Gordon Ross}