1 /*
   2  * Copyright (c) 2002-2004 Tim J. Robbins.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24  * SUCH DAMAGE.
  25  */
  26 
  27 /*
  28  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  29  * Use is subject to license terms.
  30  */
  31 
  32 #include "lint.h"
  33 #include "file64.h"
  34 #include "mtlib.h"
  35 #include "mse_int.h"
  36 #include <errno.h>
  37 #include <limits.h>
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <wchar.h>
  41 #include <synch.h>
  42 #include "mblocal.h"
  43 #include "stdiom.h"
  44 #include "mse.h"
  45 
  46 #pragma weak    _putwc = putwc
  47 
  48 /*
  49  * FreeBSD had both a MT safe and non-MT safe version.  For whatever reason,
  50  * we don't need the non-MT safe version.  We do this because its faster,
  51  * since we don't have to lock the file while doing the potentially expensive
  52  * conversion from wide to mb.
  53  *
  54  * Solaris also has XPG5 and legacy semantics.  The new standard requires
  55  * that the stream orientation change, but legacy calls don't do that.
  56  *
  57  * Note that we had the source for the XPG5 version of this, but it relied
  58  * on closed implementation bits that we lack, so we supply replacements
  59  * here.
  60  */
  61 static wint_t
  62 __fputwc_impl(wchar_t wc, FILE *fp, int orient)
  63 {
  64         char buf[MB_LEN_MAX];
  65         size_t          i, len;
  66         rmutex_t        *mx;
  67 
  68         /* If we are given WEOF, then we have to stop */
  69         if (wc == WEOF)
  70                 return (WEOF);
  71 
  72         if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) {
  73                 /*
  74                  * Assume single-byte locale with no special encoding.
  75                  * A more careful test would be to check
  76                  * _CurrentRuneLocale->encoding.
  77                  */
  78                 *buf = (unsigned char)wc;
  79                 len = 1;
  80         } else {
  81                 /*
  82                  * FreeBSD used restartable wcrtomb.  I think we can use
  83                  * the simpler wctomb form here.  We should have a complete
  84                  * decode.
  85                  */
  86                 if ((len = wctomb(buf, wc)) == (size_t)-1) {
  87                         fp->_flag |= _IOERR;
  88                         errno = EILSEQ;
  89                         return (WEOF);
  90                 }
  91         }
  92 
  93         FLOCKFILE(mx, fp);
  94         /*
  95          * This is used for XPG 5 semantics, which requires the stream
  96          * orientation to be changed when the function is called.
  97          */
  98         if (orient && GET_NO_MODE(fp)) {
  99                 _setorientation(fp, _WC_MODE);
 100         }
 101         for (i = 0; i < len; i++) {
 102                 if (PUTC((unsigned char)buf[i], fp) == EOF) {
 103                         FUNLOCKFILE(mx);
 104                         return (WEOF);
 105                 }
 106         }
 107         FUNLOCKFILE(mx);
 108         return ((wint_t)wc);
 109 }
 110 
 111 wint_t
 112 fputwc(wchar_t wc, FILE *fp)
 113 {
 114         return (__fputwc_impl(wc, fp, 0));
 115 }
 116 
 117 /*
 118  * Trivial functional form of the typical macro.
 119  */
 120 #undef __putwc
 121 wint_t
 122 putwc(wchar_t wc, FILE *fp)
 123 {
 124         return (__fputwc_impl(wc, fp, 0));
 125 }
 126 
 127 wint_t
 128 __fputwc_xpg5(wint_t wc, FILE *fp)
 129 {
 130         return (__fputwc_impl(wc, fp, 1));
 131 }
 132 
 133 #undef __putwc_xpg5
 134 wint_t
 135 __putwc_xpg5(wint_t wc, FILE *fp)
 136 {
 137         return (__fputwc_impl(wc, fp, 1));
 138 }