661 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			661 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <hawk-sio.h>
 | |
| #include "hawk-prv.h"
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #	include <windows.h> /* for the UGLY hack */
 | |
| #elif defined(__OS2__)
 | |
| 	/* nothing */
 | |
| #elif defined(__DOS__)
 | |
| 	/* nothing */
 | |
| #else
 | |
| #	include "syscall.h"
 | |
| #endif
 | |
| 
 | |
| #define LOCK_OUTPUT(sio) do { if ((sio)->mtx) hawk_mtx_lock ((sio)->mtx, HAWK_NULL); } while(0)
 | |
| #define UNLOCK_OUTPUT(sio) do { if ((sio)->mtx) hawk_mtx_unlock ((sio)->mtx); } while(0)
 | |
| 
 | |
| /* TODO: currently, LOCK_INPUT and LOCK_OUTPUT don't have difference.
 | |
|  *       can i just use two difference mutex objects to differentiate? */
 | |
| #define LOCK_INPUT(sio) do { if ((sio)->mtx) hawk_mtx_lock ((sio)->mtx, HAWK_NULL); } while(0)
 | |
| #define UNLOCK_INPUT(sio) do { if ((sio)->mtx) hawk_mtx_unlock ((sio)->mtx); } while(0)
 | |
| 
 | |
| /* internal status codes */
 | |
| enum
 | |
| {
 | |
| 	STATUS_UTF8_CONSOLE = (1 << 0),
 | |
| 	STATUS_LINE_BREAK   = (1 << 1)
 | |
| };
 | |
| 
 | |
| static hawk_ooi_t file_input (hawk_tio_t* tio, hawk_tio_cmd_t cmd, void* buf, hawk_oow_t size);
 | |
| static hawk_ooi_t file_output (hawk_tio_t* tio, hawk_tio_cmd_t cmd, void* buf, hawk_oow_t size);
 | |
| 
 | |
| hawk_sio_t* hawk_sio_open (hawk_gem_t* gem, hawk_oow_t xtnsize, const hawk_ooch_t* file, int flags)
 | |
| {
 | |
| 	hawk_sio_t* sio;
 | |
| 
 | |
| 	sio = (hawk_sio_t*)hawk_gem_allocmem(gem, HAWK_SIZEOF(hawk_sio_t) + xtnsize);
 | |
| 	if (sio)
 | |
| 	{
 | |
| 		if (hawk_sio_init(sio, gem, file, flags) <= -1)
 | |
| 		{
 | |
| 			hawk_gem_freemem (gem, sio);
 | |
| 			return HAWK_NULL;
 | |
| 		}
 | |
| 		else HAWK_MEMSET (sio + 1, 0, xtnsize);
 | |
| 	}
 | |
| 	return sio;
 | |
| }
 | |
| 
 | |
| hawk_sio_t* hawk_sio_openstd (hawk_gem_t* gem, hawk_oow_t xtnsize, hawk_sio_std_t std, int flags)
 | |
