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