2019-12-13 04:29:58 +00:00
|
|
|
/*
|
2020-04-16 03:42:30 +00:00
|
|
|
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_sio_t* hawk_sio_open (hawk_gem_t* gem, hawk_oow_t xtnsize, const hawk_ooch_t* file, int flags)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
hawk_sio_t* sio;
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
sio = (hawk_sio_t*)hawk_gem_allocmem(gem, HAWK_SIZEOF(hawk_sio_t) + xtnsize);
|
2019-12-13 04:29:58 +00:00
|
|
|
if (sio)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
if (hawk_sio_init(sio, gem, file, flags) <= -1)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_gem_freemem (gem, sio);
|
2019-12-13 04:29:58 +00:00
|
|
|
return HAWK_NULL;
|
|
|
|
}
|
|
|
|
else HAWK_MEMSET (sio + 1, 0, xtnsize);
|
|
|
|
}
|
|
|
|
return sio;
|
|
|
|
}
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_sio_t* hawk_sio_openstd (hawk_gem_t* gem, hawk_oow_t xtnsize, hawk_sio_std_t std, int flags)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
hawk_sio_t* sio;
|
|
|
|
hawk_fio_hnd_t hnd;
|
|
|
|
|
|
|
|
/* Is this necessary?
|
|
|
|
if (flags & HAWK_SIO_KEEPATH)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_gem_seterrnum (gem, HAWK_NULL, HAWK_EINVAL);
|
2019-12-13 04:29:58 +00:00
|
|
|
return HAWK_NULL;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (hawk_get_std_fio_handle(std, &hnd) <= -1) return HAWK_NULL;
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
sio = hawk_sio_open(gem, xtnsize, (const hawk_ooch_t*)&hnd, flags | HAWK_SIO_HANDLE | HAWK_SIO_NOCLOSE);
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (sio)
|
|
|
|
{
|
|
|
|
DWORD mode;
|
2019-12-18 05:15:03 +00:00
|
|
|
if (GetConsoleMode(sio->file.handle, &mode) == TRUE && GetConsoleOutputCP() == CP_UTF8)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
sio->status |= STATUS_UTF8_CONSOLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return sio;
|
|
|
|
}
|
|
|
|
|
2022-06-10 08:53:42 +00:00
|
|
|
|
2019-12-13 04:29:58 +00:00
|
|
|
void hawk_sio_close (hawk_sio_t* sio)
|
|
|
|
{
|
|
|
|
hawk_sio_fini (sio);
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_gem_freemem (sio->gem, sio);
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
int hawk_sio_init (hawk_sio_t* sio, hawk_gem_t* gem, const hawk_ooch_t* path, int flags)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
int mode;
|
|
|
|
int topt = 0;
|
|
|
|
|
|
|
|
HAWK_MEMSET (sio, 0, HAWK_SIZEOF(*sio));
|
2019-12-18 05:15:03 +00:00
|
|
|
sio->gem = gem;
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
mode = HAWK_FIO_RUSR | HAWK_FIO_WUSR | HAWK_FIO_RGRP | HAWK_FIO_ROTH;
|
|
|
|
|
|
|
|
if (flags & HAWK_SIO_REENTRANT)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
sio->mtx = hawk_mtx_open(gem, 0);
|
2019-12-13 04:29:58 +00:00
|
|
|
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. */
|
2019-12-18 05:15:03 +00:00
|
|
|
if (hawk_fio_init(&sio->file, gem, path, (flags & ~HAWK_FIO_RESERVED), mode) <= -1) goto oops01;
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2022-03-31 17:14:52 +00:00
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
2019-12-18 05:15:03 +00:00
|
|
|
sio->path = hawk_gem_dupoocstr(gem, path, HAWK_NULL);
|
2022-03-31 17:14:52 +00:00
|
|
|
#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
|
2019-12-18 05:15:03 +00:00
|
|
|
if (sio->path == HAWK_NULL) goto oops02;
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
if (hawk_tio_init(&sio->tio.io, gem, topt) <= -1) goto oops03;
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
/* store the back-reference to sio in the extension area.*/
|
2019-12-18 05:15:03 +00:00
|
|
|
/*HAWK_ASSERT (hawk, (&sio->tio.io + 1) == &sio->tio.xtn);*/
|
2019-12-13 04:29:58 +00:00
|
|
|
*(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:
|
2019-12-18 05:15:03 +00:00
|
|
|
if (sio->path) hawk_gem_freemem (sio->gem, sio->path);
|
2019-12-13 04:29:58 +00:00
|
|
|
oops02:
|
|
|
|
hawk_fio_fini (&sio->file);
|
|
|
|
oops01:
|
|
|
|
if (sio->mtx) hawk_mtx_close (sio->mtx);
|
|
|
|
oops00:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
int hawk_sio_initstd (hawk_sio_t* sio, hawk_gem_t* gem, hawk_sio_std_t std, int flags)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
hawk_fio_hnd_t hnd;
|
|
|
|
|
2022-03-31 17:14:52 +00:00
|
|
|
if (hawk_get_std_fio_handle(std, &hnd) <= -1) return -1;
|
2019-12-13 04:29:58 +00:00
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
n = hawk_sio_init(sio, gem, (const hawk_ooch_t*)&hnd, flags | HAWK_SIO_HANDLE | HAWK_SIO_NOCLOSE);
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (n >= 0)
|
|
|
|
{
|
|
|
|
DWORD mode;
|
2019-12-18 05:15:03 +00:00
|
|
|
if (GetConsoleMode (sio->file.handle, &mode) == TRUE && GetConsoleOutputCP() == CP_UTF8)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
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);
|
2019-12-18 05:15:03 +00:00
|
|
|
if (sio->path) hawk_gem_freemem (sio->gem, sio->path);
|
2019-12-13 04:29:58 +00:00
|
|
|
if (sio->mtx) hawk_mtx_close (sio->mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
hawk_cmgr_t* hawk_sio_getcmgr (hawk_sio_t* sio)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
return hawk_tio_getcmgr(&sio->tio.io);
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
/*return hawk_fio_gethnd(&sio->file);*/
|
2019-12-13 04:29:58 +00:00
|
|
|
return HAWK_FIO_HANDLE(&sio->file);
|
|
|
|
}
|
|
|
|
|
|
|
|
const hawk_ooch_t* hawk_sio_getpath (hawk_sio_t* sio)
|
|
|
|
{
|
2022-03-31 17:14:52 +00:00
|
|
|
/* 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. */
|
2019-12-13 04:29:58 +00:00
|
|
|
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);
|
2019-12-18 05:15:03 +00:00
|
|
|
if (n <= -1) return -1;
|
2019-12-13 04:29:58 +00:00
|
|
|
UNLOCK_INPUT (sio);
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
buf[n] = '\0';
|
2019-12-13 04:29:58 +00:00
|
|
|
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);
|
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
buf[n] = '\0';
|
2019-12-13 04:29:58 +00:00
|
|
|
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__)
|
2019-12-18 05:15:03 +00:00
|
|
|
if (c == '\n' && (sio->status & STATUS_LINE_BREAK))
|
|
|
|
n = hawk_tio_writebchars(&sio->tio.io, "\r\n", 2);
|
2019-12-13 04:29:58 +00:00
|
|
|
else
|
2019-12-18 05:15:03 +00:00
|
|
|
n = hawk_tio_writebchars(&sio->tio.io, &c, 1);
|
2019-12-13 04:29:58 +00:00
|
|
|
#else
|
2019-12-18 05:15:03 +00:00
|
|
|
n = hawk_tio_writebchars(&sio->tio.io, &c, 1);
|
2019-12-13 04:29:58 +00:00
|
|
|
#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__)
|
2019-12-18 05:15:03 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-12-13 04:29:58 +00:00
|
|
|
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);
|
2019-12-18 05:15:03 +00:00
|
|
|
for (n = 0; n < HAWK_TYPE_MAX(hawk_ooi_t) && str[n] != '\0'; n++)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
if ((n = putbc_no_mutex(sio, str[n])) <= -1)
|
|
|
|
{
|
|
|
|
n = -1;
|
|
|
|
break;
|
|
|
|
}
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
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++)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
if (putbc_no_mutex(sio, str[n]) <= -1)
|
|
|
|
{
|
|
|
|
n = -1;
|
|
|
|
break;
|
|
|
|
}
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
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 */
|
|
|
|
|
2019-12-18 08:16:34 +00:00
|
|
|
for (cur = str, left = hawk_count_ucstr(str); left > 0; cur += count, left -= count)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
|
|
|
if (WriteConsoleW(sio->file.handle, cur, left, &count, HAWK_NULL) == FALSE)
|
|
|
|
{
|
2020-01-01 05:20:28 +00:00
|
|
|
hawk_gem_seterrnum (sio->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
|
2019-12-13 04:29:58 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (count == 0) break;
|
|
|
|
|
|
|
|
if (count > left)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_gem_seterrnum (sio->gem, HAWK_NULL, HAWK_ESYSERR);
|
2019-12-13 04:29:58 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cur - str;
|
|
|
|
}
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
if (sio->status & STATUS_LINE_BREAK)
|
|
|
|
{
|
|
|
|
LOCK_OUTPUT (sio);
|
2019-12-18 05:15:03 +00:00
|
|
|
for (n = 0; n < HAWK_TYPE_MAX(hawk_ooi_t) && str[n] != '\0'; n++)
|
2019-12-13 04:29:58 +00:00
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
if (put_uchar_no_mutex(sio, str[n]) <= -1)
|
|
|
|
{
|
|
|
|
n = -1;
|
|
|
|
break;
|
|
|
|
}
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2020-01-01 05:20:28 +00:00
|
|
|
hawk_gem_seterrnum (sio->gem, HAWK_NULL, hawk_syserr_to_errnum(GetLastError()));
|
2019-12-13 04:29:58 +00:00
|
|
|
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)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
hawk_gem_seterrnum (sio->gem, HAWK_NULL, HAWK_ESYSERR);
|
2019-12-13 04:29:58 +00:00
|
|
|
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++)
|
|
|
|
{
|
2019-12-18 05:15:03 +00:00
|
|
|
if (put_uchar_no_mutex(sio, str[n]) <= -1)
|
|
|
|
{
|
|
|
|
n = -1;
|
|
|
|
break;
|
|
|
|
}
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
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);
|
2019-12-18 05:15:03 +00:00
|
|
|
if (off == (hawk_fio_off_t)-1) return -1;
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
*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);
|
2019-12-18 05:15:03 +00:00
|
|
|
if (off == (hawk_fio_off_t)-1) return -1;
|
2019-12-13 04:29:58 +00:00
|
|
|
|
|
|
|
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);
|
2019-12-18 05:15:03 +00:00
|
|
|
/*HAWK_ASSERT (tio->hawk, sio != HAWK_NULL);
|
|
|
|
HAWK_ASSERT (tio->hawk, tio->hawk == sio->hawk);*/
|
2019-12-13 04:29:58 +00:00
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
return hawk_fio_read(&sio->file, buf, size);
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2019-12-18 05:15:03 +00:00
|
|
|
/*HAWK_ASSERT (tio->hawk, sio != HAWK_NULL);
|
|
|
|
HAWK_ASSERT (tio->hawk, tio->hawk == sio->hawk);*/
|
2019-12-13 04:29:58 +00:00
|
|
|
|
2019-12-18 05:15:03 +00:00
|
|
|
return hawk_fio_write(&sio->file, buf, size);
|
2019-12-13 04:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|