qse/qse/lib/cmn/stdio.c

479 lines
8.6 KiB
C
Raw Normal View History

/*
2008-12-10 00:52:03 +00:00
* $Id: stdio.c 463 2008-12-09 06:52:03Z baconevi $
*
2009-06-04 15:50:32 +00:00
Copyright 2006-2009 Chung, Hyung-Hwan.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
2009-06-04 15:50:32 +00:00
#include <qse/cmn/stdio.h>
#include <qse/cmn/chr.h>
#include <wchar.h>
#include <stdlib.h>
#include <limits.h>
#ifndef PATH_MAX
#define PATH_MAX 2048
#endif
#if defined(_WIN32)
2008-12-21 21:35:07 +00:00
int qse_vsprintf (qse_char_t* buf, size_t size, const qse_char_t* fmt, va_list ap)
{
int n;
2008-12-21 21:35:07 +00:00
#ifdef QSE_CHAR_IS_MCHAR
2008-12-10 00:52:03 +00:00
n = _vsnprintf (buf, size, fmt, ap);
#else
n = _vsnwprintf (buf, size, fmt, ap);
#endif
if (n < 0 || (size_t)n >= size)
{
2008-12-21 21:35:07 +00:00
if (size > 0) buf[size-1] = QSE_T('\0');
n = -1;
}
return n;
}
2008-12-21 21:35:07 +00:00
int qse_sprintf (qse_char_t* buf, size_t size, const qse_char_t* fmt, ...)
{
int n;
va_list ap;
va_start (ap, fmt);
2008-12-21 21:35:07 +00:00
n = qse_vsprintf (buf, size, fmt, ap);
va_end (ap);
return n;
}
#else
2008-12-21 21:35:07 +00:00
static qse_char_t* __adjust_format (const qse_char_t* format);
2008-12-21 21:35:07 +00:00
int qse_vfprintf (QSE_FILE *stream, const qse_char_t* fmt, va_list ap)
{
int n;
2008-12-21 21:35:07 +00:00
qse_char_t* nf = __adjust_format (fmt);
if (nf == NULL) return -1;
2008-12-21 21:35:07 +00:00
#ifdef QSE_CHAR_IS_MCHAR
n = vfprintf (stream, nf, ap);
#else
n = vfwprintf (stream, nf, ap);
#endif
free (nf);
return n;
}
2008-12-21 21:35:07 +00:00
int qse_vprintf (const qse_char_t* fmt, va_list ap)
{
2008-12-21 21:35:07 +00:00
return qse_vfprintf (stdout, fmt, ap);
}
2008-12-21 21:35:07 +00:00
int qse_fprintf (QSE_FILE* file, const qse_char_t* fmt, ...)
{
int n;
va_list ap;
va_start (ap, fmt);
2008-12-21 21:35:07 +00:00
n = qse_vfprintf (file, fmt, ap);
va_end (ap);
return n;
}
2008-12-21 21:35:07 +00:00
int qse_printf (const qse_char_t* fmt, ...)
{
int n;
va_list ap;
va_start (ap, fmt);
2008-12-21 21:35:07 +00:00
n = qse_vprintf (fmt, ap);
va_end (ap);
return n;
}
2008-12-21 21:35:07 +00:00
int qse_vsprintf (qse_char_t* buf, size_t size, const qse_char_t* fmt, va_list ap)
{
int n;
2008-12-21 21:35:07 +00:00
qse_char_t* nf = __adjust_format (fmt);
if (nf == NULL) return -1;
2008-12-21 21:35:07 +00:00
#if defined(QSE_CHAR_IS_MCHAR)
n = vsnprintf (buf, size, nf, ap);
#elif defined(_WIN32)
n = _vsnwprintf (buf, size, nf, ap);
#else
n = vswprintf (buf, size, nf, ap);
#endif
if (n < 0 || (size_t)n >= size)
{
2008-12-21 21:35:07 +00:00
if (size > 0) buf[size-1] = QSE_T('\0');
n = -1;
}
free (nf);
return n;
}
2008-12-21 21:35:07 +00:00
int qse_sprintf (qse_char_t* buf, size_t size, const qse_char_t* fmt, ...)
{
int n;
va_list ap;
va_start (ap, fmt);
2008-12-21 21:35:07 +00:00
n = qse_vsprintf (buf, size, fmt, ap);
va_end (ap);
return n;
}
#define MOD_SHORT 1
#define MOD_LONG 2
#define MOD_LONGLONG 3
#define ADDC(buf,c) \
do { \
if (buf.len >= buf.cap) \
{ \
2008-12-21 21:35:07 +00:00
qse_char_t* tmp; \
tmp = (qse_char_t*)realloc ( \
buf.ptr, sizeof(qse_char_t)*(buf.cap+256+1)); \
if (tmp == NULL) \
{ \
free (buf.ptr); \
return NULL; \
} \
buf.ptr = tmp; \
buf.cap = buf.cap + 256; \
} \
buf.ptr[buf.len++] = c; \
} while (0)
2008-12-21 21:35:07 +00:00
static qse_char_t* __adjust_format (const qse_char_t* format)
{
2008-12-21 21:35:07 +00:00
const qse_char_t* fp = format;
int modifier;
2008-12-21 21:35:07 +00:00
qse_char_t ch;
struct
{
2008-12-21 21:35:07 +00:00
qse_char_t* ptr;
qse_size_t len;
qse_size_t cap;
} buf;
buf.len = 0;
buf.cap = 256;
2008-12-21 21:35:07 +00:00
#if (defined(vms) || defined(__vms)) && (QSE_SIZEOF_VOID_P >= 8)
buf.ptr = (qse_char_t*) _malloc32 (sizeof(qse_char_t)*(buf.cap+1));
#else
2008-12-21 21:35:07 +00:00
buf.ptr = (qse_char_t*) malloc (sizeof(qse_char_t)*(buf.cap+1));
#endif
if (buf.ptr == NULL) return NULL;
2008-12-21 21:35:07 +00:00
while (*fp != QSE_T('\0'))
{
2008-12-21 21:35:07 +00:00
while (*fp != QSE_T('\0') && *fp != QSE_T('%'))
{
ADDC (buf, *fp++);
}
2008-12-21 21:35:07 +00:00
if (*fp == QSE_T('\0')) break;
ch = *fp++;
ADDC (buf, ch); /* add % */
ch = *fp++;
/* flags */
while (1)
{
2008-12-21 21:35:07 +00:00
if (ch == QSE_T(' ') || ch == QSE_T('+') ||
ch == QSE_T('-') || ch == QSE_T('#'))
{
ADDC (buf, ch);
ch = *fp++;
}
else
{
2008-12-21 21:35:07 +00:00
if (ch == QSE_T('0'))
{
ADDC (buf, ch);
ch = *fp++;
}
break;
}
}
/* check the width */
2008-12-21 21:35:07 +00:00
if (ch == QSE_T('*'))
{
ADDC (buf, ch);
ch = *fp++;
}
else
{
2008-12-21 21:35:07 +00:00
while (QSE_ISDIGIT(ch))
{
ADDC (buf, ch);
ch = *fp++;
}
}
/* precision */
2008-12-21 21:35:07 +00:00
if (ch == QSE_T('.'))
{
ADDC (buf, ch);
ch = *fp++;
2008-12-21 21:35:07 +00:00
if (ch == QSE_T('*'))
{
ADDC (buf, ch);
ch = *fp++;
}
else
{
2008-12-21 21:35:07 +00:00
while (QSE_ISDIGIT(ch))
{
ADDC (buf, ch);
ch = *fp++;
}
}
}
/* modifier */
for (modifier = 0;;)
{
2008-12-21 21:35:07 +00:00
if (ch == QSE_T('h')) modifier = MOD_SHORT;
else if (ch == QSE_T('l'))
{
modifier = (modifier == MOD_LONG)? MOD_LONGLONG: MOD_LONG;
}
else break;
ch = *fp++;
}
/* type */
2008-12-21 21:35:07 +00:00
if (ch == QSE_T('%')) ADDC (buf, ch);
else if (ch == QSE_T('c') || ch == QSE_T('s'))
{
2008-12-21 21:35:07 +00:00
#if !defined(QSE_CHAR_IS_MCHAR) && !defined(_WIN32)
ADDC (buf, 'l');
#endif
ADDC (buf, ch);
}
2008-12-21 21:35:07 +00:00
else if (ch == QSE_T('C') || ch == QSE_T('S'))
{
#if defined(_WIN32)
ADDC (buf, ch);
#else
2008-12-21 21:35:07 +00:00
#ifdef QSE_CHAR_IS_MCHAR
ADDC (buf, 'l');
#endif
2008-12-21 21:35:07 +00:00
ADDC (buf, QSE_TOLOWER(ch));
#endif
}
2008-12-21 21:35:07 +00:00
else if (ch == QSE_T('d') || ch == QSE_T('i') ||
ch == QSE_T('o') || ch == QSE_T('u') ||
ch == QSE_T('x') || ch == QSE_T('X'))
{
if (modifier == MOD_SHORT)
{
ADDC (buf, 'h');
}
else if (modifier == MOD_LONG)
{
ADDC (buf, 'l');
}
else if (modifier == MOD_LONGLONG)
{
#if defined(_WIN32) && !defined(__LCC__)
ADDC (buf, 'I');
ADDC (buf, '6');
ADDC (buf, '4');
#else
ADDC (buf, 'l');
ADDC (buf, 'l');
#endif
}
ADDC (buf, ch);
}
2008-12-21 21:35:07 +00:00
else if (ch == QSE_T('\0')) break;
else ADDC (buf, ch);
}
2008-12-21 21:35:07 +00:00
buf.ptr[buf.len] = QSE_T('\0');
return buf.ptr;
}
#endif
2008-12-21 21:35:07 +00:00
int qse_dprintf (const qse_char_t* fmt, ...)
{
int n;
va_list ap;
va_start (ap, fmt);
2008-12-21 21:35:07 +00:00
n = qse_vfprintf (stderr, fmt, ap);
va_end (ap);
return n;
}
2008-12-21 21:35:07 +00:00
QSE_FILE* qse_fopen (const qse_char_t* path, const qse_char_t* mode)
{
2008-12-21 21:35:07 +00:00
#if defined(QSE_CHAR_IS_MCHAR)
return fopen (path, mode);
2008-12-10 00:52:03 +00:00
#elif defined(_WIN32)
return _wfopen (path, mode);
#else
char path_mb[PATH_MAX + 1];
char mode_mb[32];
size_t n;
2008-12-21 21:35:07 +00:00
n = wcstombs (path_mb, path, QSE_COUNTOF(path_mb));
if (n == (size_t)-1) return NULL;
2008-12-21 21:35:07 +00:00
if (n == QSE_COUNTOF(path_mb)) path_mb[QSE_COUNTOF(path_mb)-1] = '\0';
2008-12-21 21:35:07 +00:00
n = wcstombs (mode_mb, mode, QSE_COUNTOF(mode_mb));
if (n == (size_t)-1) return NULL;
2008-12-21 21:35:07 +00:00
if (n == QSE_COUNTOF(mode_mb)) path_mb[QSE_COUNTOF(mode_mb)-1] = '\0';
return fopen (path_mb, mode_mb);
#endif
}
2008-12-21 21:35:07 +00:00
QSE_FILE* qse_popen (const qse_char_t* cmd, const qse_char_t* mode)
{
2008-12-21 21:35:07 +00:00
#if defined(QSE_CHAR_IS_MCHAR)
return popen (cmd, mode);
2008-12-10 00:52:03 +00:00
#elif defined(_WIN32)
return _wpopen (cmd, mode);
#else
char cmd_mb[PATH_MAX + 1];
char mode_mb[32];
size_t n;
2008-12-21 21:35:07 +00:00
n = wcstombs (cmd_mb, cmd, QSE_COUNTOF(cmd_mb));
if (n == (size_t)-1) return NULL;
2008-12-21 21:35:07 +00:00
if (n == QSE_COUNTOF(cmd_mb)) cmd_mb[QSE_COUNTOF(cmd_mb)-1] = '\0';
2008-12-21 21:35:07 +00:00
n = wcstombs (mode_mb, mode, QSE_COUNTOF(mode_mb));
if (n == (size_t)-1) return NULL;
2008-12-21 21:35:07 +00:00
if (n == QSE_COUNTOF(mode_mb)) cmd_mb[QSE_COUNTOF(mode_mb)-1] = '\0';
return popen (cmd_mb, mode_mb);
#endif
}
2008-12-21 21:35:07 +00:00
static int isnl (const qse_char_t* ptr, qse_size_t len, void* delim)
2008-03-13 05:55:39 +00:00
{
2008-12-21 21:35:07 +00:00
return (ptr[len-1] == *(qse_char_t*)delim)? 1: 0;
2008-03-19 02:02:12 +00:00
}
2008-12-21 21:35:07 +00:00
qse_ssize_t qse_getline (qse_char_t **buf, qse_size_t *n, QSE_FILE *fp)
2008-03-19 02:02:12 +00:00
{
2008-12-21 21:35:07 +00:00
qse_char_t nl = QSE_T('\n');
return qse_getdelim (buf, n, isnl, &nl, fp);
2008-03-13 05:55:39 +00:00
}
2008-12-21 21:35:07 +00:00
qse_ssize_t qse_getdelim (
qse_char_t **buf, qse_size_t *n,
qse_getdelim_t fn, void* fnarg, QSE_FILE *fp)
2008-03-13 05:55:39 +00:00
{
2008-12-21 21:35:07 +00:00
qse_char_t* b;
qse_size_t capa;
qse_size_t len = 0;
2008-03-19 02:02:12 +00:00
int x;
2008-03-13 05:55:39 +00:00
2008-12-21 21:35:07 +00:00
QSE_ASSERT (buf != QSE_NULL);
QSE_ASSERT (n != QSE_NULL);
2008-03-13 05:55:39 +00:00
b = *buf;
capa = *n;
2008-12-21 21:35:07 +00:00
if (b == QSE_NULL)
2008-03-13 05:55:39 +00:00
{
capa = 256;
2008-12-21 21:35:07 +00:00
#if (defined(vms) || defined(__vms)) && (QSE_SIZEOF_VOID_P >= 8)
b = (qse_char_t*) _malloc32 (sizeof(qse_char_t)*(capa+1));
2008-12-10 00:52:03 +00:00
#else
2008-12-21 21:35:07 +00:00
b = (qse_char_t*) malloc (sizeof(qse_char_t)*(capa+1));
2008-12-10 00:52:03 +00:00
#endif
2008-12-21 21:35:07 +00:00
if (b == QSE_NULL) return -2;
2008-03-13 05:55:39 +00:00
}
2008-12-21 21:35:07 +00:00
if (qse_feof(fp))
2008-03-13 06:21:33 +00:00
{
2008-12-21 21:35:07 +00:00
len = (qse_size_t)-1;
2008-03-13 06:21:33 +00:00
goto exit_task;
}
2008-03-13 05:55:39 +00:00
while (1)
{
2008-12-21 21:35:07 +00:00
qse_cint_t c = qse_fgetc(fp);
if (c == QSE_CHAR_EOF)
2008-03-13 05:55:39 +00:00
{
2008-12-21 21:35:07 +00:00
if (qse_ferror(fp))
2008-03-13 06:25:11 +00:00
{
2008-12-21 21:35:07 +00:00
len = (qse_size_t)-2;
2008-03-13 06:25:11 +00:00
goto exit_task;
}
if (len == 0)
2008-03-13 05:55:39 +00:00
{
2008-12-21 21:35:07 +00:00
len = (qse_size_t)-1;
2008-03-13 05:55:39 +00:00
goto exit_task;
}
break;
}
if (len+1 >= capa)
{
2008-12-21 21:35:07 +00:00
qse_size_t ncapa = capa + 256;
qse_char_t* nb;
2008-03-13 05:55:39 +00:00
2008-12-21 21:35:07 +00:00
nb = realloc (b, ncapa*sizeof(qse_char_t));
if (nb == QSE_NULL)
2008-03-13 05:55:39 +00:00
{
2008-12-21 21:35:07 +00:00
len = (qse_size_t)-2;
2008-03-13 05:55:39 +00:00
goto exit_task;
}
b = nb;
capa = ncapa;
}
b[len++] = c;
2008-03-19 02:02:12 +00:00
2008-03-19 02:26:52 +00:00
x = fn (b, len, fnarg);
2008-03-19 02:02:12 +00:00
if (x < 0)
{
2008-12-21 21:35:07 +00:00
len = (qse_size_t)-3;
2008-03-19 02:02:12 +00:00
goto exit_task;
}
if (x > 0) break;
2008-03-13 05:55:39 +00:00
}
2008-12-21 21:35:07 +00:00
b[len] = QSE_T('\0');
2008-03-13 05:55:39 +00:00
exit_task:
*buf = b;
*n = capa;
2008-12-21 21:35:07 +00:00
return (qse_ssize_t)len;
2008-03-13 05:55:39 +00:00
}