1 /*
   2  * Copyright 2013 Garrett D'Amore <garrett@damore.org>
   3  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
   4  * Copyright (c) 2002-2004 Tim J. Robbins.
   5  * All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in the
  14  *    documentation and/or other materials provided with the distribution.
  15  *
  16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  */
  28 
  29 #include "lint.h"
  30 #include "mse_int.h"
  31 #include "file64.h"
  32 #include "mtlib.h"
  33 #include <errno.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <wchar.h>
  37 #include "mblocal.h"
  38 #include "stdiom.h"
  39 #include "localeimpl.h"
  40 #include "lctype.h"
  41 
  42 /*
  43  * Non-MT-safe version.
  44  */
  45 wint_t
  46 _fgetwc_unlocked_l(FILE *fp, locale_t loc)
  47 {
  48         wchar_t wc;
  49         size_t nconv;
  50         int     c;
  51         mbstate_t       *statep;
  52         const struct lc_ctype *lct;
  53 
  54         if ((c = GETC(fp)) == EOF)
  55                 return (WEOF);
  56 
  57         lct = loc->ctype;
  58         if (lct->lc_max_mblen == 1) {
  59                 /* Fast path for single-byte encodings. */
  60                 return ((wint_t)c);
  61         }
  62         if ((statep = _getmbstate(fp)) == NULL) {
  63                 fp->_flag = _IOERR;
  64                 errno = EBADF;
  65                 return (WEOF);
  66         }
  67         do {
  68                 char    x = (char)c;
  69                 nconv = lct->lc_mbrtowc(&wc, &x, 1, statep);
  70                 if (nconv == (size_t)-1) {
  71                         break;
  72                 } else if (nconv == (size_t)-2) {
  73                         /* Incompletely decoded, consume another char */
  74                         continue;
  75                 } else if (nconv == 0) {
  76                         /*
  77                          * Assume that the only valid representation of
  78                          * the null wide character is a single null byte.
  79                          */
  80                         return (L'\0');
  81                 } else {
  82                         return (wc);
  83                 }
  84         } while ((c = GETC(fp)) != EOF);
  85 
  86         /*
  87          * If we got here it means we got truncated in a character, or
  88          * the character did not decode properly.  Note that in the case
  89          * of a botched decoding, we don't UNGETC the bad bytes.  Should
  90          * we?
  91          */
  92         fp->_flag |= _IOERR;
  93         errno = EILSEQ;
  94         return (WEOF);
  95 }
  96 
  97 wint_t
  98 _fgetwc_unlocked(FILE *fp)
  99 {
 100         return (_fgetwc_unlocked_l(fp, uselocale(NULL)));
 101 }
 102 
 103 
 104 /*
 105  * MT safe version
 106  */
 107 #undef getwc
 108 #pragma weak getwc = fgetwc
 109 wint_t
 110 fgetwc(FILE *fp)
 111 {
 112         wint_t          r;
 113         rmutex_t        *l;
 114         locale_t        loc = uselocale(NULL);
 115 
 116         FLOCKFILE(l, fp);
 117         r = _fgetwc_unlocked_l(fp, loc);
 118         FUNLOCKFILE(l);
 119 
 120         return (r);
 121 }
 122 
 123 /*
 124  * XPG5 version.
 125  */
 126 #undef  __getwc_xpg5
 127 #pragma weak __getwc_xpg5 = __fgetwc_xpg5
 128 wint_t
 129 __fgetwc_xpg5(FILE *fp)
 130 {
 131         wint_t          r;
 132         rmutex_t        *l;
 133         locale_t        loc = uselocale(NULL);
 134 
 135         FLOCKFILE(l, fp);
 136         if (GET_NO_MODE(fp))
 137                 _setorientation(fp, _WC_MODE);
 138         r = _fgetwc_unlocked_l(fp, loc);
 139         FUNLOCKFILE(l);
 140 
 141         return (r);
 142 }
 143 
 144 #pragma weak getwc_l = fgetwc_l
 145 wint_t
 146 fgetwc_l(FILE *fp, locale_t loc)
 147 {
 148         wint_t          r;
 149         rmutex_t        *l;
 150         FLOCKFILE(l, fp);
 151         if (GET_NO_MODE(fp))
 152                 _setorientation(fp, _WC_MODE);
 153         r = _fgetwc_unlocked_l(fp, loc);
 154         FUNLOCKFILE(l);
 155 
 156         return (r);
 157 }