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 }