ec30b0d5db
This is probably only a partial fix, but won’t hurt. Sentry-Id: FLIGHTGEAR-39N
649 lines
17 KiB
C
Executable file
649 lines
17 KiB
C
Executable file
/* ----------------------------------------------------------------- */
|
|
/* The HMM-Based Speech Synthesis Engine "hts_engine API" */
|
|
/* developed by HTS Working Group */
|
|
/* http://hts-engine.sourceforge.net/ */
|
|
/* ----------------------------------------------------------------- */
|
|
/* */
|
|
/* Copyright (c) 2001-2015 Nagoya Institute of Technology */
|
|
/* Department of Computer Science */
|
|
/* */
|
|
/* 2001-2008 Tokyo Institute of Technology */
|
|
/* Interdisciplinary Graduate School of */
|
|
/* Science and Engineering */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* Redistribution and use in source and binary forms, with or */
|
|
/* without modification, are permitted provided that the following */
|
|
/* conditions are met: */
|
|
/* */
|
|
/* - Redistributions of source code must retain the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer. */
|
|
/* - 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. */
|
|
/* - Neither the name of the HTS working group nor the names of its */
|
|
/* contributors may be used to endorse or promote products derived */
|
|
/* from this software without specific prior written permission. */
|
|
/* */
|
|
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND */
|
|
/* CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS */
|
|
/* 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. */
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
#ifndef HTS_MISC_C
|
|
#define HTS_MISC_C
|
|
|
|
#ifdef __cplusplus
|
|
#define HTS_MISC_C_START extern "C" {
|
|
#define HTS_MISC_C_END }
|
|
#else
|
|
#define HTS_MISC_C_START
|
|
#define HTS_MISC_C_END
|
|
#endif /* __CPLUSPLUS */
|
|
|
|
HTS_MISC_C_START;
|
|
|
|
#include <stdlib.h> /* for exit(),calloc(),free() */
|
|
#include <stdarg.h> /* for va_list */
|
|
#include <string.h> /* for strcpy(),strlen() */
|
|
|
|
/* hts_engine libraries */
|
|
#include "HTS_hidden.h"
|
|
|
|
#ifdef FESTIVAL
|
|
#include "EST_walloc.h"
|
|
#endif /* FESTIVAL */
|
|
|
|
#define HTS_FILE 0
|
|
#define HTS_DATA 1
|
|
|
|
typedef struct _HTS_Data {
|
|
unsigned char *data;
|
|
size_t size;
|
|
size_t index;
|
|
} HTS_Data;
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <windows.h>
|
|
|
|
#define MAX_PATH_SIZE 8192
|
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
|
|
|
// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
|
|
// wbuf and wbuf_len is a target buffer and its length.
|
|
static void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
|
|
char buf[MAX_PATH_SIZE * 2], buf2[MAX_PATH_SIZE * 2], *p;
|
|
|
|
strncpy(buf, path, sizeof(buf));
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
|
|
// Trim trailing slashes. Leave backslash for paths like "X:\"
|
|
p = buf + strlen(buf) - 1;
|
|
while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
|
|
|
|
// Convert to Unicode and back. If doubly-converted string does not
|
|
// match the original, something is fishy, reject.
|
|
memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
|
|
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
|
|
WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
|
|
NULL, NULL);
|
|
if (strcmp(buf, buf2) != 0) {
|
|
wbuf[0] = L'\0';
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* HTS_fopen_from_fn: wrapper for fopen */
|
|
HTS_File *HTS_fopen_from_fn(const char *name, const char *opt)
|
|
{
|
|
HTS_File *fp = (HTS_File *) HTS_calloc(1, sizeof(HTS_File));
|
|
|
|
fp->type = HTS_FILE;
|
|
#if defined(_WIN32)
|
|
wchar_t wpath[MAX_PATH_SIZE], wmode[10];
|
|
to_wchar(name, wpath, ARRAY_SIZE(wpath));
|
|
to_wchar(opt, wmode, ARRAY_SIZE(wmode));
|
|
fp->pointer = (void*) _wfopen(wpath, wmode);
|
|
#else
|
|
fp->pointer = (void *) fopen(name, opt);
|
|
#endif
|
|
if (fp->pointer == NULL) {
|
|
HTS_error(0, "HTS_fopen: Cannot open %s.\n", name);
|
|
HTS_free(fp);
|
|
return NULL;
|
|
}
|
|
|
|
return fp;
|
|
}
|
|
|
|
/* HTS_fopen_from_fp: wrapper for fopen */
|
|
HTS_File *HTS_fopen_from_fp(HTS_File * fp, size_t size)
|
|
{
|
|
if (fp == NULL || size == 0)
|
|
return NULL;
|
|
else if (fp->type == HTS_FILE) {
|
|
HTS_Data *d;
|
|
HTS_File *f;
|
|
d = (HTS_Data *) HTS_calloc(1, sizeof(HTS_Data));
|
|
d->data = (unsigned char *) HTS_calloc(size, sizeof(unsigned char));
|
|
d->size = size;
|
|
d->index = 0;
|
|
if (fread(d->data, sizeof(unsigned char), size, (FILE *) fp->pointer) != size) {
|
|
free(d->data);
|
|
free(d);
|
|
return NULL;
|
|
}
|
|
f = (HTS_File *) HTS_calloc(1, sizeof(HTS_File));
|
|
f->type = HTS_DATA;
|
|
f->pointer = (void *) d;
|
|
return f;
|
|
} else if (fp->type == HTS_DATA) {
|
|
HTS_File *f;
|
|
HTS_Data *tmp1, *tmp2;
|
|
tmp1 = (HTS_Data *) fp->pointer;
|
|
if (tmp1->index + size > tmp1->size)
|
|
return NULL;
|
|
tmp2 = (HTS_Data *) HTS_calloc(1, sizeof(HTS_Data));
|
|
tmp2->data = (unsigned char *) HTS_calloc(size, sizeof(unsigned char));
|
|
tmp2->size = size;
|
|
tmp2->index = 0;
|
|
memcpy(tmp2->data, &tmp1->data[tmp1->index], size);
|
|
tmp1->index += size;
|
|
f = (HTS_File *) HTS_calloc(1, sizeof(HTS_File));
|
|
f->type = HTS_DATA;
|
|
f->pointer = (void *) tmp2;
|
|
return f;
|
|
}
|
|
|
|
HTS_error(0, "HTS_fopen_from_fp: Unknown file type.\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* HTS_fopen_from_data: wrapper for fopen */
|
|
HTS_File *HTS_fopen_from_data(void *data, size_t size)
|
|
{
|
|
HTS_Data *d;
|
|
HTS_File *f;
|
|
|
|
if (data == NULL || size == 0)
|
|
return NULL;
|
|
|
|
d = (HTS_Data *) HTS_calloc(1, sizeof(HTS_Data));
|
|
d->data = (unsigned char *) HTS_calloc(size, sizeof(unsigned char));
|
|
d->size = size;
|
|
d->index = 0;
|
|
|
|
memcpy(d->data, data, size);
|
|
|
|
f = (HTS_File *) HTS_calloc(1, sizeof(HTS_File));
|
|
f->type = HTS_DATA;
|
|
f->pointer = (void *) d;
|
|
|
|
return f;
|
|
}
|
|
|
|
/* HTS_fclose: wrapper for fclose */
|
|
void HTS_fclose(HTS_File * fp)
|
|
{
|
|
if (fp == NULL) {
|
|
return;
|
|
} else if (fp->type == HTS_FILE) {
|
|
if (fp->pointer != NULL)
|
|
fclose((FILE *) fp->pointer);
|
|
HTS_free(fp);
|
|
return;
|
|
} else if (fp->type == HTS_DATA) {
|
|
if (fp->pointer != NULL) {
|
|
HTS_Data *d = (HTS_Data *) fp->pointer;
|
|
if (d->data != NULL)
|
|
HTS_free(d->data);
|
|
HTS_free(d);
|
|
}
|
|
HTS_free(fp);
|
|
return;
|
|
}
|
|
HTS_error(0, "HTS_fclose: Unknown file type.\n");
|
|
}
|
|
|
|
/* HTS_fgetc: wrapper for fgetc */
|
|
int HTS_fgetc(HTS_File * fp)
|
|
{
|
|
if (fp == NULL) {
|
|
return EOF;
|
|
} else if (fp->type == HTS_FILE) {
|
|
return fgetc((FILE *) fp->pointer);
|
|
} else if (fp->type == HTS_DATA) {
|
|
HTS_Data *d = (HTS_Data *) fp->pointer;
|
|
if (d->size <= d->index)
|
|
return EOF;
|
|
return (int) d->data[d->index++];
|
|
}
|
|
HTS_error(0, "HTS_fgetc: Unknown file type.\n");
|
|
return EOF;
|
|
}
|
|
|
|
/* HTS_feof: wrapper for feof */
|
|
int HTS_feof(HTS_File * fp)
|
|
{
|
|
if (fp == NULL) {
|
|
return 1;
|
|
} else if (fp->type == HTS_FILE) {
|
|
return feof((FILE *) fp->pointer);
|
|
} else if (fp->type == HTS_DATA) {
|
|
HTS_Data *d = (HTS_Data *) fp->pointer;
|
|
return d->size <= d->index ? 1 : 0;
|
|
}
|
|
HTS_error(0, "HTS_feof: Unknown file type.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* HTS_fseek: wrapper for fseek */
|
|
int HTS_fseek(HTS_File * fp, long offset, int origin)
|
|
{
|
|
if (fp == NULL) {
|
|
return 1;
|
|
} else if (fp->type == HTS_FILE) {
|
|
return fseek((FILE *) fp->pointer, offset, origin);
|
|
} else if (fp->type == HTS_DATA) {
|
|
HTS_Data *d = (HTS_Data *) fp->pointer;
|
|
if (origin == SEEK_SET) {
|
|
d->index = (size_t) offset;
|
|
} else if (origin == SEEK_CUR) {
|
|
d->index += offset;
|
|
} else if (origin == SEEK_END) {
|
|
d->index = d->size + offset;
|
|
} else {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
HTS_error(0, "HTS_fseek: Unknown file type.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* HTS_ftell: rapper for ftell */
|
|
size_t HTS_ftell(HTS_File * fp)
|
|
{
|
|
if (fp == NULL) {
|
|
return 0;
|
|
} else if (fp->type == HTS_FILE) {
|
|
fpos_t pos;
|
|
fgetpos((FILE *) fp->pointer, &pos);
|
|
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__) || defined(__OpenBSD__)
|
|
return (size_t) pos;
|
|
#else
|
|
return (size_t) pos.__pos;
|
|
#endif /* _WIN32 || __CYGWIN__ || __APPLE__ || __ANDROID__ */
|
|
} else if (fp->type == HTS_DATA) {
|
|
HTS_Data *d = (HTS_Data *) fp->pointer;
|
|
return d->index;
|
|
}
|
|
HTS_error(0, "HTS_ftell: Unknown file type.\n");
|
|
return 0;
|
|
}
|
|
|
|
/* HTS_fread: wrapper for fread */
|
|
static size_t HTS_fread(void *buf, size_t size, size_t n, HTS_File * fp)
|
|
{
|
|
if (fp == NULL || size == 0 || n == 0) {
|
|
return 0;
|
|
}
|
|
if (fp->type == HTS_FILE) {
|
|
return fread(buf, size, n, (FILE *) fp->pointer);
|
|
} else if (fp->type == HTS_DATA) {
|
|
HTS_Data *d = (HTS_Data *) fp->pointer;
|
|
size_t i, length = size * n;
|
|
unsigned char *c = (unsigned char *) buf;
|
|
for (i = 0; i < length; i++) {
|
|
if (d->index < d->size)
|
|
c[i] = d->data[d->index++];
|
|
else
|
|
break;
|
|
}
|
|
if (i == 0)
|
|
return 0;
|
|
else
|
|
return i / size;
|
|
}
|
|
HTS_error(0, "HTS_fread: Unknown file type.\n");
|
|
return 0;
|
|
}
|
|
|
|
/* HTS_byte_swap: byte swap */
|
|
static void HTS_byte_swap(void *p, size_t size, size_t block)
|
|
{
|
|
char *q, tmp;
|
|
size_t i, j;
|
|
|
|
q = (char *) p;
|
|
|
|
for (i = 0; i < block; i++) {
|
|
for (j = 0; j < (size / 2); j++) {
|
|
tmp = *(q + j);
|
|
*(q + j) = *(q + (size - 1 - j));
|
|
*(q + (size - 1 - j)) = tmp;
|
|
}
|
|
q += size;
|
|
}
|
|
}
|
|
|
|
/* HTS_fread_big_endian: fread with byteswap */
|
|
size_t HTS_fread_big_endian(void *buf, size_t size, size_t n, HTS_File * fp)
|
|
{
|
|
size_t block = HTS_fread(buf, size, n, fp);
|
|
|
|
#ifdef WORDS_LITTLEENDIAN
|
|
HTS_byte_swap(buf, size, block);
|
|
#endif /* WORDS_LITTLEENDIAN */
|
|
|
|
return block;
|
|
}
|
|
|
|
/* HTS_fread_little_endian: fread with byteswap */
|
|
size_t HTS_fread_little_endian(void *buf, size_t size, size_t n, HTS_File * fp)
|
|
{
|
|
size_t block = HTS_fread(buf, size, n, fp);
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
HTS_byte_swap(buf, size, block);
|
|
#endif /* WORDS_BIGENDIAN */
|
|
|
|
return block;
|
|
}
|
|
|
|
/* HTS_fwrite_little_endian: fwrite with byteswap */
|
|
size_t HTS_fwrite_little_endian(const void *buf, size_t size, size_t n, FILE * fp)
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
HTS_byte_swap(buf, size, n * size);
|
|
#endif /* WORDS_BIGENDIAN */
|
|
return fwrite(buf, size, n, fp);
|
|
}
|
|
|
|
/* HTS_get_pattern_token: get pattern token (single/double quote can be used) */
|
|
HTS_Boolean HTS_get_pattern_token(HTS_File * fp, char *buff)
|
|
{
|
|
char c;
|
|
size_t i;
|
|
HTS_Boolean squote = FALSE, dquote = FALSE;
|
|
|
|
if (fp == NULL || HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
|
|
while (c == ' ' || c == '\n') {
|
|
if (HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
}
|
|
|
|
if (c == '\'') { /* single quote case */
|
|
if (HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
squote = TRUE;
|
|
}
|
|
|
|
if (c == '\"') { /*double quote case */
|
|
if (HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
dquote = TRUE;
|
|
}
|
|
|
|
if (c == ',') { /*special character ',' */
|
|
strcpy(buff, ",");
|
|
return TRUE;
|
|
}
|
|
|
|
i = 0;
|
|
while (1) {
|
|
buff[i++] = c;
|
|
c = HTS_fgetc(fp);
|
|
if (squote && c == '\'')
|
|
break;
|
|
if (dquote && c == '\"')
|
|
break;
|
|
if (!squote && !dquote) {
|
|
if (c == ' ')
|
|
break;
|
|
if (c == '\n')
|
|
break;
|
|
if (HTS_feof(fp))
|
|
break;
|
|
}
|
|
}
|
|
|
|
buff[i] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
/* HTS_get_token: get token from file pointer (separators are space, tab, and line break) */
|
|
HTS_Boolean HTS_get_token_from_fp(HTS_File * fp, char *buff)
|
|
{
|
|
char c;
|
|
size_t i;
|
|
|
|
if (fp == NULL || HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
while (c == ' ' || c == '\n' || c == '\t') {
|
|
if (HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
if (c == EOF)
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; c != ' ' && c != '\n' && c != '\t';) {
|
|
buff[i++] = c;
|
|
if (HTS_feof(fp))
|
|
break;
|
|
c = HTS_fgetc(fp);
|
|
if (c == EOF)
|
|
break;
|
|
}
|
|
|
|
buff[i] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
/* HTS_get_token_with_separator: get token from file pointer with specified separator */
|
|
HTS_Boolean HTS_get_token_from_fp_with_separator(HTS_File * fp, char *buff, char separator)
|
|
{
|
|
char c;
|
|
size_t i;
|
|
|
|
if (fp == NULL || HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
while (c == separator) {
|
|
if (HTS_feof(fp))
|
|
return FALSE;
|
|
c = HTS_fgetc(fp);
|
|
if (c == EOF)
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; c != separator;) {
|
|
buff[i++] = c;
|
|
if (HTS_feof(fp))
|
|
break;
|
|
c = HTS_fgetc(fp);
|
|
if (c == EOF)
|
|
break;
|
|
}
|
|
|
|
buff[i] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
/* HTS_get_token_from_string: get token from string (separators are space, tab, and line break) */
|
|
HTS_Boolean HTS_get_token_from_string(const char *string, size_t * index, char *buff)
|
|
{
|
|
char c;
|
|
size_t i;
|
|
|
|
c = string[(*index)];
|
|
if (c == '\0')
|
|
return FALSE;
|
|
c = string[(*index)++];
|
|
if (c == '\0')
|
|
return FALSE;
|
|
while (c == ' ' || c == '\n' || c == '\t') {
|
|
if (c == '\0')
|
|
return FALSE;
|
|
c = string[(*index)++];
|
|
}
|
|
for (i = 0; c != ' ' && c != '\n' && c != '\t' && c != '\0'; i++) {
|
|
buff[i] = c;
|
|
c = string[(*index)++];
|
|
}
|
|
|
|
buff[i] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
/* HTS_get_token_from_string_with_separator: get token from string with specified separator */
|
|
HTS_Boolean HTS_get_token_from_string_with_separator(const char *str, size_t * index, char *buff, char separator)
|
|
{
|
|
char c;
|
|
size_t len = 0;
|
|
|
|
if (str == NULL)
|
|
return FALSE;
|
|
|
|
c = str[(*index)];
|
|
if (c == '\0')
|
|
return FALSE;
|
|
while (c == separator) {
|
|
if (c == '\0')
|
|
return FALSE;
|
|
(*index)++;
|
|
c = str[(*index)];
|
|
}
|
|
while (c != separator && c != '\0') {
|
|
buff[len++] = c;
|
|
(*index)++;
|
|
c = str[(*index)];
|
|
}
|
|
if (c != '\0')
|
|
(*index)++;
|
|
|
|
buff[len] = '\0';
|
|
|
|
if (len > 0)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/* HTS_calloc: wrapper for calloc */
|
|
void *HTS_calloc(const size_t num, const size_t size)
|
|
{
|
|
size_t n = num * size;
|
|
void *mem;
|
|
|
|
if (n == 0)
|
|
return NULL;
|
|
|
|
#ifdef FESTIVAL
|
|
mem = (void *) safe_wcalloc(n);
|
|
#else
|
|
mem = (void *) malloc(n);
|
|
#endif /* FESTIVAL */
|
|
if (mem == NULL) {
|
|
HTS_error(1, "HTS_calloc: Cannot allocate memory.\n");
|
|
}
|
|
|
|
memset(mem, 0, n);
|
|
return mem;
|
|
}
|
|
|
|
/* HTS_Free: wrapper for free */
|
|
void HTS_free(void *ptr)
|
|
{
|
|
#ifdef FESTIVAL
|
|
wfree(ptr);
|
|
#else
|
|
free(ptr);
|
|
#endif /* FESTIVAL */
|
|
}
|
|
|
|
/* HTS_strdup: wrapper for strdup */
|
|
char *HTS_strdup(const char *string)
|
|
{
|
|
#ifdef FESTIVAL
|
|
return (wstrdup(string));
|
|
#else
|
|
char *buff = (char *) HTS_calloc(strlen(string) + 1, sizeof(char));
|
|
strcpy(buff, string);
|
|
return buff;
|
|
#endif /* FESTIVAL */
|
|
}
|
|
|
|
/* HTS_alloc_matrix: allocate double matrix */
|
|
double **HTS_alloc_matrix(size_t x, size_t y)
|
|
{
|
|
size_t i;
|
|
double **p;
|
|
|
|
if (x == 0 || y == 0)
|
|
return NULL;
|
|
|
|
p = (double **) HTS_calloc(x, sizeof(double *));
|
|
|
|
for (i = 0; i < x; i++)
|
|
p[i] = (double *) HTS_calloc(y, sizeof(double));
|
|
return p;
|
|
}
|
|
|
|
/* HTS_free_matrix: free double matrix */
|
|
void HTS_free_matrix(double **p, size_t x)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < x; i++)
|
|
HTS_free(p[i]);
|
|
HTS_free(p);
|
|
}
|
|
|
|
/* HTS_error: output error message */
|
|
void HTS_error(int error, const char *message, ...)
|
|
{
|
|
va_list arg;
|
|
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
|
|
if (error > 0)
|
|
fprintf(stderr, "\nError: ");
|
|
else
|
|
fprintf(stderr, "\nWarning: ");
|
|
|
|
va_start(arg, message);
|
|
vfprintf(stderr, message, arg);
|
|
va_end(arg);
|
|
|
|
fflush(stderr);
|
|
|
|
if (error > 0)
|
|
exit(error);
|
|
}
|
|
|
|
HTS_MISC_C_END;
|
|
|
|
#endif /* !HTS_MISC_C */
|