| {
 | |
| 	hawk_sio_t* sio;
 | |
| 	hawk_fio_hnd_t hnd;
 | |
| 
 | |
| 	/* Is this necessary?
 | |
| 	if (flags & HAWK_SIO_KEEPATH)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum (gem, HAWK_NULL, HAWK_EINVAL);
 | |
| 		return HAWK_NULL;
 | |
| 	}
 | |
| 	*/
 | |
| 
 | |
| 	if (hawk_get_std_fio_handle(std, &hnd) <= -1) return HAWK_NULL;
 | |
| 
 | |
| 	sio = hawk_sio_open(gem, xtnsize, (const hawk_ooch_t*)&hnd, flags | HAWK_SIO_HANDLE | HAWK_SIO_NOCLOSE);
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	if (sio)
 | |
| 	{
 | |
| 		DWORD mode;
 | |
| 		if (GetConsoleMode(sio->file.handle, &mode) == TRUE && GetConsoleOutputCP() == CP_UTF8)
 | |
| 		{
 | |
| 			sio->status |= STATUS_UTF8_CONSOLE;
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	return sio;
 | |
| }
 | |
| 
 | |
| 
 | |
| void hawk_sio_close (hawk_sio_t* sio)
 | |
| {
 | |
| 	hawk_sio_fini (sio);
 | |
| 	hawk_gem_freemem (sio->gem, sio);
 | |
| }
 | |
| 
 | |
| int hawk_sio_init (hawk_sio_t* sio, hawk_gem_t* gem, const hawk_ooch_t* path, int flags)
 | |
| {
 | |
| 	int mode;
 | |
| 	int topt = 0;
 | |
| 
 | |
| 	HAWK_MEMSET (sio, 0, HAWK_SIZEOF(*sio));
 | |
| 	sio->gem = gem;
 | |
| 
 | |
| 	mode = HAWK_FIO_RUSR | HAWK_FIO_WUSR | HAWK_FIO_RGRP | HAWK_FIO_ROTH;
 | |
| 
 | |
| 	if (flags & HAWK_SIO_REENTRANT)
 | |
| 	{
 | |
| 		sio->mtx = hawk_mtx_open(gem, 0);
 | |
| 		if (!sio->mtx) goto oops00;
 | |
| 	}
 | |
| 	/* sio flag enumerators redefines most fio flag enumerators and
 | |
| 	 * compose a superset of fio flag enumerators. when a user calls
 | |
| 	 * this function, a user can specify a sio flag enumerator not
 | |
| 	 * present in the fio flag enumerator. mask off such an enumerator. */
 | |
| 	if (hawk_fio_init(&sio->file, gem, path, (flags & ~HAWK_FIO_RESERVED), mode) <= -1) goto oops01;
 | |
| 
 | |
| 	if (flags & HAWK_SIO_IGNOREECERR) topt |= HAWK_TIO_IGNOREECERR;
 | |
| 	if (flags & HAWK_SIO_NOAUTOFLUSH) topt |= HAWK_TIO_NOAUTOFLUSH;
 | |
| 
 | |
| 	if ((flags & HAWK_SIO_KEEPPATH) && !(flags & HAWK_SIO_HANDLE))
 | |
| 	{
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 		sio->path = hawk_gem_dupoocstr(gem, path, HAWK_NULL);
 | |
| 	#else
 | |
| 		if (flags & HAWK_SIO_BCSTRPATH)
 | |
| 		{
 | |
| 			/* the stored path is always of the hawk_ooch_t type.
 | |
| 			 * and the conversion uses the cmgr set on the gem object.
 | |
| 			 * note that cmgr for the actual file content can be set
 | |
| 			 * with hawk_sio_setcmgr(). */
 | |
| 			sio->path = hawk_gem_dupbtoucstr(gem, (const hawk_bch_t*)path, HAWK_NULL, 1);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			sio->path = hawk_gem_dupoocstr(gem, path, HAWK_NULL);
 | |
| 		}
 | |
| 	#endif
 | |
| 		if (sio->path == HAWK_NULL) goto oops02;
 | |
| 	}
 | |
| 
 | |
| 	if (hawk_tio_init(&sio->tio.io, gem, topt) <= -1) goto oops03;
 | |
| 
 | |
| 	/* store the back-reference to sio in the extension area.*/
 | |
| 	/*HAWK_ASSERT(hawk, (&sio->tio.io + 1) == &sio->tio.xtn);*/
 | |
| 	*(hawk_sio_t**)(&sio->tio.io + 1) = sio;
 | |
| 
 | |
| 	if (hawk_tio_attachin(&sio->tio.io, file_input, sio->inbuf, HAWK_COUNTOF(sio->inbuf)) <= -1 ||
 | |
| 	    hawk_tio_attachout(&sio->tio.io, file_output, sio->outbuf, HAWK_COUNTOF(sio->outbuf)) <= -1)
 | |
| 	{
 | |
| 		goto oops04;
 | |
| 	}
 | |
| 
 | |
| #if defined(__OS2__)
 | |
| 	if (flags & HAWK_SIO_LINEBREAK) sio->status |= STATUS_LINE_BREAK;
 | |
| #endif
 | |
| 	return 0;
 | |
| 
 | |
| oops04:
 | |
| 	hawk_tio_fini (&sio->tio.io);
 | |
| oops03:
 | |
| 	if (sio->path) hawk_gem_freemem (sio->gem, sio->path);
 | |
| oops02:
 | |
| 	hawk_fio_fini (&sio->file);
 | |
| oops01:
 | |
| 	if (sio->mtx) hawk_mtx_close (sio->mtx);
 | |
| oops00:
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| int hawk_sio_initstd (hawk_sio_t* sio, hawk_gem_t* gem, hawk_sio_std_t std, int flags)
 | |
| {
 | |
| 	int n;
 | |
| 	hawk_fio_hnd_t hnd;
 | |
| 
 | |
| 	if (hawk_get_std_fio_handle(std, &hnd) <= -1) return -1;
 | |
| 
 | |
| 	n = hawk_sio_init(sio, gem, (const hawk_ooch_t*)&hnd, flags | HAWK_SIO_HANDLE | HAWK_SIO_NOCLOSE);
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	if (n >= 0)
 | |
| 	{
 | |
| 		DWORD mode;
 | |
| 		if (GetConsoleMode (sio->file.handle, &mode) == TRUE && GetConsoleOutputCP() == CP_UTF8)
 | |
| 		{
 | |
| 			sio->status |= STATUS_UTF8_CONSOLE;
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| void hawk_sio_fini (hawk_sio_t* sio)
 | |
| {
 | |
| 	/*if (hawk_sio_flush (sio) <= -1) return -1;*/
 | |
| 	hawk_sio_flush (sio);
 | |
| 	hawk_tio_fini (&sio->tio.io);
 | |
| 	hawk_fio_fini (&sio->file);
 | |
| 	if (sio->path) hawk_gem_freemem (sio->gem, sio->path);
 | |
| 	if (sio->mtx) hawk_mtx_close (sio->mtx);
 | |
| }
 | |
| 
 | |
| hawk_cmgr_t* hawk_sio_getcmgr (hawk_sio_t* sio)
 | |
| {
 | |
| 	return hawk_tio_getcmgr(&sio->tio.io);
 | |
| }
 | |
| 
 | |
| void hawk_sio_setcmgr (hawk_sio_t* sio, hawk_cmgr_t* cmgr)
 | |
| {
 | |
| 	hawk_tio_setcmgr (&sio->tio.io, cmgr);
 | |
| }
 | |
| 
 | |
| hawk_sio_hnd_t hawk_sio_gethnd (const hawk_sio_t* sio)
 | |
| {
 | |
| 	/*return hawk_fio_gethnd(&sio->file);*/
 | |
| 	return HAWK_FIO_HANDLE(&sio->file);
 | |
| }
 | |
| 
 | |
| const hawk_ooch_t* hawk_sio_getpath (hawk_sio_t* sio)
 | |
| {
 | |
| 	/* this path is valid if HAWK_SIO_HANDLE is off and HAWK_SIO_KEEPPATH is on.
 | |
| 	 * HAWK_SIO_BCSTRPATH doesn't affect this value. The opening side ensures it
 | |
| 	 * to be in the hawk_ooch_type. */
 | |
| 	return sio->path;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_flush (hawk_sio_t* sio)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = hawk_tio_flush(&sio->tio.io);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| void hawk_sio_drain (hawk_sio_t* sio)
 | |
| {
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	hawk_tio_drain (&sio->tio.io);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_getbchar (hawk_sio_t* sio, hawk_bch_t* c)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 	LOCK_INPUT (sio);
 | |
| 	n = hawk_tio_readbchars(&sio->tio.io, c, 1);
 | |
| 	UNLOCK_INPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_getuchar (hawk_sio_t* sio, hawk_uch_t* c)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 	LOCK_INPUT (sio);
 | |
| 	n = hawk_tio_readuchars(&sio->tio.io, c, 1);
 | |
| 	UNLOCK_INPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_getbcstr (hawk_sio_t* sio, hawk_bch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| 	if (size <= 0) return 0;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* Using ReadConsoleA() didn't help at all.
 | |
| 	 * so I don't implement any hack here */
 | |
| #endif
 | |
| 
 | |
| 	LOCK_INPUT (sio);
 | |
| 	n = hawk_tio_readbchars(&sio->tio.io, buf, size - 1);
 | |
| 	if (n <= -1) return -1;
 | |
| 	UNLOCK_INPUT (sio);
 | |
| 
 | |
| 	buf[n] = '\0';
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_getbchars (hawk_sio_t* sio, hawk_bch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| #if defined(_WIN32)
 | |
| 	/* Using ReadConsoleA() didn't help at all.
 | |
| 	 * so I don't implement any hack here */
 | |
| #endif
 | |
| 
 | |
| 	LOCK_INPUT (sio);
 | |
| 	n = hawk_tio_readbchars(&sio->tio.io, buf, size);
 | |
| 	UNLOCK_INPUT (sio);
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_getucstr (hawk_sio_t* sio, hawk_uch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| 	if (size <= 0) return 0;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* Using ReadConsoleA() didn't help at all.
 | |
| 	 * so I don't implement any hack here */
 | |
| #endif
 | |
| 
 | |
| 	LOCK_INPUT (sio);
 | |
| 	n = hawk_tio_readuchars(&sio->tio.io, buf, size - 1);
 | |
| 	UNLOCK_INPUT (sio);
 | |
| 
 | |
| 	buf[n] = '\0';
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_getuchars(hawk_sio_t* sio, hawk_uch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* Using ReadConsoleW() didn't help at all.
 | |
| 	 * so I don't implement any hack here */
 | |
| #endif
 | |
| 
 | |
| 	LOCK_INPUT (sio);
 | |
| 	n = hawk_tio_readuchars (&sio->tio.io, buf, size);
 | |
| 	UNLOCK_INPUT (sio);
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| static hawk_ooi_t putbc_no_mutex (hawk_sio_t* sio, hawk_bch_t c)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(__OS2__)
 | |
| 	if (c == '\n' && (sio->status & STATUS_LINE_BREAK))
 | |
| 		n = hawk_tio_writebchars(&sio->tio.io, "\r\n", 2);
 | |
| 	else
 | |
| 		n = hawk_tio_writebchars(&sio->tio.io, &c, 1);
 | |
| #else
 | |
| 	n = hawk_tio_writebchars(&sio->tio.io, &c, 1);
 | |
| #endif
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_putbchar (hawk_sio_t* sio, hawk_bch_t c)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = putbc_no_mutex(sio, c);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| static hawk_ooi_t put_uchar_no_mutex (hawk_sio_t* sio, hawk_uch_t c)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(__OS2__)
 | |
| 	if (c == '\n' && (sio->status & STATUS_LINE_BREAK))
 | |
| 	{
 | |
| 		static hawk_uch_t crnl[2] = { '\r', '\n' };
 | |
| 		n = hawk_tio_writeuchars(&sio->tio.io, crnl, 2);
 | |
| 	}
 | |
| 	else
 | |
| 		n = hawk_tio_writeuchars(&sio->tio.io, &c, 1);
 | |
| #else
 | |
| 	n = hawk_tio_writeuchars(&sio->tio.io, &c, 1);
 | |
| #endif
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_putuchar (hawk_sio_t* sio, hawk_uch_t c)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = put_uchar_no_mutex(sio, c);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_putbcstr (hawk_sio_t* sio, const hawk_bch_t* str)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* Using WriteConsoleA() didn't help at all.
 | |
| 	 * so I don't implement any hacks here */
 | |
| #elif defined(__OS2__)
 | |
| 	if (sio->status & STATUS_LINE_BREAK)
 | |
| 	{
 | |
| 		LOCK_OUTPUT (sio);
 | |
| 		for (n = 0; n < HAWK_TYPE_MAX(hawk_ooi_t) && str[n] != '\0'; n++)
 | |
| 		{
 | |
| 			if ((n = putbc_no_mutex(sio, str[n])) <= -1)
 | |
| 			{
 | |
| 				n = -1;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		UNLOCK_OUTPUT (sio);
 | |
| 		return n;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = hawk_tio_writebchars(&sio->tio.io, str, (hawk_oow_t)-1);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_putbchars (hawk_sio_t* sio, const hawk_bch_t* str, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* Using WriteConsoleA() didn't help at all.
 | |
| 	 * so I don't implement any hacks here */
 | |
| #elif defined(__OS2__)
 | |
| 	if (sio->status & STATUS_LINE_BREAK)
 | |
| 	{
 | |
| 		if (size > HAWK_TYPE_MAX(hawk_ooi_t)) size = HAWK_TYPE_MAX(hawk_ooi_t);
 | |
| 		LOCK_OUTPUT (sio);
 | |
| 		for (n = 0; n < size; n++)
 | |
| 		{
 | |
| 			if (putbc_no_mutex(sio, str[n]) <= -1)
 | |
| 			{
 | |
| 				n = -1;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		UNLOCK_OUTPUT (sio);
 | |
| 		return n;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = hawk_tio_writebchars (&sio->tio.io, str, size);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_putucstr (hawk_sio_t* sio, const hawk_uch_t* str)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* DAMN UGLY: See comment in hawk_sio_putuchars() */
 | |
| 	if (sio->status & STATUS_UTF8_CONSOLE)
 | |
| 	{
 | |
| 		DWORD count, left;
 | |
| 		const hawk_uch_t* cur;
 | |
| 
 | |
| 		if (hawk_sio_flush (sio) <= -1) return -1; /* can't do buffering */
 | |
| 
 | |
| 		for (cur = str, left = hawk_count_ucstr(str); left > 0; cur += count, left -= count)
 | |
| 		{
 | |
| 			if (WriteConsoleW(sio->file.handle, cur, left, &count, HAWK_NULL) == FALSE)
 | |
| 			{
 | |
| 				hawk_gem_seterrnum (sio->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 				return -1;
 | |
| 			}
 | |
| 			if (count == 0) break;
 | |
| 
 | |
| 			if (count > left)
 | |
| 			{
 | |
| 				hawk_gem_seterrnum (sio->gem, HAWK_NULL, HAWK_ESYSERR);
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 		return cur - str;
 | |
| 	}
 | |
| #elif defined(__OS2__)
 | |
| 	if (sio->status & STATUS_LINE_BREAK)
 | |
| 	{
 | |
| 		LOCK_OUTPUT (sio);
 | |
| 		for (n = 0; n < HAWK_TYPE_MAX(hawk_ooi_t) && str[n] != '\0'; n++)
 | |
| 		{
 | |
| 			if (put_uchar_no_mutex(sio, str[n]) <= -1)
 | |
| 			{
 | |
| 				n = -1;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		UNLOCK_OUTPUT (sio);
 | |
| 		return n;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = hawk_tio_writeuchars(&sio->tio.io, str, (hawk_oow_t)-1);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_ooi_t hawk_sio_putuchars (hawk_sio_t* sio, const hawk_uch_t* str, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_ooi_t n;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	/* DAMN UGLY:
 | |
| 	 *  WriteFile returns wrong number of bytes written if it is
 | |
| 	 *  requested to write a utf8 string on utf8 console (codepage 65001).
 | |
| 	 *  it seems to return a number of characters written instead. so
 | |
| 	 *  i have to use an alternate API for console output for
 | |
| 	 *  wide-character strings. Conversion to either an OEM codepage or
 | |
| 	 *  the utf codepage is handled by the API. This hack at least
 | |
| 	 *  lets you do proper utf8 output on utf8 console using wide-character.
 | |
| 	 *
 | |
| 	 *  Note that the multibyte functions hawk_sio_putbcstr() and
 | |
| 	 *  hawk_sio_putbchars() doesn't handle this. So you may still suffer.
 | |
| 	 */
 | |
| 	if (sio->status & STATUS_UTF8_CONSOLE)
 | |
| 	{
 | |
| 		DWORD count, left;
 | |
| 		const hawk_uch_t* cur;
 | |
| 
 | |
| 		if (hawk_sio_flush (sio) <= -1) return -1; /* can't do buffering */
 | |
| 
 | |
| 		for (cur = str, left = size; left > 0; cur += count, left -= count)
 | |
| 		{
 | |
| 			if (WriteConsoleW(sio->file.handle, cur, left, &count, HAWK_NULL) == FALSE)
 | |
| 			{
 | |
| 				hawk_gem_seterrnum (sio->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
 | |
| 				return -1;
 | |
| 			}
 | |
| 			if (count == 0) break;
 | |
| 
 | |
| 			/* Note:
 | |
| 			 * WriteConsoleW() in unicosw.dll on win 9x/me returns
 | |
| 			 * the number of bytes via 'count'. If a double byte
 | |
| 			 * string is given, 'count' can be greater than 'left'.
 | |
| 			 * this case is a miserable failure. however, i don't
 | |
| 			 * think there is CP_UTF8 codepage for console on win9x/me.
 | |
| 			 * so let me make this function fail if that ever happens.
 | |
| 			 */
 | |
| 			if (count > left)
 | |
| 			{
 | |
| 				hawk_gem_seterrnum (sio->gem, HAWK_NULL, HAWK_ESYSERR);
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 		return cur - str;
 | |
| 	}
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 	if (sio->status & STATUS_LINE_BREAK)
 | |
| 	{
 | |
| 		if (size > HAWK_TYPE_MAX(hawk_ooi_t)) size = HAWK_TYPE_MAX(hawk_ooi_t);
 | |
| 		LOCK_OUTPUT (sio);
 | |
| 		for (n = 0; n < size; n++)
 | |
| 		{
 | |
| 			if (put_uchar_no_mutex(sio, str[n]) <= -1)
 | |
| 			{
 | |
| 				n = -1;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		UNLOCK_OUTPUT (sio);
 | |
| 		return n;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	LOCK_OUTPUT (sio);
 | |
| 	n = hawk_tio_writeuchars(&sio->tio.io, str, size);
 | |
| 	UNLOCK_OUTPUT (sio);
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| int hawk_sio_getpos (hawk_sio_t* sio, hawk_sio_pos_t* pos)
 | |
| {
 | |
| 	hawk_fio_off_t off;
 | |
| 
 | |
| 	if (hawk_sio_flush(sio) <= -1) return -1;
 | |
| 
 | |
| 	off = hawk_fio_seek(&sio->file, 0, HAWK_FIO_CURRENT);
 | |
| 	if (off == (hawk_fio_off_t)-1) return -1;
 | |
| 
 | |
| 	*pos = off;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hawk_sio_setpos (hawk_sio_t* sio, hawk_sio_pos_t pos)
 | |
| {
 | |
| 	hawk_fio_off_t off;
 | |
| 
 | |
| 	if (hawk_sio_flush(sio) <= -1) return -1;
 | |
| 
 | |
| 	off = hawk_fio_seek(&sio->file, pos, HAWK_FIO_BEGIN);
 | |
| 	if (off == (hawk_fio_off_t)-1) return -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hawk_sio_truncate (hawk_sio_t* sio, hawk_sio_pos_t pos)
 | |
| {
 | |
| 	if (hawk_sio_flush(sio) <= -1) return -1;
 | |
| 	return hawk_fio_truncate(&sio->file, pos);
 | |
| }
 | |
| 
 | |
| int hawk_sio_seek (hawk_sio_t* sio, hawk_sio_pos_t* pos, hawk_sio_ori_t origin)
 | |
| {
 | |
| 	hawk_fio_off_t x;
 | |
| 
 | |
| 	if (hawk_sio_flush(sio) <= -1) return -1;
 | |
| 	x = hawk_fio_seek(&sio->file, *pos, origin);
 | |
| 	if (x == (hawk_fio_off_t)-1) return -1;
 | |
| 
 | |
| 	*pos = x;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static hawk_ooi_t file_input (hawk_tio_t* tio, hawk_tio_cmd_t cmd, void* buf, hawk_oow_t size)
 | |
| {
 | |
| 	if (cmd == HAWK_TIO_DATA)
 | |
| 	{
 | |
| 		hawk_sio_t* sio;
 | |
| 
 | |
| 		sio = *(hawk_sio_t**)(tio + 1);
 | |
| 		/*HAWK_ASSERT (tio->hawk, sio != HAWK_NULL);
 | |
| 		HAWK_ASSERT (tio->hawk, tio->hawk == sio->hawk);*/
 | |
| 
 | |
| 		return hawk_fio_read(&sio->file, buf, size);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static hawk_ooi_t file_output (hawk_tio_t* tio, hawk_tio_cmd_t cmd, void* buf, hawk_oow_t size)
 | |
| {
 | |
| 	if (cmd == HAWK_TIO_DATA)
 | |
| 	{
 | |
| 		hawk_sio_t* sio;
 | |
| 
 | |
| 		sio = *(hawk_sio_t**)(tio + 1);
 | |
| 		/*HAWK_ASSERT (tio->hawk, sio != HAWK_NULL);
 | |
| 		HAWK_ASSERT (tio->hawk, tio->hawk == sio->hawk);*/
 | |
| 
 | |
| 		return hawk_fio_write(&sio->file, buf, size);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 |