diff options
Diffstat (limited to 'media/sphinxbase/src/libsphinxbase/util')
27 files changed, 16548 insertions, 0 deletions
diff --git a/media/sphinxbase/src/libsphinxbase/util/bio.c b/media/sphinxbase/src/libsphinxbase/util/bio.c new file mode 100644 index 000000000..56c620f68 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/bio.c @@ -0,0 +1,644 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * bio.c -- Sphinx-3 binary file I/O functions. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1996 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log$ + * Revision 1.4 2005/06/21 20:40:46 arthchan2003 + * 1, Fixed doxygen documentation, 2, Add the $ keyword. + * + * Revision 1.3 2005/03/30 01:22:46 archan + * Fixed mistakes in last updates. Add + * + * + * 02-Jul-1997 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Bugfix: Added byteswapping in bio_verify_chksum(). + * + * 18-Dec-1996 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Created. + */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include "sphinxbase/bio.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" + + +#define BIO_HDRARG_MAX 32 +#define END_COMMENT "*end_comment*\n" + + +static void +bcomment_read(FILE * fp) +{ + __BIGSTACKVARIABLE__ char iline[16384]; + + while (fgets(iline, sizeof(iline), fp) != NULL) { + if (strcmp(iline, END_COMMENT) == 0) + return; + } + E_FATAL("Missing %s marker\n", END_COMMENT); +} + + +static int32 +swap_check(FILE * fp) +{ + uint32 magic; + + if (fread(&magic, sizeof(uint32), 1, fp) != 1) { + E_ERROR("Cannot read BYTEORDER MAGIC NO.\n"); + return -1; + } + + if (magic != BYTE_ORDER_MAGIC) { + /* either need to swap or got bogus magic number */ + SWAP_INT32(&magic); + + if (magic == BYTE_ORDER_MAGIC) + return 1; + + SWAP_INT32(&magic); + E_ERROR("Bad BYTEORDER MAGIC NO: %08x, expecting %08x\n", + magic, BYTE_ORDER_MAGIC); + return -1; + } + + return 0; +} + + +void +bio_hdrarg_free(char **argname, char **argval) +{ + int32 i; + + if (argname == NULL) + return; + for (i = 0; argname[i]; i++) { + ckd_free(argname[i]); + ckd_free(argval[i]); + } + ckd_free(argname); + ckd_free(argval); +} + + +int32 +bio_writehdr_version(FILE * fp, char *version) +{ + uint32 b; + + fprintf(fp, "s3\n"); + fprintf(fp, "version %s\n", version); + fprintf(fp, "endhdr\n"); + fflush(fp); + + b = (uint32) BYTE_ORDER_MAGIC; + fwrite(&b, sizeof(uint32), 1, fp); + fflush(fp); + + return 0; +} + + +int32 +bio_writehdr(FILE *fp, ...) +{ + char const *key; + va_list args; + uint32 b; + + fprintf(fp, "s3\n"); + va_start(args, fp); + while ((key = va_arg(args, char const *)) != NULL) { + char const *val = va_arg(args, char const *); + if (val == NULL) { + E_ERROR("Wrong number of arguments\n"); + va_end(args); + return -1; + } + fprintf(fp, "%s %s\n", key, val); + } + va_end(args); + + fprintf(fp, "endhdr\n"); + fflush(fp); + + b = (uint32) BYTE_ORDER_MAGIC; + if (fwrite(&b, sizeof(uint32), 1, fp) != 1) + return -1; + fflush(fp); + + return 0; +} + + +int32 +bio_readhdr(FILE * fp, char ***argname, char ***argval, int32 * swap) +{ + __BIGSTACKVARIABLE__ char line[16384], word[4096]; + int32 i, l; + int32 lineno; + + *argname = (char **) ckd_calloc(BIO_HDRARG_MAX + 1, sizeof(char *)); + *argval = (char **) ckd_calloc(BIO_HDRARG_MAX, sizeof(char *)); + + lineno = 0; + if (fgets(line, sizeof(line), fp) == NULL){ + E_ERROR("Premature EOF, line %d\n", lineno); + goto error_out; + } + lineno++; + + if ((line[0] == 's') && (line[1] == '3') && (line[2] == '\n')) { + /* New format (post Dec-1996, including checksums); read argument-value pairs */ + for (i = 0;;) { + if (fgets(line, sizeof(line), fp) == NULL) { + E_ERROR("Premature EOF, line %d\n", lineno); + goto error_out; + } + lineno++; + + if (sscanf(line, "%s%n", word, &l) != 1) { + E_ERROR("Header format error, line %d\n", lineno); + goto error_out; + } + if (strcmp(word, "endhdr") == 0) + break; + if (word[0] == '#') /* Skip comments */ + continue; + + if (i >= BIO_HDRARG_MAX) { + E_ERROR + ("Max arg-value limit(%d) exceeded; increase BIO_HDRARG_MAX\n", + BIO_HDRARG_MAX); + goto error_out; + } + + (*argname)[i] = ckd_salloc(word); + if (sscanf(line + l, "%s", word) != 1) { /* Multi-word values not allowed */ + E_ERROR("Header format error, line %d\n", lineno); + goto error_out; + } + (*argval)[i] = ckd_salloc(word); + i++; + } + } + else { + /* Old format (without checksums); the first entry must be the version# */ + if (sscanf(line, "%s", word) != 1) { + E_ERROR("Header format error, line %d\n", lineno); + goto error_out; + } + + (*argname)[0] = ckd_salloc("version"); + (*argval)[0] = ckd_salloc(word); + i = 1; + + bcomment_read(fp); + } + (*argname)[i] = NULL; + + if ((*swap = swap_check(fp)) < 0) { + E_ERROR("swap_check failed\n"); + goto error_out; + } + + return 0; +error_out: + bio_hdrarg_free(*argname, *argval); + *argname = *argval = NULL; + return -1; +} + + +static uint32 +chksum_accum(const void *buf, int32 el_sz, int32 n_el, uint32 sum) +{ + int32 i; + uint8 *i8; + uint16 *i16; + uint32 *i32; + + switch (el_sz) { + case 1: + i8 = (uint8 *) buf; + for (i = 0; i < n_el; i++) + sum = (sum << 5 | sum >> 27) + i8[i]; + break; + case 2: + i16 = (uint16 *) buf; + for (i = 0; i < n_el; i++) + sum = (sum << 10 | sum >> 22) + i16[i]; + break; + case 4: + i32 = (uint32 *) buf; + for (i = 0; i < n_el; i++) + sum = (sum << 20 | sum >> 12) + i32[i]; + break; + default: + E_FATAL("Unsupported elemsize for checksum: %d\n", el_sz); + break; + } + + return sum; +} + + +static void +swap_buf(void *buf, int32 el_sz, int32 n_el) +{ + int32 i; + uint16 *buf16; + uint32 *buf32; + + switch (el_sz) { + case 1: + break; + case 2: + buf16 = (uint16 *) buf; + for (i = 0; i < n_el; i++) + SWAP_INT16(buf16 + i); + break; + case 4: + buf32 = (uint32 *) buf; + for (i = 0; i < n_el; i++) + SWAP_INT32(buf32 + i); + break; + default: + E_FATAL("Unsupported elemsize for byteswapping: %d\n", el_sz); + break; + } +} + + +int32 +bio_fread(void *buf, int32 el_sz, int32 n_el, FILE * fp, int32 swap, + uint32 * chksum) +{ + if (fread(buf, el_sz, n_el, fp) != (size_t) n_el) + return -1; + + if (swap) + swap_buf(buf, el_sz, n_el); + + if (chksum) + *chksum = chksum_accum(buf, el_sz, n_el, *chksum); + + return n_el; +} + +int32 +bio_fwrite(const void *buf, int32 el_sz, int32 n_el, FILE *fp, + int32 swap, uint32 *chksum) +{ + if (chksum) + *chksum = chksum_accum(buf, el_sz, n_el, *chksum); + if (swap) { + void *nbuf; + int rv; + + nbuf = ckd_calloc(n_el, el_sz); + memcpy(nbuf, buf, n_el * el_sz); + swap_buf(nbuf, el_sz, n_el); + rv = fwrite(nbuf, el_sz, n_el, fp); + ckd_free(nbuf); + return rv; + } + else { + return fwrite(buf, el_sz, n_el, fp); + } +} + +int32 +bio_fread_1d(void **buf, size_t el_sz, uint32 * n_el, FILE * fp, + int32 sw, uint32 * ck) +{ + /* Read 1-d array size */ + if (bio_fread(n_el, sizeof(int32), 1, fp, sw, ck) != 1) + E_FATAL("fread(arraysize) failed\n"); + if (*n_el <= 0) + E_FATAL("Bad arraysize: %d\n", *n_el); + + /* Allocate memory for array data */ + *buf = (void *) ckd_calloc(*n_el, el_sz); + + /* Read array data */ + if (bio_fread(*buf, el_sz, *n_el, fp, sw, ck) != *n_el) + E_FATAL("fread(arraydata) failed\n"); + + return *n_el; +} + +int32 +bio_fread_2d(void ***arr, + size_t e_sz, + uint32 *d1, + uint32 *d2, + FILE *fp, + uint32 swap, + uint32 *chksum) +{ + uint32 l_d1, l_d2; + uint32 n; + size_t ret; + void *raw; + + ret = bio_fread(&l_d1, sizeof(uint32), 1, fp, swap, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to read complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fread_2d"); + } + return -1; + } + ret = bio_fread(&l_d2, sizeof(uint32), 1, fp, swap, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to read complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fread_2d"); + } + return -1; + } + if (bio_fread_1d(&raw, e_sz, &n, fp, swap, chksum) != n) + return -1; + + assert(n == l_d1*l_d2); + + *d1 = l_d1; + *d2 = l_d2; + *arr = ckd_alloc_2d_ptr(l_d1, l_d2, raw, e_sz); + + return n; +} + +int32 +bio_fread_3d(void ****arr, + size_t e_sz, + uint32 *d1, + uint32 *d2, + uint32 *d3, + FILE *fp, + uint32 swap, + uint32 *chksum) +{ + uint32 l_d1; + uint32 l_d2; + uint32 l_d3; + uint32 n; + void *raw; + size_t ret; + + ret = bio_fread(&l_d1, sizeof(uint32), 1, fp, swap, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to read complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fread_3d"); + } + return -1; + } + ret = bio_fread(&l_d2, sizeof(uint32), 1, fp, swap, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to read complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fread_3d"); + } + return -1; + } + ret = bio_fread(&l_d3, sizeof(uint32), 1, fp, swap, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to read complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fread_3d"); + } + return -1; + } + + if (bio_fread_1d(&raw, e_sz, &n, fp, swap, chksum) != n) { + return -1; + } + + assert(n == l_d1 * l_d2 * l_d3); + + *arr = ckd_alloc_3d_ptr(l_d1, l_d2, l_d3, raw, e_sz); + *d1 = l_d1; + *d2 = l_d2; + *d3 = l_d3; + + return n; +} + +void +bio_verify_chksum(FILE * fp, int32 byteswap, uint32 chksum) +{ + uint32 file_chksum; + + if (fread(&file_chksum, sizeof(uint32), 1, fp) != 1) + E_FATAL("fread(chksum) failed\n"); + if (byteswap) + SWAP_INT32(&file_chksum); + if (file_chksum != chksum) + E_FATAL + ("Checksum error; file-checksum %08x, computed %08x\n", + file_chksum, chksum); +} + +int +bio_fwrite_3d(void ***arr, + size_t e_sz, + uint32 d1, + uint32 d2, + uint32 d3, + FILE *fp, + uint32 *chksum) +{ + size_t ret; + + /* write out first dimension 1 */ + ret = bio_fwrite(&d1, sizeof(uint32), 1, fp, 0, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to write complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fwrite_3d"); + } + return -1; + } + + /* write out first dimension 2 */ + ret = bio_fwrite(&d2, sizeof(uint32), 1, fp, 0, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to write complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fwrite_3d"); + } + return -1; + } + + /* write out first dimension 3 */ + ret = bio_fwrite(&d3, sizeof(uint32), 1, fp, 0, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to write complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fwrite_3d"); + } + return -1; + } + + /* write out the data in the array as one big block */ + return bio_fwrite_1d(arr[0][0], e_sz, d1 * d2 * d3, fp, chksum); +} + +int +bio_fwrite_1d(void *arr, + size_t e_sz, + uint32 d1, + FILE *fp, + uint32 *chksum) +{ + size_t ret; + ret = bio_fwrite(&d1, sizeof(uint32), 1, fp, 0, chksum); + if (ret != 1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to write complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fwrite_1d"); + } + return -1; + } + + ret = bio_fwrite(arr, e_sz, d1, fp, 0, chksum); + if (ret != d1) { + if (ret == 0) { + E_ERROR_SYSTEM("Unable to write complete data"); + } + else { + E_ERROR_SYSTEM("OS error in bio_fwrite_1d"); + } + + return -1; + } + + return ret; +} + +int16* +bio_read_wavfile(char const *directory, + char const *filename, + char const *extension, + int32 header, + int32 endian, + size_t *nsamps) +{ + FILE *uttfp; + char *inputfile; + size_t n, l; + int16 *data; + + n = strlen(extension); + l = strlen(filename); + if ((n <= l) && (0 == strcmp(filename + l - n, extension))) + extension = ""; + inputfile = ckd_calloc(strlen(directory) + l + n + 2, 1); + if (directory) { + sprintf(inputfile, "%s/%s%s", directory, filename, extension); + } else { + sprintf(inputfile, "%s%s", filename, extension); + } + + if ((uttfp = fopen(inputfile, "rb")) == NULL) { + E_FATAL_SYSTEM("Failed to open file '%s' for reading", inputfile); + } + fseek(uttfp, 0, SEEK_END); + n = ftell(uttfp); + fseek(uttfp, 0, SEEK_SET); + if (header > 0) { + if (fseek(uttfp, header, SEEK_SET) < 0) { + E_ERROR_SYSTEM("Failed to move to an offset %d in a file '%s'", header, inputfile); + fclose(uttfp); + ckd_free(inputfile); + return NULL; + } + n -= header; + } + n /= sizeof(int16); + data = ckd_calloc(n, sizeof(*data)); + if ((l = fread(data, sizeof(int16), n, uttfp)) < n) { + E_ERROR_SYSTEM("Failed to read %d samples from %s: %d", n, inputfile, l); + ckd_free(data); + ckd_free(inputfile); + fclose(uttfp); + return NULL; + } + ckd_free(inputfile); + fclose(uttfp); + if (nsamps) *nsamps = n; + + return data; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/bitvec.c b/media/sphinxbase/src/libsphinxbase/util/bitvec.c new file mode 100644 index 000000000..2d139010e --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/bitvec.c @@ -0,0 +1,101 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * bitvec.c -- Bit vector type. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: bitvec.c,v $ + * Revision 1.4 2005/06/22 02:58:22 arthchan2003 + * Added keyword + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 05-Mar-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Started. + */ + + +#include "sphinxbase/bitvec.h" + +bitvec_t * +bitvec_realloc(bitvec_t *vec, + size_t old_len, + size_t new_len) +{ + bitvec_t *new_vec; + size_t old_size = bitvec_size(old_len); + size_t new_size = bitvec_size(new_len); + + new_vec = ckd_realloc(vec, new_size * sizeof(bitvec_t)); + if (new_size > old_size) + memset(new_vec + old_size, 0, (new_size - old_size) * sizeof(bitvec_t)); + + return new_vec; +} + +size_t +bitvec_count_set(bitvec_t *vec, size_t len) +{ + size_t words, bits, w, b, n; + bitvec_t *v; + + words = len / BITVEC_BITS; + bits = len % BITVEC_BITS; + v = vec; + n = 0; + for (w = 0; w < words; ++w, ++v) { + if (*v == 0) + continue; + for (b = 0; b < BITVEC_BITS; ++b) + if (*v & (1<<b)) + ++n; + } + for (b = 0; b < bits; ++b) + if (*v & (1<<b)) + ++n; + + return n; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/blas_lite.c b/media/sphinxbase/src/libsphinxbase/util/blas_lite.c new file mode 100644 index 000000000..c175eaa52 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/blas_lite.c @@ -0,0 +1,2147 @@ +/* +NOTE: This is generated code. Look in README.python for information on + remaking this file. +*/ +#include "sphinxbase/f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal slamch_(char *); +#define EPSILON slamch_("Epsilon") +#define SAFEMINIMUM slamch_("Safe minimum") +#define PRECISION slamch_("Precision") +#define BASE slamch_("Base") +#endif + + +extern doublereal slapy2_(real *, real *); + + + +/* Table of constant values */ + +static integer c__1 = 1; + +logical lsame_(char *ca, char *cb) +{ + /* System generated locals */ + logical ret_val; + + /* Local variables */ + static integer inta, intb, zcode; + + +/* + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 + + + Purpose + ======= + + LSAME returns .TRUE. if CA is the same letter as CB regardless of + case. + + Arguments + ========= + + CA (input) CHARACTER*1 + CB (input) CHARACTER*1 + CA and CB specify the single characters to be compared. + + ===================================================================== + + + Test if the characters are equal +*/ + + ret_val = *(unsigned char *)ca == *(unsigned char *)cb; + if (ret_val) { + return ret_val; + } + +/* Now test for equivalence if both characters are alphabetic. */ + + zcode = 'Z'; + +/* + Use 'Z' rather than 'A' so that ASCII can be detected on Prime + machines, on which ICHAR returns a value with bit 8 set. + ICHAR('A') on Prime machines returns 193 which is the same as + ICHAR('A') on an EBCDIC machine. +*/ + + inta = *(unsigned char *)ca; + intb = *(unsigned char *)cb; + + if (zcode == 90 || zcode == 122) { + +/* + ASCII is assumed - ZCODE is the ASCII code of either lower or + upper case 'Z'. +*/ + + if (inta >= 97 && inta <= 122) { + inta += -32; + } + if (intb >= 97 && intb <= 122) { + intb += -32; + } + + } else if (zcode == 233 || zcode == 169) { + +/* + EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or + upper case 'Z'. +*/ + + if (inta >= 129 && inta <= 137 || inta >= 145 && inta <= 153 || inta + >= 162 && inta <= 169) { + inta += 64; + } + if (intb >= 129 && intb <= 137 || intb >= 145 && intb <= 153 || intb + >= 162 && intb <= 169) { + intb += 64; + } + + } else if (zcode == 218 || zcode == 250) { + +/* + ASCII is assumed, on Prime machines - ZCODE is the ASCII code + plus 128 of either lower or upper case 'Z'. +*/ + + if (inta >= 225 && inta <= 250) { + inta += -32; + } + if (intb >= 225 && intb <= 250) { + intb += -32; + } + } + ret_val = inta == intb; + +/* + RETURN + + End of LSAME +*/ + + return ret_val; +} /* lsame_ */ + +doublereal sdot_(integer *n, real *sx, integer *incx, real *sy, integer *incy) +{ + /* System generated locals */ + integer i__1; + real ret_val; + + /* Local variables */ + static integer i__, m, ix, iy, mp1; + static real stemp; + + +/* + forms the dot product of two vectors. + uses unrolled loops for increments equal to one. + jack dongarra, linpack, 3/11/78. + modified 12/3/93, array(1) declarations changed to array(*) +*/ + + + /* Parameter adjustments */ + --sy; + --sx; + + /* Function Body */ + stemp = 0.f; + ret_val = 0.f; + if (*n <= 0) { + return ret_val; + } + if (*incx == 1 && *incy == 1) { + goto L20; + } + +/* + code for unequal increments or equal increments + not equal to 1 +*/ + + ix = 1; + iy = 1; + if (*incx < 0) { + ix = (-(*n) + 1) * *incx + 1; + } + if (*incy < 0) { + iy = (-(*n) + 1) * *incy + 1; + } + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp += sx[ix] * sy[iy]; + ix += *incx; + iy += *incy; +/* L10: */ + } + ret_val = stemp; + return ret_val; + +/* + code for both increments equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__1 = m; + for (i__ = 1; i__ <= i__1; ++i__) { + stemp += sx[i__] * sy[i__]; +/* L30: */ + } + if (*n < 5) { + goto L60; + } +L40: + mp1 = m + 1; + i__1 = *n; + for (i__ = mp1; i__ <= i__1; i__ += 5) { + stemp = stemp + sx[i__] * sy[i__] + sx[i__ + 1] * sy[i__ + 1] + sx[ + i__ + 2] * sy[i__ + 2] + sx[i__ + 3] * sy[i__ + 3] + sx[i__ + + 4] * sy[i__ + 4]; +/* L50: */ + } +L60: + ret_val = stemp; + return ret_val; +} /* sdot_ */ + +/* Subroutine */ int sgemm_(char *transa, char *transb, integer *m, integer * + n, integer *k, real *alpha, real *a, integer *lda, real *b, integer * + ldb, real *beta, real *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__, j, l, info; + static logical nota, notb; + static real temp; + static integer ncola; + extern logical lsame_(char *, char *); + static integer nrowa, nrowb; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SGEMM performs one of the matrix-matrix operations + + C := alpha*op( A )*op( B ) + beta*C, + + where op( X ) is one of + + op( X ) = X or op( X ) = X', + + alpha and beta are scalars, and A, B and C are matrices, with op( A ) + an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. + + Parameters + ========== + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n', op( A ) = A. + + TRANSA = 'T' or 't', op( A ) = A'. + + TRANSA = 'C' or 'c', op( A ) = A'. + + Unchanged on exit. + + TRANSB - CHARACTER*1. + On entry, TRANSB specifies the form of op( B ) to be used in + the matrix multiplication as follows: + + TRANSB = 'N' or 'n', op( B ) = B. + + TRANSB = 'T' or 't', op( B ) = B'. + + TRANSB = 'C' or 'c', op( B ) = B'. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix + op( A ) and of the matrix C. M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix + op( B ) and the number of columns of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry, K specifies the number of columns of the matrix + op( A ) and the number of rows of the matrix op( B ). K must + be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, ka ), where ka is + k when TRANSA = 'N' or 'n', and is m otherwise. + Before entry with TRANSA = 'N' or 'n', the leading m by k + part of the array A must contain the matrix A, otherwise + the leading k by m part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANSA = 'N' or 'n' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, k ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, kb ), where kb is + n when TRANSB = 'N' or 'n', and is k otherwise. + Before entry with TRANSB = 'N' or 'n', the leading k by n + part of the array B must contain the matrix B, otherwise + the leading n by k part of the array B must contain the + matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. When TRANSB = 'N' or 'n' then + LDB must be at least max( 1, k ), otherwise LDB must be at + least max( 1, n ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + + C - REAL array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n matrix + ( alpha*op( A )*op( B ) + beta*C ). + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + + Set NOTA and NOTB as true if A and B respectively are not + transposed and set NROWA, NCOLA and NROWB as the number of rows + and columns of A and the number of rows of B respectively. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + nota = lsame_(transa, "N"); + notb = lsame_(transb, "N"); + if (nota) { + nrowa = *m; + ncola = *k; + } else { + nrowa = *k; + ncola = *m; + } + if (notb) { + nrowb = *k; + } else { + nrowb = *n; + } + +/* Test the input parameters. */ + + info = 0; + if (! nota && ! lsame_(transa, "C") && ! lsame_( + transa, "T")) { + info = 1; + } else if (! notb && ! lsame_(transb, "C") && ! + lsame_(transb, "T")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < max(1,nrowa)) { + info = 8; + } else if (*ldb < max(1,nrowb)) { + info = 10; + } else if (*ldc < max(1,*m)) { + info = 13; + } + if (info != 0) { + xerbla_("SGEMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || (*alpha == 0.f || *k == 0) && *beta == 1.f) { + return 0; + } + +/* And if alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + return 0; + } + +/* Start the operations. */ + + if (notb) { + if (nota) { + +/* Form C := alpha*A*B + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L50: */ + } + } else if (*beta != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L60: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b[l + j * b_dim1] != 0.f) { + temp = *alpha * b[l + j * b_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L70: */ + } + } +/* L80: */ + } +/* L90: */ + } + } else { + +/* Form C := alpha*A'*B + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * b[l + j * b_dim1]; +/* L100: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L110: */ + } +/* L120: */ + } + } + } else { + if (nota) { + +/* Form C := alpha*A*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L130: */ + } + } else if (*beta != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L140: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (b[j + l * b_dim1] != 0.f) { + temp = *alpha * b[j + l * b_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L150: */ + } + } +/* L160: */ + } +/* L170: */ + } + } else { + +/* Form C := alpha*A'*B' + beta*C */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * b[j + l * b_dim1]; +/* L180: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L190: */ + } +/* L200: */ + } + } + } + + return 0; + +/* End of SGEMM . */ + +} /* sgemm_ */ + +/* Subroutine */ int sgemv_(char *trans, integer *m, integer *n, real *alpha, + real *a, integer *lda, real *x, integer *incx, real *beta, real *y, + integer *incy) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2; + + /* Local variables */ + static integer i__, j, ix, iy, jx, jy, kx, ky, info; + static real temp; + static integer lenx, leny; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SGEMV performs one of the matrix-vector operations + + y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, + + where alpha and beta are scalars, x and y are vectors and A is an + m by n matrix. + + Parameters + ========== + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' y := alpha*A*x + beta*y. + + TRANS = 'T' or 't' y := alpha*A'*x + beta*y. + + TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix A. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix A. + N must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, n ). + Before entry, the leading m by n part of the array A must + contain the matrix of coefficients. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. LDA must be at least + max( 1, m ). + Unchanged on exit. + + X - REAL array of DIMENSION at least + ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. + Before entry, the incremented array X must contain the + vector x. + Unchanged on exit. + + INCX - INTEGER. + On entry, INCX specifies the increment for the elements of + X. INCX must not be zero. + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then Y need not be set on input. + Unchanged on exit. + + Y - REAL array of DIMENSION at least + ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' + and at least + ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. + Before entry with BETA non-zero, the incremented array Y + must contain the vector y. On exit, Y is overwritten by the + updated vector y. + + INCY - INTEGER. + On entry, INCY specifies the increment for the elements of + Y. INCY must not be zero. + Unchanged on exit. + + + Level 2 Blas routine. + + -- Written on 22-October-1986. + Jack Dongarra, Argonne National Lab. + Jeremy Du Croz, Nag Central Office. + Sven Hammarling, Nag Central Office. + Richard Hanson, Sandia National Labs. + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(trans, "N") && ! lsame_(trans, "T") && ! lsame_(trans, "C") + ) { + info = 1; + } else if (*m < 0) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*lda < max(1,*m)) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("SGEMV ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || *alpha == 0.f && *beta == 1.f) { + return 0; + } + +/* + Set LENX and LENY, the lengths of the vectors x and y, and set + up the start points in X and Y. +*/ + + if (lsame_(trans, "N")) { + lenx = *n; + leny = *m; + } else { + lenx = *m; + leny = *n; + } + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (lenx - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (leny - 1) * *incy; + } + +/* + Start the operations. In this version the elements of A are + accessed sequentially with one pass through A. + + First form y := beta*y. +*/ + + if (*beta != 1.f) { + if (*incy == 1) { + if (*beta == 0.f) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.f; +/* L10: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.f) { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = leny; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.f) { + return 0; + } + if (lsame_(trans, "N")) { + +/* Form y := alpha*A*x + y. */ + + jx = kx; + if (*incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f) { + temp = *alpha * x[jx]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp * a[i__ + j * a_dim1]; +/* L50: */ + } + } + jx += *incx; +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f) { + temp = *alpha * x[jx]; + iy = ky; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + y[iy] += temp * a[i__ + j * a_dim1]; + iy += *incy; +/* L70: */ + } + } + jx += *incx; +/* L80: */ + } + } + } else { + +/* Form y := alpha*A'*x + y. */ + + jy = ky; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = 0.f; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[jy] += *alpha * temp; + jy += *incy; +/* L100: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp = 0.f; + ix = kx; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp += a[i__ + j * a_dim1] * x[ix]; + ix += *incx; +/* L110: */ + } + y[jy] += *alpha * temp; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of SGEMV . */ + +} /* sgemv_ */ + +/* Subroutine */ int sscal_(integer *n, real *sa, real *sx, integer *incx) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + static integer i__, m, mp1, nincx; + + +/* + scales a vector by a constant. + uses unrolled loops for increment equal to 1. + jack dongarra, linpack, 3/11/78. + modified 3/93 to return if incx .le. 0. + modified 12/3/93, array(1) declarations changed to array(*) +*/ + + + /* Parameter adjustments */ + --sx; + + /* Function Body */ + if (*n <= 0 || *incx <= 0) { + return 0; + } + if (*incx == 1) { + goto L20; + } + +/* code for increment not equal to 1 */ + + nincx = *n * *incx; + i__1 = nincx; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + sx[i__] = *sa * sx[i__]; +/* L10: */ + } + return 0; + +/* + code for increment equal to 1 + + + clean-up loop +*/ + +L20: + m = *n % 5; + if (m == 0) { + goto L40; + } + i__2 = m; + for (i__ = 1; i__ <= i__2; ++i__) { + sx[i__] = *sa * sx[i__]; +/* L30: */ + } + if (*n < 5) { + return 0; + } +L40: + mp1 = m + 1; + i__2 = *n; + for (i__ = mp1; i__ <= i__2; i__ += 5) { + sx[i__] = *sa * sx[i__]; + sx[i__ + 1] = *sa * sx[i__ + 1]; + sx[i__ + 2] = *sa * sx[i__ + 2]; + sx[i__ + 3] = *sa * sx[i__ + 3]; + sx[i__ + 4] = *sa * sx[i__ + 4]; +/* L50: */ + } + return 0; +} /* sscal_ */ + +/* Subroutine */ int ssymm_(char *side, char *uplo, integer *m, integer *n, + real *alpha, real *a, integer *lda, real *b, integer *ldb, real *beta, + real *c__, integer *ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, i__1, i__2, + i__3; + + /* Local variables */ + static integer i__, j, k, info; + static real temp1, temp2; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SSYMM performs one of the matrix-matrix operations + + C := alpha*A*B + beta*C, + + or + + C := alpha*B*A + beta*C, + + where alpha and beta are scalars, A is a symmetric matrix and B and + C are m by n matrices. + + Parameters + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether the symmetric matrix A + appears on the left or right in the operation as follows: + + SIDE = 'L' or 'l' C := alpha*A*B + beta*C, + + SIDE = 'R' or 'r' C := alpha*B*A + beta*C, + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the symmetric matrix A is to be + referenced as follows: + + UPLO = 'U' or 'u' Only the upper triangular part of the + symmetric matrix is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of the + symmetric matrix is to be referenced. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of the matrix C. + M must be at least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of the matrix C. + N must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, ka ), where ka is + m when SIDE = 'L' or 'l' and is n otherwise. + Before entry with SIDE = 'L' or 'l', the m by m part of + the array A must contain the symmetric matrix, such that + when UPLO = 'U' or 'u', the leading m by m upper triangular + part of the array A must contain the upper triangular part + of the symmetric matrix and the strictly lower triangular + part of A is not referenced, and when UPLO = 'L' or 'l', + the leading m by m lower triangular part of the array A + must contain the lower triangular part of the symmetric + matrix and the strictly upper triangular part of A is not + referenced. + Before entry with SIDE = 'R' or 'r', the n by n part of + the array A must contain the symmetric matrix, such that + when UPLO = 'U' or 'u', the leading n by n upper triangular + part of the array A must contain the upper triangular part + of the symmetric matrix and the strictly lower triangular + part of A is not referenced, and when UPLO = 'L' or 'l', + the leading n by n lower triangular part of the array A + must contain the lower triangular part of the symmetric + matrix and the strictly upper triangular part of A is not + referenced. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), otherwise LDA must be at + least max( 1, n ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the matrix B. + Unchanged on exit. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. When BETA is + supplied as zero then C need not be set on input. + Unchanged on exit. + + C - REAL array of DIMENSION ( LDC, n ). + Before entry, the leading m by n part of the array C must + contain the matrix C, except when beta is zero, in which + case C need not be set on entry. + On exit, the array C is overwritten by the m by n updated + matrix. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, m ). + Unchanged on exit. + + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + + Set NROWA as the number of rows of A. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(side, "L")) { + nrowa = *m; + } else { + nrowa = *n; + } + upper = lsame_(uplo, "U"); + +/* Test the input parameters. */ + + info = 0; + if (! lsame_(side, "L") && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (*m < 0) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldb < max(1,*m)) { + info = 9; + } else if (*ldc < max(1,*m)) { + info = 12; + } + if (info != 0) { + xerbla_("SSYMM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*m == 0 || *n == 0 || *alpha == 0.f && *beta == 1.f) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(side, "L")) { + +/* Form C := alpha*A*B + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp1 = *alpha * b[i__ + j * b_dim1]; + temp2 = 0.f; + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + c__[k + j * c_dim1] += temp1 * a[k + i__ * a_dim1]; + temp2 += b[k + j * b_dim1] * a[k + i__ * a_dim1]; +/* L50: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = temp1 * a[i__ + i__ * a_dim1] + + *alpha * temp2; + } else { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + temp1 * a[i__ + i__ * a_dim1] + *alpha * + temp2; + } +/* L60: */ + } +/* L70: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp1 = *alpha * b[i__ + j * b_dim1]; + temp2 = 0.f; + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + c__[k + j * c_dim1] += temp1 * a[k + i__ * a_dim1]; + temp2 += b[k + j * b_dim1] * a[k + i__ * a_dim1]; +/* L80: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = temp1 * a[i__ + i__ * a_dim1] + + *alpha * temp2; + } else { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + temp1 * a[i__ + i__ * a_dim1] + *alpha * + temp2; + } +/* L90: */ + } +/* L100: */ + } + } + } else { + +/* Form C := alpha*B*A + beta*C. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * a[j + j * a_dim1]; + if (*beta == 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = temp1 * b[i__ + j * b_dim1]; +/* L110: */ + } + } else { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1] + + temp1 * b[i__ + j * b_dim1]; +/* L120: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + if (upper) { + temp1 = *alpha * a[k + j * a_dim1]; + } else { + temp1 = *alpha * a[j + k * a_dim1]; + } + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp1 * b[i__ + k * b_dim1]; +/* L130: */ + } +/* L140: */ + } + i__2 = *n; + for (k = j + 1; k <= i__2; ++k) { + if (upper) { + temp1 = *alpha * a[j + k * a_dim1]; + } else { + temp1 = *alpha * a[k + j * a_dim1]; + } + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp1 * b[i__ + k * b_dim1]; +/* L150: */ + } +/* L160: */ + } +/* L170: */ + } + } + + return 0; + +/* End of SSYMM . */ + +} /* ssymm_ */ + +/* Subroutine */ int ssyrk_(char *uplo, char *trans, integer *n, integer *k, + real *alpha, real *a, integer *lda, real *beta, real *c__, integer * + ldc) +{ + /* System generated locals */ + integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, l, info; + static real temp; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + Purpose + ======= + + SSYRK performs one of the symmetric rank k operations + + C := alpha*A*A' + beta*C, + + or + + C := alpha*A'*A + beta*C, + + where alpha and beta are scalars, C is an n by n symmetric matrix + and A is an n by k matrix in the first case and a k by n matrix + in the second case. + + Parameters + ========== + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the upper or lower + triangular part of the array C is to be referenced as + follows: + + UPLO = 'U' or 'u' Only the upper triangular part of C + is to be referenced. + + UPLO = 'L' or 'l' Only the lower triangular part of C + is to be referenced. + + Unchanged on exit. + + TRANS - CHARACTER*1. + On entry, TRANS specifies the operation to be performed as + follows: + + TRANS = 'N' or 'n' C := alpha*A*A' + beta*C. + + TRANS = 'T' or 't' C := alpha*A'*A + beta*C. + + TRANS = 'C' or 'c' C := alpha*A'*A + beta*C. + + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the order of the matrix C. N must be + at least zero. + Unchanged on exit. + + K - INTEGER. + On entry with TRANS = 'N' or 'n', K specifies the number + of columns of the matrix A, and on entry with + TRANS = 'T' or 't' or 'C' or 'c', K specifies the number + of rows of the matrix A. K must be at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, ka ), where ka is + k when TRANS = 'N' or 'n', and is n otherwise. + Before entry with TRANS = 'N' or 'n', the leading n by k + part of the array A must contain the matrix A, otherwise + the leading k by n part of the array A must contain the + matrix A. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When TRANS = 'N' or 'n' + then LDA must be at least max( 1, n ), otherwise LDA must + be at least max( 1, k ). + Unchanged on exit. + + BETA - REAL . + On entry, BETA specifies the scalar beta. + Unchanged on exit. + + C - REAL array of DIMENSION ( LDC, n ). + Before entry with UPLO = 'U' or 'u', the leading n by n + upper triangular part of the array C must contain the upper + triangular part of the symmetric matrix and the strictly + lower triangular part of C is not referenced. On exit, the + upper triangular part of the array C is overwritten by the + upper triangular part of the updated matrix. + Before entry with UPLO = 'L' or 'l', the leading n by n + lower triangular part of the array C must contain the lower + triangular part of the symmetric matrix and the strictly + upper triangular part of C is not referenced. On exit, the + lower triangular part of the array C is overwritten by the + lower triangular part of the updated matrix. + + LDC - INTEGER. + On entry, LDC specifies the first dimension of C as declared + in the calling (sub) program. LDC must be at least + max( 1, n ). + Unchanged on exit. + + + Level 3 Blas routine. + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + c_dim1 = *ldc; + c_offset = 1 + c_dim1; + c__ -= c_offset; + + /* Function Body */ + if (lsame_(trans, "N")) { + nrowa = *n; + } else { + nrowa = *k; + } + upper = lsame_(uplo, "U"); + + info = 0; + if (! upper && ! lsame_(uplo, "L")) { + info = 1; + } else if (! lsame_(trans, "N") && ! lsame_(trans, + "T") && ! lsame_(trans, "C")) { + info = 2; + } else if (*n < 0) { + info = 3; + } else if (*k < 0) { + info = 4; + } else if (*lda < max(1,nrowa)) { + info = 7; + } else if (*ldc < max(1,*n)) { + info = 10; + } + if (info != 0) { + xerbla_("SSYRK ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0.f || *k == 0) && *beta == 1.f) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + if (upper) { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L30: */ + } +/* L40: */ + } + } + } else { + if (*beta == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L70: */ + } +/* L80: */ + } + } + } + return 0; + } + +/* Start the operations. */ + + if (lsame_(trans, "N")) { + +/* Form C := alpha*A*A' + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L90: */ + } + } else if (*beta != 1.f) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L100: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.f) { + temp = *alpha * a[j + l * a_dim1]; + i__3 = j; + for (i__ = 1; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L110: */ + } + } +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*beta == 0.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = 0.f; +/* L140: */ + } + } else if (*beta != 1.f) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + c__[i__ + j * c_dim1] = *beta * c__[i__ + j * c_dim1]; +/* L150: */ + } + } + i__2 = *k; + for (l = 1; l <= i__2; ++l) { + if (a[j + l * a_dim1] != 0.f) { + temp = *alpha * a[j + l * a_dim1]; + i__3 = *n; + for (i__ = j; i__ <= i__3; ++i__) { + c__[i__ + j * c_dim1] += temp * a[i__ + l * + a_dim1]; +/* L160: */ + } + } +/* L170: */ + } +/* L180: */ + } + } + } else { + +/* Form C := alpha*A'*A + beta*C. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * a[l + j * a_dim1]; +/* L190: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L200: */ + } +/* L210: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *n; + for (i__ = j; i__ <= i__2; ++i__) { + temp = 0.f; + i__3 = *k; + for (l = 1; l <= i__3; ++l) { + temp += a[l + i__ * a_dim1] * a[l + j * a_dim1]; +/* L220: */ + } + if (*beta == 0.f) { + c__[i__ + j * c_dim1] = *alpha * temp; + } else { + c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[ + i__ + j * c_dim1]; + } +/* L230: */ + } +/* L240: */ + } + } + } + + return 0; + +/* End of SSYRK . */ + +} /* ssyrk_ */ + +/* Subroutine */ int strsm_(char *side, char *uplo, char *transa, char *diag, + integer *m, integer *n, real *alpha, real *a, integer *lda, real *b, + integer *ldb) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3; + + /* Local variables */ + static integer i__, j, k, info; + static real temp; + static logical lside; + extern logical lsame_(char *, char *); + static integer nrowa; + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + static logical nounit; + + +/* + Purpose + ======= + + STRSM solves one of the matrix equations + + op( A )*X = alpha*B, or X*op( A ) = alpha*B, + + where alpha is a scalar, X and B are m by n matrices, A is a unit, or + non-unit, upper or lower triangular matrix and op( A ) is one of + + op( A ) = A or op( A ) = A'. + + The matrix X is overwritten on B. + + Parameters + ========== + + SIDE - CHARACTER*1. + On entry, SIDE specifies whether op( A ) appears on the left + or right of X as follows: + + SIDE = 'L' or 'l' op( A )*X = alpha*B. + + SIDE = 'R' or 'r' X*op( A ) = alpha*B. + + Unchanged on exit. + + UPLO - CHARACTER*1. + On entry, UPLO specifies whether the matrix A is an upper or + lower triangular matrix as follows: + + UPLO = 'U' or 'u' A is an upper triangular matrix. + + UPLO = 'L' or 'l' A is a lower triangular matrix. + + Unchanged on exit. + + TRANSA - CHARACTER*1. + On entry, TRANSA specifies the form of op( A ) to be used in + the matrix multiplication as follows: + + TRANSA = 'N' or 'n' op( A ) = A. + + TRANSA = 'T' or 't' op( A ) = A'. + + TRANSA = 'C' or 'c' op( A ) = A'. + + Unchanged on exit. + + DIAG - CHARACTER*1. + On entry, DIAG specifies whether or not A is unit triangular + as follows: + + DIAG = 'U' or 'u' A is assumed to be unit triangular. + + DIAG = 'N' or 'n' A is not assumed to be unit + triangular. + + Unchanged on exit. + + M - INTEGER. + On entry, M specifies the number of rows of B. M must be at + least zero. + Unchanged on exit. + + N - INTEGER. + On entry, N specifies the number of columns of B. N must be + at least zero. + Unchanged on exit. + + ALPHA - REAL . + On entry, ALPHA specifies the scalar alpha. When alpha is + zero then A is not referenced and B need not be set before + entry. + Unchanged on exit. + + A - REAL array of DIMENSION ( LDA, k ), where k is m + when SIDE = 'L' or 'l' and is n when SIDE = 'R' or 'r'. + Before entry with UPLO = 'U' or 'u', the leading k by k + upper triangular part of the array A must contain the upper + triangular matrix and the strictly lower triangular part of + A is not referenced. + Before entry with UPLO = 'L' or 'l', the leading k by k + lower triangular part of the array A must contain the lower + triangular matrix and the strictly upper triangular part of + A is not referenced. + Note that when DIAG = 'U' or 'u', the diagonal elements of + A are not referenced either, but are assumed to be unity. + Unchanged on exit. + + LDA - INTEGER. + On entry, LDA specifies the first dimension of A as declared + in the calling (sub) program. When SIDE = 'L' or 'l' then + LDA must be at least max( 1, m ), when SIDE = 'R' or 'r' + then LDA must be at least max( 1, n ). + Unchanged on exit. + + B - REAL array of DIMENSION ( LDB, n ). + Before entry, the leading m by n part of the array B must + contain the right-hand side matrix B, and on exit is + overwritten by the solution matrix X. + + LDB - INTEGER. + On entry, LDB specifies the first dimension of B as declared + in the calling (sub) program. LDB must be at least + max( 1, m ). + Unchanged on exit. + + + Level 3 Blas routine. + + + -- Written on 8-February-1989. + Jack Dongarra, Argonne National Laboratory. + Iain Duff, AERE Harwell. + Jeremy Du Croz, Numerical Algorithms Group Ltd. + Sven Hammarling, Numerical Algorithms Group Ltd. + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + lside = lsame_(side, "L"); + if (lside) { + nrowa = *m; + } else { + nrowa = *n; + } + nounit = lsame_(diag, "N"); + upper = lsame_(uplo, "U"); + + info = 0; + if (! lside && ! lsame_(side, "R")) { + info = 1; + } else if (! upper && ! lsame_(uplo, "L")) { + info = 2; + } else if (! lsame_(transa, "N") && ! lsame_(transa, + "T") && ! lsame_(transa, "C")) { + info = 3; + } else if (! lsame_(diag, "U") && ! lsame_(diag, + "N")) { + info = 4; + } else if (*m < 0) { + info = 5; + } else if (*n < 0) { + info = 6; + } else if (*lda < max(1,nrowa)) { + info = 9; + } else if (*ldb < max(1,*m)) { + info = 11; + } + if (info != 0) { + xerbla_("STRSM ", &info); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + +/* And when alpha.eq.zero. */ + + if (*alpha == 0.f) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = 0.f; +/* L10: */ + } +/* L20: */ + } + return 0; + } + +/* Start the operations. */ + + if (lside) { + if (lsame_(transa, "N")) { + +/* Form B := alpha*inv( A )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L30: */ + } + } + for (k = *m; k >= 1; --k) { + if (b[k + j * b_dim1] != 0.f) { + if (nounit) { + b[k + j * b_dim1] /= a[k + k * a_dim1]; + } + i__2 = k - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[ + i__ + k * a_dim1]; +/* L40: */ + } + } +/* L50: */ + } +/* L60: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L70: */ + } + } + i__2 = *m; + for (k = 1; k <= i__2; ++k) { + if (b[k + j * b_dim1] != 0.f) { + if (nounit) { + b[k + j * b_dim1] /= a[k + k * a_dim1]; + } + i__3 = *m; + for (i__ = k + 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[ + i__ + k * a_dim1]; +/* L80: */ + } + } +/* L90: */ + } +/* L100: */ + } + } + } else { + +/* Form B := alpha*inv( A' )*B. */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + temp = *alpha * b[i__ + j * b_dim1]; + i__3 = i__ - 1; + for (k = 1; k <= i__3; ++k) { + temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L110: */ + } + if (nounit) { + temp /= a[i__ + i__ * a_dim1]; + } + b[i__ + j * b_dim1] = temp; +/* L120: */ + } +/* L130: */ + } + } else { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + for (i__ = *m; i__ >= 1; --i__) { + temp = *alpha * b[i__ + j * b_dim1]; + i__2 = *m; + for (k = i__ + 1; k <= i__2; ++k) { + temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1]; +/* L140: */ + } + if (nounit) { + temp /= a[i__ + i__ * a_dim1]; + } + b[i__ + j * b_dim1] = temp; +/* L150: */ + } +/* L160: */ + } + } + } + } else { + if (lsame_(transa, "N")) { + +/* Form B := alpha*B*inv( A ). */ + + if (upper) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L170: */ + } + } + i__2 = j - 1; + for (k = 1; k <= i__2; ++k) { + if (a[k + j * a_dim1] != 0.f) { + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[ + i__ + k * b_dim1]; +/* L180: */ + } + } +/* L190: */ + } + if (nounit) { + temp = 1.f / a[j + j * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L200: */ + } + } +/* L210: */ + } + } else { + for (j = *n; j >= 1; --j) { + if (*alpha != 1.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = *alpha * b[i__ + j * b_dim1] + ; +/* L220: */ + } + } + i__1 = *n; + for (k = j + 1; k <= i__1; ++k) { + if (a[k + j * a_dim1] != 0.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[ + i__ + k * b_dim1]; +/* L230: */ + } + } +/* L240: */ + } + if (nounit) { + temp = 1.f / a[j + j * a_dim1]; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1]; +/* L250: */ + } + } +/* L260: */ + } + } + } else { + +/* Form B := alpha*B*inv( A' ). */ + + if (upper) { + for (k = *n; k >= 1; --k) { + if (nounit) { + temp = 1.f / a[k + k * a_dim1]; + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L270: */ + } + } + i__1 = k - 1; + for (j = 1; j <= i__1; ++j) { + if (a[j + k * a_dim1] != 0.f) { + temp = a[j + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + j * b_dim1] -= temp * b[i__ + k * + b_dim1]; +/* L280: */ + } + } +/* L290: */ + } + if (*alpha != 1.f) { + i__1 = *m; + for (i__ = 1; i__ <= i__1; ++i__) { + b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1] + ; +/* L300: */ + } + } +/* L310: */ + } + } else { + i__1 = *n; + for (k = 1; k <= i__1; ++k) { + if (nounit) { + temp = 1.f / a[k + k * a_dim1]; + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1]; +/* L320: */ + } + } + i__2 = *n; + for (j = k + 1; j <= i__2; ++j) { + if (a[j + k * a_dim1] != 0.f) { + temp = a[j + k * a_dim1]; + i__3 = *m; + for (i__ = 1; i__ <= i__3; ++i__) { + b[i__ + j * b_dim1] -= temp * b[i__ + k * + b_dim1]; +/* L330: */ + } + } +/* L340: */ + } + if (*alpha != 1.f) { + i__2 = *m; + for (i__ = 1; i__ <= i__2; ++i__) { + b[i__ + k * b_dim1] = *alpha * b[i__ + k * b_dim1] + ; +/* L350: */ + } + } +/* L360: */ + } + } + } + } + + return 0; + +/* End of STRSM . */ + +} /* strsm_ */ + +/* Subroutine */ int xerbla_(char *srname, integer *info) +{ + /* Format strings */ + static char fmt_9999[] = "(\002 ** On entry to \002,a6,\002 parameter nu" + "mber \002,i2,\002 had \002,\002an illegal value\002)"; + + /* Builtin functions */ + integer s_wsfe(cilist *), do_fio(integer *, char *, ftnlen), e_wsfe(void); + /* Subroutine */ int s_stop(char *, ftnlen); + + /* Fortran I/O blocks */ + static cilist io___60 = { 0, 6, 0, fmt_9999, 0 }; + + +/* + -- LAPACK auxiliary routine (preliminary version) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 + + + Purpose + ======= + + XERBLA is an error handler for the LAPACK routines. + It is called by an LAPACK routine if an input parameter has an + invalid value. A message is printed and execution stops. + + Installers may consider modifying the STOP statement in order to + call system-specific exception-handling facilities. + + Arguments + ========= + + SRNAME (input) CHARACTER*6 + The name of the routine which called XERBLA. + + INFO (input) INTEGER + The position of the invalid parameter in the parameter list + of the calling routine. +*/ + + + s_wsfe(&io___60); + do_fio(&c__1, srname, (ftnlen)6); + do_fio(&c__1, (char *)&(*info), (ftnlen)sizeof(integer)); + e_wsfe(); + + s_stop("", (ftnlen)0); + + +/* End of XERBLA */ + + return 0; +} /* xerbla_ */ + diff --git a/media/sphinxbase/src/libsphinxbase/util/case.c b/media/sphinxbase/src/libsphinxbase/util/case.c new file mode 100644 index 000000000..f9e24ac06 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/case.c @@ -0,0 +1,141 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * case.c -- Upper/lower case conversion routines + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: case.c,v $ + * Revision 1.7 2005/06/22 02:58:54 arthchan2003 + * Added keyword + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 18-Jun-97 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Added strcmp_nocase. Moved UPPER_CASE and LOWER_CASE definitions to .h. + * + * 16-Feb-97 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Created. + */ + + +#include <stdlib.h> +#include <assert.h> + +#include "sphinxbase/case.h" +#include "sphinxbase/err.h" + + +void +lcase(register char *cp) +{ + if (cp) { + while (*cp) { + *cp = LOWER_CASE(*cp); + cp++; + } + } +} + +void +ucase(register char *cp) +{ + if (cp) { + while (*cp) { + *cp = UPPER_CASE(*cp); + cp++; + } + } +} + +int32 +strcmp_nocase(const char *str1, const char *str2) +{ + char c1, c2; + + if (str1 == str2) + return 0; + if (str1 && str2) { + for (;;) { + c1 = *(str1++); + c1 = UPPER_CASE(c1); + c2 = *(str2++); + c2 = UPPER_CASE(c2); + if (c1 != c2) + return (c1 - c2); + if (c1 == '\0') + return 0; + } + } + else + return (str1 == NULL) ? -1 : 1; + + return 0; +} + +int32 +strncmp_nocase(const char *str1, const char *str2, size_t len) +{ + char c1, c2; + + if (str1 && str2) { + size_t n; + + for (n = 0; n < len; ++n) { + c1 = *(str1++); + c1 = UPPER_CASE(c1); + c2 = *(str2++); + c2 = UPPER_CASE(c2); + if (c1 != c2) + return (c1 - c2); + if (c1 == '\0') + return 0; + } + } + else + return (str1 == NULL) ? -1 : 1; + + return 0; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/ckd_alloc.c b/media/sphinxbase/src/libsphinxbase/util/ckd_alloc.c new file mode 100644 index 000000000..45dc84aae --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/ckd_alloc.c @@ -0,0 +1,427 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * ckd_alloc.c -- Memory allocation package. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: ckd_alloc.c,v $ + * Revision 1.6 2005/06/22 02:59:25 arthchan2003 + * Added keyword + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 19-Jun-97 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Removed file,line arguments from free functions. + * Removed debugging stuff. + * + * 01-Jan-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Created. + */ + + +/********************************************************************* + * + * $Header: /cvsroot/cmusphinx/sphinx3/src/libutil/ckd_alloc.c,v 1.6 2005/06/22 02:59:25 arthchan2003 Exp $ + * + * Carnegie Mellon ARPA Speech Group + * + * Copyright (c) 1994 Carnegie Mellon University. + * All rights reserved. + * + ********************************************************************* + * + * file: ckd_alloc.c + * + * traceability: + * + * description: + * + * author: + * + *********************************************************************/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdarg.h> + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/err.h" + +/** + * Target for longjmp() on failure. + * + * FIXME: This should be in thread-local storage. + */ +static jmp_buf *ckd_target; +static int jmp_abort; + +jmp_buf * +ckd_set_jump(jmp_buf *env, int abort) +{ + jmp_buf *old; + + if (abort) + jmp_abort = 1; + + old = ckd_target; + ckd_target = env; + return old; +} + +void +ckd_fail(char *format, ...) +{ + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + if (jmp_abort) + /* abort() doesn't exist in Windows CE */ + #if defined(_WIN32_WCE) + exit(-1); + #else + abort(); + #endif + else if (ckd_target) + longjmp(*ckd_target, 1); + else + exit(-1); +} + +void * +__ckd_calloc__(size_t n_elem, size_t elem_size, + const char *caller_file, int caller_line) +{ + void *mem; + +#if defined(__ADSPBLACKFIN__) && !defined(__linux__) + if ((mem = heap_calloc(heap_lookup(1),n_elem, elem_size)) == NULL) + if ((mem = heap_calloc(heap_lookup(0),n_elem, elem_size)) == NULL) + { + ckd_fail("calloc(%d,%d) failed from %s(%d), free space: %d\n", n_elem, + elem_size, caller_file, caller_line,space_unused()); + } +#else + if ((mem = calloc(n_elem, elem_size)) == NULL) { + ckd_fail("calloc(%d,%d) failed from %s(%d)\n", n_elem, + elem_size, caller_file, caller_line); + } +#endif + + + return mem; +} + + +void * +__ckd_malloc__(size_t size, const char *caller_file, int caller_line) +{ + void *mem; + +#if defined(__ADSPBLACKFIN__) && !defined(__linux__) + if ((mem = heap_malloc(heap_lookup(0),size)) == NULL) + if ((mem = heap_malloc(heap_lookup(1),size)) == NULL) +#else + if ((mem = malloc(size)) == NULL) +#endif + ckd_fail("malloc(%d) failed from %s(%d)\n", size, + caller_file, caller_line); + + return mem; +} + + +void * +__ckd_realloc__(void *ptr, size_t new_size, + const char *caller_file, int caller_line) +{ + void *mem; +#if defined(__ADSPBLACKFIN__) && !defined(__linux__) + if ((mem = heap_realloc(heap_lookup(0),ptr, new_size)) == NULL) { +#else + if ((mem = realloc(ptr, new_size)) == NULL) { +#endif + ckd_fail("malloc(%d) failed from %s(%d)\n", new_size, + caller_file, caller_line); + } + + return mem; +} + + +char * +__ckd_salloc__(const char *orig, const char *caller_file, + int caller_line) +{ + size_t len; + char *buf; + + if (!orig) + return NULL; + + len = strlen(orig) + 1; + buf = (char *) __ckd_malloc__(len, caller_file, caller_line); + + strcpy(buf, orig); + return (buf); +} + + +void * +__ckd_calloc_2d__(size_t d1, size_t d2, size_t elemsize, + const char *caller_file, int caller_line) +{ + char **ref, *mem; + size_t i, offset; + + mem = + (char *) __ckd_calloc__(d1 * d2, elemsize, caller_file, + caller_line); + ref = + (char **) __ckd_malloc__(d1 * sizeof(void *), caller_file, + caller_line); + + for (i = 0, offset = 0; i < d1; i++, offset += d2 * elemsize) + ref[i] = mem + offset; + + return ref; +} + + +void +ckd_free(void *ptr) +{ +#if defined(__ADSPBLACKFIN__) && !defined(__linux__) + if (ptr) + heap_free(0,ptr); +#else + free(ptr); +#endif +} + +void +ckd_free_2d(void *tmpptr) +{ + void **ptr = (void **)tmpptr; + if (ptr) + ckd_free(ptr[0]); + ckd_free(ptr); +} + + +void * +__ckd_calloc_3d__(size_t d1, size_t d2, size_t d3, size_t elemsize, + const char *caller_file, int caller_line) +{ + char ***ref1, **ref2, *mem; + size_t i, j, offset; + + mem = + (char *) __ckd_calloc__(d1 * d2 * d3, elemsize, caller_file, + caller_line); + ref1 = + (char ***) __ckd_malloc__(d1 * sizeof(void **), caller_file, + caller_line); + ref2 = + (char **) __ckd_malloc__(d1 * d2 * sizeof(void *), caller_file, + caller_line); + + for (i = 0, offset = 0; i < d1; i++, offset += d2) + ref1[i] = ref2 + offset; + + offset = 0; + for (i = 0; i < d1; i++) { + for (j = 0; j < d2; j++) { + ref1[i][j] = mem + offset; + offset += d3 * elemsize; + } + } + + return ref1; +} + + +void +ckd_free_3d(void *inptr) +{ + void ***ptr = (void ***)inptr; + + if (ptr && ptr[0]) + ckd_free(ptr[0][0]); + if (ptr) + ckd_free(ptr[0]); + ckd_free(ptr); +} + + +void **** +__ckd_calloc_4d__(size_t d1, + size_t d2, + size_t d3, + size_t d4, + size_t elem_size, + char *file, + int line) +{ + void *store; + void **tmp1; + void ***tmp2; + void ****out; + size_t i, j; + + store = calloc(d1 * d2 * d3 * d4, elem_size); + if (store == NULL) { + E_FATAL("ckd_calloc_4d failed for caller at %s(%d) at %s(%d)\n", + file, line, __FILE__, __LINE__); + } + + tmp1 = calloc(d1 * d2 * d3, sizeof(void *)); + if (tmp1 == NULL) { + E_FATAL("ckd_calloc_4d failed for caller at %s(%d) at %s(%d)\n", + file, line, __FILE__, __LINE__); + } + + tmp2 = ckd_calloc(d1 * d2, sizeof(void **)); + if (tmp2 == NULL) { + E_FATAL("ckd_calloc_4d failed for caller at %s(%d) at %s(%d)\n", + file, line, __FILE__, __LINE__); + } + + out = ckd_calloc(d1, sizeof(void ***)); + if (out == NULL) { + E_FATAL("ckd_calloc_4d failed for caller at %s(%d) at %s(%d)\n", + file, line, __FILE__, __LINE__); + } + + for (i = 0, j = 0; i < d1*d2*d3; i++, j += d4) { + tmp1[i] = &((char *)store)[j*elem_size]; + } + + for (i = 0, j = 0; i < d1*d2; i++, j += d3) { + tmp2[i] = &tmp1[j]; + } + + for (i = 0, j = 0; i < d1; i++, j += d2) { + out[i] = &tmp2[j]; + } + + return out; +} + +void +ckd_free_4d(void *inptr) +{ + void ****ptr = (void ****)inptr; + if (ptr == NULL) + return; + /* free the underlying store */ + ckd_free(ptr[0][0][0]); + + /* free the access overhead */ + ckd_free(ptr[0][0]); + ckd_free(ptr[0]); + ckd_free(ptr); +} + +/* Layers a 3d array access structure over a preallocated storage area */ +void * +__ckd_alloc_3d_ptr(size_t d1, + size_t d2, + size_t d3, + void *store, + size_t elem_size, + char *file, + int line) +{ + void **tmp1; + void ***out; + size_t i, j; + + tmp1 = __ckd_calloc__(d1 * d2, sizeof(void *), file, line); + + out = __ckd_calloc__(d1, sizeof(void **), file, line); + + for (i = 0, j = 0; i < d1*d2; i++, j += d3) { + tmp1[i] = &((char *)store)[j*elem_size]; + } + + for (i = 0, j = 0; i < d1; i++, j += d2) { + out[i] = &tmp1[j]; + } + + return out; +} + +void * +__ckd_alloc_2d_ptr(size_t d1, + size_t d2, + void *store, + size_t elem_size, + char *file, + int line) +{ + void **out; + size_t i, j; + + out = __ckd_calloc__(d1, sizeof(void *), file, line); + + for (i = 0, j = 0; i < d1; i++, j += d2) { + out[i] = &((char *)store)[j*elem_size]; + } + + return out; +} + +/* vim: set ts=4 sw=4: */ diff --git a/media/sphinxbase/src/libsphinxbase/util/cmd_ln.c b/media/sphinxbase/src/libsphinxbase/util/cmd_ln.c new file mode 100644 index 000000000..962482995 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/cmd_ln.c @@ -0,0 +1,1082 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * cmd_ln.c -- Command line argument parsing. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * + * 10-Sep-1998 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Changed strcasecmp() call in cmp_name() to strcmp_nocase() call. + * + * 15-Jul-1997 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Added required arguments handling. + * + * 07-Dec-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Created, based on Eric's implementation. Basically, combined several + * functions into one, eliminated validation, and simplified the interface. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#ifdef _MSC_VER +#pragma warning (disable: 4996 4018) +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "sphinxbase/cmd_ln.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/hash_table.h" +#include "sphinxbase/case.h" +#include "sphinxbase/strfuncs.h" + +typedef struct cmd_ln_val_s { + anytype_t val; + int type; +} cmd_ln_val_t; + +struct cmd_ln_s { + int refcount; + hash_table_t *ht; + char **f_argv; + uint32 f_argc; +}; + +/** Global command-line, for non-reentrant API. */ +cmd_ln_t *global_cmdln; + +static void +arg_dump_r(cmd_ln_t *, FILE *, arg_t const *, int32); + +static cmd_ln_t * +parse_options(cmd_ln_t *, const arg_t *, int32, char* [], int32); + +/* + * Find max length of name and default fields in the given defn array. + * Return #items in defn array. + */ +static int32 +arg_strlen(const arg_t * defn, int32 * namelen, int32 * deflen) +{ + int32 i, l; + + *namelen = *deflen = 0; + for (i = 0; defn[i].name; i++) { + l = strlen(defn[i].name); + if (*namelen < l) + *namelen = l; + + if (defn[i].deflt) + l = strlen(defn[i].deflt); + else + l = strlen("(null)"); + /* E_INFO("string default, %s , name %s, length %d\n",defn[i].deflt,defn[i].name,l); */ + if (*deflen < l) + *deflen = l; + } + + return i; +} + + +static int32 +cmp_name(const void *a, const void *b) +{ + return (strcmp_nocase + ((* (arg_t**) a)->name, + (* (arg_t**) b)->name)); +} + +static arg_t const ** +arg_sort(const arg_t * defn, int32 n) +{ + const arg_t ** pos; + int32 i; + + pos = (arg_t const **) ckd_calloc(n, sizeof(arg_t *)); + for (i = 0; i < n; ++i) + pos[i] = &defn[i]; + qsort(pos, n, sizeof(arg_t *), cmp_name); + + return pos; +} + +static size_t +strnappend(char **dest, size_t *dest_allocation, + const char *source, size_t n) +{ + size_t source_len, required_allocation; + + if (dest == NULL || dest_allocation == NULL) + return -1; + if (*dest == NULL && *dest_allocation != 0) + return -1; + if (source == NULL) + return *dest_allocation; + + source_len = strlen(source); + if (n && n < source_len) + source_len = n; + + required_allocation = (*dest ? strlen(*dest) : 0) + source_len + 1; + if (*dest_allocation < required_allocation) { + if (*dest_allocation == 0) { + *dest = (char *)ckd_calloc(required_allocation * 2, 1); + } else { + *dest = (char *)ckd_realloc(*dest, required_allocation * 2); + } + *dest_allocation = required_allocation * 2; + } + + strncat(*dest, source, source_len); + + return *dest_allocation; +} + +static size_t +strappend(char **dest, size_t *dest_allocation, + const char *source) +{ + return strnappend(dest, dest_allocation, source, 0); +} + +static char* +arg_resolve_env(const char *str) +{ + char *resolved_str = NULL; + char env_name[100]; + const char *env_val; + size_t alloced = 0; + const char *i = str, *j; + + /* calculate required resolved_str size */ + do { + j = strstr(i, "$("); + if (j != NULL) { + if (j != i) { + strnappend(&resolved_str, &alloced, i, j - i); + i = j; + } + j = strchr(i + 2, ')'); + if (j != NULL) { + if (j - (i + 2) < 100) { + strncpy(env_name, i + 2, j - (i + 2)); + env_name[j - (i + 2)] = '\0'; + #if !defined(_WIN32_WCE) + env_val = getenv(env_name); + if (env_val) + strappend(&resolved_str, &alloced, env_val); + #else + env_val = 0; + #endif + } + i = j + 1; + } else { + /* unclosed, copy and skip */ + j = i + 2; + strnappend(&resolved_str, &alloced, i, j - i); + i = j; + } + } else { + strappend(&resolved_str, &alloced, i); + } + } while(j != NULL); + + return resolved_str; +} + +static void +arg_dump_r(cmd_ln_t *cmdln, FILE *fp, const arg_t * defn, int32 doc) +{ + arg_t const **pos; + int32 i, n; + size_t l; + int32 namelen, deflen; + anytype_t *vp; + char const **array; + + /* No definitions, do nothing. */ + if (defn == NULL || fp == NULL) + return; + + /* Find max lengths of name and default value fields, and #entries in defn */ + n = arg_strlen(defn, &namelen, &deflen); + /* E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */ + namelen = namelen & 0xfffffff8; /* Previous tab position */ + deflen = deflen & 0xfffffff8; /* Previous tab position */ + + fprintf(fp, "[NAME]"); + for (l = strlen("[NAME]"); l < namelen; l += 8) + fprintf(fp, "\t"); + fprintf(fp, "\t[DEFLT]"); + for (l = strlen("[DEFLT]"); l < deflen; l += 8) + fprintf(fp, "\t"); + + if (doc) { + fprintf(fp, "\t[DESCR]\n"); + } + else { + fprintf(fp, "\t[VALUE]\n"); + } + + /* Print current configuration, sorted by name */ + pos = arg_sort(defn, n); + for (i = 0; i < n; i++) { + fprintf(fp, "%s", pos[i]->name); + for (l = strlen(pos[i]->name); l < namelen; l += 8) + fprintf(fp, "\t"); + + fprintf(fp, "\t"); + if (pos[i]->deflt) { + fprintf(fp, "%s", pos[i]->deflt); + l = strlen(pos[i]->deflt); + } + else + l = 0; + for (; l < deflen; l += 8) + fprintf(fp, "\t"); + + fprintf(fp, "\t"); + if (doc) { + if (pos[i]->doc) + fprintf(fp, "%s", pos[i]->doc); + } + else { + vp = cmd_ln_access_r(cmdln, pos[i]->name); + if (vp) { + switch (pos[i]->type) { + case ARG_INTEGER: + case REQARG_INTEGER: + fprintf(fp, "%ld", vp->i); + break; + case ARG_FLOATING: + case REQARG_FLOATING: + fprintf(fp, "%e", vp->fl); + break; + case ARG_STRING: + case REQARG_STRING: + if (vp->ptr) + fprintf(fp, "%s", (char *)vp->ptr); + break; + case ARG_STRING_LIST: + array = (char const**)vp->ptr; + if (array) + for (l = 0; array[l] != 0; l++) { + fprintf(fp, "%s,", array[l]); + } + break; + case ARG_BOOLEAN: + case REQARG_BOOLEAN: + fprintf(fp, "%s", vp->i ? "yes" : "no"); + break; + default: + E_ERROR("Unknown argument type: %d\n", pos[i]->type); + } + } + } + + fprintf(fp, "\n"); + } + ckd_free(pos); + + fprintf(fp, "\n"); +} + +static char ** +parse_string_list(const char *str) +{ + int count, i, j; + const char *p; + char **result; + + p = str; + count = 1; + while (*p) { + if (*p == ',') + count++; + p++; + } + /* Should end with NULL */ + result = (char **) ckd_calloc(count + 1, sizeof(char *)); + p = str; + for (i = 0; i < count; i++) { + for (j = 0; p[j] != ',' && p[j] != 0; j++); + result[i] = (char *)ckd_calloc(j + 1, sizeof(char)); + strncpy( result[i], p, j); + p = p + j + 1; + } + return result; +} + +static cmd_ln_val_t * +cmd_ln_val_init(int t, const char *str) +{ + cmd_ln_val_t *v; + anytype_t val; + char *e_str; + + if (!str) { + /* For lack of a better default value. */ + memset(&val, 0, sizeof(val)); + } + else { + int valid = 1; + e_str = arg_resolve_env(str); + + switch (t) { + case ARG_INTEGER: + case REQARG_INTEGER: + if (sscanf(e_str, "%ld", &val.i) != 1) + valid = 0; + break; + case ARG_FLOATING: + case REQARG_FLOATING: + if (e_str == NULL || e_str[0] == 0) + valid = 0; + val.fl = atof_c(e_str); + break; + case ARG_BOOLEAN: + case REQARG_BOOLEAN: + if ((e_str[0] == 'y') || (e_str[0] == 't') || + (e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) { + val.i = TRUE; + } + else if ((e_str[0] == 'n') || (e_str[0] == 'f') || + (e_str[0] == 'N') || (e_str[0] == 'F') | + (e_str[0] == '0')) { + val.i = FALSE; + } + else { + E_ERROR("Unparsed boolean value '%s'\n", str); + valid = 0; + } + break; + case ARG_STRING: + case REQARG_STRING: + val.ptr = ckd_salloc(e_str); + break; + case ARG_STRING_LIST: + val.ptr = parse_string_list(e_str); + break; + default: + E_ERROR("Unknown argument type: %d\n", t); + valid = 0; + } + + ckd_free(e_str); + if (valid == 0) + return NULL; + } + + v = (cmd_ln_val_t *)ckd_calloc(1, sizeof(*v)); + memcpy(v, &val, sizeof(val)); + v->type = t; + + return v; +} + +/* + * Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init() + * also takes care of storing argv. + * DO NOT call it from cmd_ln_parse_r() + */ +static cmd_ln_t * +parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict) +{ + cmd_ln_t *new_cmdln; + + new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict); + /* If this failed then clean up and return NULL. */ + if (new_cmdln == NULL) { + int32 i; + for (i = 0; i < argc; ++i) + ckd_free(argv[i]); + ckd_free(argv); + return NULL; + } + + /* Otherwise, we need to add the contents of f_argv to the new object. */ + if (new_cmdln == cmdln) { + /* If we are adding to a previously passed-in cmdln, then + * store our allocated strings in its f_argv. */ + new_cmdln->f_argv = (char **)ckd_realloc(new_cmdln->f_argv, + (new_cmdln->f_argc + argc) + * sizeof(*new_cmdln->f_argv)); + memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv, + argc * sizeof(*argv)); + ckd_free(argv); + new_cmdln->f_argc += argc; + } + else { + /* Otherwise, store f_argc and f_argv. */ + new_cmdln->f_argc = argc; + new_cmdln->f_argv = argv; + } + + return new_cmdln; +} + +void +cmd_ln_val_free(cmd_ln_val_t *val) +{ + int i; + if (val->type & ARG_STRING_LIST) { + char ** array = (char **)val->val.ptr; + if (array) { + for (i = 0; array[i] != NULL; i++) { + ckd_free(array[i]); + } + ckd_free(array); + } + } + if (val->type & ARG_STRING) + ckd_free(val->val.ptr); + ckd_free(val); +} + +cmd_ln_t * +cmd_ln_get(void) +{ + return global_cmdln; +} + +void +cmd_ln_appl_enter(int argc, char *argv[], + const char *default_argfn, + const arg_t * defn) +{ + /* Look for default or specified arguments file */ + const char *str; + + str = NULL; + + if ((argc == 2) && (strcmp(argv[1], "help") == 0)) { + cmd_ln_print_help(stderr, defn); + exit(1); + } + + if ((argc == 2) && (argv[1][0] != '-')) + str = argv[1]; + else if (argc == 1) { + FILE *fp; + E_INFO("Looking for default argument file: %s\n", default_argfn); + + if ((fp = fopen(default_argfn, "r")) == NULL) { + E_INFO("Can't find default argument file %s.\n", + default_argfn); + } + else { + str = default_argfn; + } + if (fp != NULL) + fclose(fp); + } + + + if (str) { + /* Build command line argument list from file */ + E_INFO("Parsing command lines from file %s\n", str); + if (cmd_ln_parse_file(defn, str, TRUE)) { + E_INFOCONT("Usage:\n"); + E_INFOCONT("\t%s argument-list, or\n", argv[0]); + E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n", + argv[0], default_argfn); + cmd_ln_print_help(stderr, defn); + exit(1); + } + } + else { + cmd_ln_parse(defn, argc, argv, TRUE); + } +} + +void +cmd_ln_appl_exit() +{ + cmd_ln_free(); +} + + +cmd_ln_t * +cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict) +{ + int32 i, j, n, argstart; + hash_table_t *defidx = NULL; + cmd_ln_t *cmdln; + + /* Construct command-line object */ + if (inout_cmdln == NULL) { + cmdln = (cmd_ln_t*)ckd_calloc(1, sizeof(*cmdln)); + cmdln->refcount = 1; + } + else + cmdln = inout_cmdln; + + /* Build a hash table for argument definitions */ + defidx = hash_table_new(50, 0); + if (defn) { + for (n = 0; defn[n].name; n++) { + void *v; + + v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]); + if (strict && (v != &defn[n])) { + E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name); + goto error; + } + } + } + else { + /* No definitions. */ + n = 0; + } + + /* Allocate memory for argument values */ + if (cmdln->ht == NULL) + cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ ); + + + /* skip argv[0] if it doesn't start with dash */ + argstart = 0; + if (argc > 0 && argv[0][0] != '-') { + argstart = 1; + } + + /* Parse command line arguments (name-value pairs) */ + for (j = argstart; j < argc; j += 2) { + arg_t *argdef; + cmd_ln_val_t *val; + void *v; + + if (hash_table_lookup(defidx, argv[j], &v) < 0) { + if (strict) { + E_ERROR("Unknown argument name '%s'\n", argv[j]); + goto error; + } + else if (defn == NULL) + v = NULL; + else + continue; + } + argdef = (arg_t *)v; + + /* Enter argument value */ + if (j + 1 >= argc) { + cmd_ln_print_help_r(cmdln, stderr, defn); + E_ERROR("Argument value for '%s' missing\n", argv[j]); + goto error; + } + + if (argdef == NULL) + val = cmd_ln_val_init(ARG_STRING, argv[j + 1]); + else { + if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) { + cmd_ln_print_help_r(cmdln, stderr, defn); + E_ERROR("Bad argument value for %s: %s\n", argv[j], + argv[j + 1]); + goto error; + } + } + + if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != + (void *)val) + { + if (strict) { + cmd_ln_val_free(val); + E_ERROR("Duplicate argument name in arguments: %s\n", + argdef->name); + goto error; + } + else { + v = hash_table_replace(cmdln->ht, argv[j], (void *)val); + cmd_ln_val_free((cmd_ln_val_t *)v); + } + } + } + + /* Fill in default values, if any, for unspecified arguments */ + for (i = 0; i < n; i++) { + cmd_ln_val_t *val; + void *v; + + if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) { + if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) { + E_ERROR + ("Bad default argument value for %s: %s\n", + defn[i].name, defn[i].deflt); + goto error; + } + hash_table_enter(cmdln->ht, defn[i].name, (void *)val); + } + } + + /* Check for required arguments; exit if any missing */ + j = 0; + for (i = 0; i < n; i++) { + if (defn[i].type & ARG_REQUIRED) { + void *v; + if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0) + E_ERROR("Missing required argument %s\n", defn[i].name); + } + } + if (j > 0) { + cmd_ln_print_help_r(cmdln, stderr, defn); + goto error; + } + + if (strict && argc == 1) { + E_ERROR("No arguments given, available options are:\n"); + cmd_ln_print_help_r(cmdln, stderr, defn); + if (defidx) + hash_table_free(defidx); + if (inout_cmdln == NULL) + cmd_ln_free_r(cmdln); + return NULL; + } + +#ifndef _WIN32_WCE + /* Set up logging. We need to do this earlier because we want to dump + * the information to the configured log, not to the stderr. */ + if (cmd_ln_exists_r(cmdln, "-logfn") && cmd_ln_str_r(cmdln, "-logfn")) { + if (err_set_logfile(cmd_ln_str_r(cmdln, "-logfn")) < 0) + E_FATAL_SYSTEM("cannot redirect log output"); + } + + /* Echo command line */ + E_INFO("Parsing command line:\n"); + for (i = 0; i < argc; i++) { + if (argv[i][0] == '-') + E_INFOCONT("\\\n\t"); + E_INFOCONT("%s ", argv[i]); + } + E_INFOCONT("\n\n"); + + /* Print configuration */ + E_INFOCONT("Current configuration:\n"); + arg_dump_r(cmdln, err_get_logfp(), defn, 0); +#endif + + hash_table_free(defidx); + return cmdln; + + error: + if (defidx) + hash_table_free(defidx); + if (inout_cmdln == NULL) + cmd_ln_free_r(cmdln); + E_ERROR("Failed to parse arguments list\n"); + return NULL; +} + +cmd_ln_t * +cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...) +{ + va_list args; + const char *arg, *val; + char **f_argv; + int32 f_argc; + + va_start(args, strict); + f_argc = 0; + while ((arg = va_arg(args, const char *))) { + ++f_argc; + val = va_arg(args, const char*); + if (val == NULL) { + E_ERROR("Number of arguments must be even!\n"); + return NULL; + } + ++f_argc; + } + va_end(args); + + /* Now allocate f_argv */ + f_argv = (char**)ckd_calloc(f_argc, sizeof(*f_argv)); + va_start(args, strict); + f_argc = 0; + while ((arg = va_arg(args, const char *))) { + f_argv[f_argc] = ckd_salloc(arg); + ++f_argc; + val = va_arg(args, const char*); + f_argv[f_argc] = ckd_salloc(val); + ++f_argc; + } + va_end(args); + + return parse_options(inout_cmdln, defn, f_argc, f_argv, strict); +} + +int +cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict) +{ + cmd_ln_t *cmdln; + + cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict); + if (cmdln == NULL) { + /* Old, bogus behaviour... */ + E_ERROR("Failed to parse arguments list, forced exit\n"); + exit(-1); + } + /* Initialize global_cmdln if not present. */ + if (global_cmdln == NULL) { + global_cmdln = cmdln; + } + return 0; +} + +cmd_ln_t * +cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict) +{ + FILE *file; + int argc; + int argv_size; + char *str; + int arg_max_length = 512; + int len = 0; + int quoting, ch; + char **f_argv; + int rv = 0; + const char separator[] = " \t\r\n"; + + if ((file = fopen(filename, "r")) == NULL) { + E_ERROR("Cannot open configuration file %s for reading\n", + filename); + return NULL; + } + + ch = fgetc(file); + /* Skip to the next interesting character */ + for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; + + if (ch == EOF) { + fclose(file); + return NULL; + } + + /* + * Initialize default argv, argc, and argv_size. + */ + argv_size = 10; + argc = 0; + f_argv = (char **)ckd_calloc(argv_size, sizeof(char *)); + /* Silently make room for \0 */ + str = (char* )ckd_calloc(arg_max_length + 1, sizeof(char)); + quoting = 0; + + do { + /* Handle arguments that are commented out */ + if (len == 0 && argc % 2 == 0) { + while (ch == '#') { + /* Skip everything until newline */ + for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ; + /* Skip to the next interesting character */ + for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; + } + + /* Check if we are at the last line (without anything interesting in it) */ + if (ch == EOF) + break; + } + + /* Handle quoted arguments */ + if (ch == '"' || ch == '\'') { + if (quoting == ch) /* End a quoted section with the same type */ + quoting = 0; + else if (quoting) { + E_ERROR("Nesting quotations is not supported!\n"); + rv = 1; + break; + } + else + quoting = ch; /* Start a quoted section */ + } + else if (ch == EOF || (!quoting && strchr(separator, ch))) { + /* Reallocate argv so it is big enough to contain all the arguments */ + if (argc >= argv_size) { + char **tmp_argv; + if (!(tmp_argv = + (char **)ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) { + rv = 1; + break; + } + f_argv = tmp_argv; + argv_size *= 2; + } + /* Add the string to the list of arguments */ + f_argv[argc] = ckd_salloc(str); + len = 0; + str[0] = '\0'; + argc++; + + if (quoting) + E_WARN("Unclosed quotation, having EOF close it...\n"); + + /* Skip to the next interesting character */ + for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; + + if (ch == EOF) + break; + + /* We already have the next character */ + continue; + } + else { + if (len >= arg_max_length) { + /* Make room for more chars (including the \0 !) */ + char *tmp_str = str; + if ((tmp_str = (char *)ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) { + rv = 1; + break; + } + str = tmp_str; + arg_max_length *= 2; + } + /* Add the char to the argument string */ + str[len++] = ch; + /* Always null terminate */ + str[len] = '\0'; + } + + ch = fgetc(file); + } while (1); + + fclose(file); + + ckd_free(str); + + if (rv) { + for (ch = 0; ch < argc; ++ch) + ckd_free(f_argv[ch]); + ckd_free(f_argv); + return NULL; + } + + return parse_options(inout_cmdln, defn, argc, f_argv, strict); +} + +int +cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict) +{ + cmd_ln_t *cmdln; + + cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict); + if (cmdln == NULL) { + return -1; + } + /* Initialize global_cmdln if not present. */ + if (global_cmdln == NULL) { + global_cmdln = cmdln; + } + return 0; +} + +void +cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE *fp, arg_t const* defn) +{ + if (defn == NULL) + return; + fprintf(fp, "Arguments list definition:\n"); + arg_dump_r(cmdln, fp, defn, 1); +} + +int +cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name) +{ + void *val; + if (cmdln == NULL) + return FALSE; + return (hash_table_lookup(cmdln->ht, name, &val) == 0); +} + +anytype_t * +cmd_ln_access_r(cmd_ln_t *cmdln, const char *name) +{ + void *val; + if (hash_table_lookup(cmdln->ht, name, &val) < 0) { + E_ERROR("Unknown argument: %s\n", name); + return NULL; + } + return (anytype_t *)val; +} + +char const * +cmd_ln_str_r(cmd_ln_t *cmdln, char const *name) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) + return NULL; + return (char const *)val->ptr; +} + +char const ** +cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) + return NULL; + return (char const **)val->ptr; +} + +long +cmd_ln_int_r(cmd_ln_t *cmdln, char const *name) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) + return 0L; + return val->i; +} + +double +cmd_ln_float_r(cmd_ln_t *cmdln, char const *name) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) + return 0.0; + return val->fl; +} + +void +cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) { + E_ERROR("Unknown argument: %s\n", name); + return; + } + ckd_free(val->ptr); + if (str == NULL) + val->ptr = NULL; + else + val->ptr = ckd_salloc(str); +} + +void +cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) { + E_ERROR("Unknown argument: %s\n", name); + return; + } + val->i = iv; +} + +void +cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv) +{ + anytype_t *val; + val = cmd_ln_access_r(cmdln, name); + if (val == NULL) { + E_ERROR("Unknown argument: %s\n", name); + return; + } + val->fl = fv; +} + +cmd_ln_t * +cmd_ln_retain(cmd_ln_t *cmdln) +{ + ++cmdln->refcount; + return cmdln; +} + +int +cmd_ln_free_r(cmd_ln_t *cmdln) +{ + if (cmdln == NULL) + return 0; + if (--cmdln->refcount > 0) + return cmdln->refcount; + + if (cmdln->ht) { + glist_t entries; + gnode_t *gn; + int32 n; + + entries = hash_table_tolist(cmdln->ht, &n); + for (gn = entries; gn; gn = gnode_next(gn)) { + hash_entry_t *e = (hash_entry_t *)gnode_ptr(gn); + cmd_ln_val_free((cmd_ln_val_t *)e->val); + } + glist_free(entries); + hash_table_free(cmdln->ht); + cmdln->ht = NULL; + } + + if (cmdln->f_argv) { + int32 i; + for (i = 0; i < cmdln->f_argc; ++i) { + ckd_free(cmdln->f_argv[i]); + } + ckd_free(cmdln->f_argv); + cmdln->f_argv = NULL; + cmdln->f_argc = 0; + } + ckd_free(cmdln); + return 0; +} + +void +cmd_ln_free(void) +{ + cmd_ln_free_r(global_cmdln); + global_cmdln = NULL; +} + +/* vim: set ts=4 sw=4: */ diff --git a/media/sphinxbase/src/libsphinxbase/util/dtoa.c b/media/sphinxbase/src/libsphinxbase/util/dtoa.c new file mode 100644 index 000000000..4673ae003 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/dtoa.c @@ -0,0 +1,2979 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/**************************************************************** + * This is dtoa.c by David M. Gay, downloaded from + * http://www.netlib.org/fp/dtoa.c on April 15, 2009 and modified for + * inclusion into the Python core by Mark E. T. Dickinson and Eric V. Smith. + * It was taken from Python distribution then and imported into sphinxbase. + * Python version is preferred due to cleanups, though original + * version at netlib is still maintained. + * + * Please remember to check http://www.netlib.org/fp regularly for bugfixes and updates. + * + * The major modifications from Gay's original code are as follows: + * + * 0. The original code has been specialized to Sphinxbase's needs by removing + * many of the #ifdef'd sections. In particular, code to support VAX and + * IBM floating-point formats, hex NaNs, hex floats, locale-aware + * treatment of the decimal point, and setting of the inexact flag have + * been removed. + * + * 1. We use cdk_calloc and ckd_free in place of malloc and free. + * + * 2. The public functions strtod, dtoa and freedtoa all now have + * a sb_ prefix. + * + * 3. Instead of assuming that malloc always succeeds, we thread + * malloc failures through the code. The functions + * + * Balloc, multadd, s2b, i2b, mult, pow5mult, lshift, diff, d2b + * + * of return type *Bigint all return NULL to indicate a malloc failure. + * Similarly, rv_alloc and nrv_alloc (return type char *) return NULL on + * failure. bigcomp now has return type int (it used to be void) and + * returns -1 on failure and 0 otherwise. sb_dtoa returns NULL + * on failure. sb_strtod indicates failure due to malloc failure + * by returning -1.0, setting errno=ENOMEM and *se to s00. + * + * 4. The static variable dtoa_result has been removed. Callers of + * sb_dtoa are expected to call sb_freedtoa to free the memory allocated + * by sb_dtoa. + * + * 5. The code has been reformatted to better fit with C style. + * + * 6. A bug in the memory allocation has been fixed: to avoid FREEing memory + * that hasn't been MALLOC'ed, private_mem should only be used when k <= + * Kmax. + * + * 7. sb_strtod has been modified so that it doesn't accept strings with + * leading whitespace. + * + ***************************************************************/ + +/* Please send bug reports for the original dtoa.c code to David M. Gay (dmg + * at acm dot org, with " at " changed at "@" and " dot " changed to "."). + */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* Linking of sphinxbase's #defines to Gay's #defines starts here. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> + +#include <sphinxbase/ckd_alloc.h> +#include <sphinxbase/prim_type.h> + +#ifdef WORDS_BIGENDIAN +#define IEEE_MC68k +#else +#define IEEE_8087 +#endif + +#define Long int32 /* ZOMG */ +#define ULong uint32 /* WTF */ +#ifdef HAVE_LONG_LONG +#define ULLong uint64 +#endif + +#define MALLOC ckd_malloc +#define FREE ckd_free + +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 + +/* maximum permitted exponent value for strtod; exponents larger than + MAX_ABS_EXP in absolute value get truncated to +-MAX_ABS_EXP. MAX_ABS_EXP + should fit into an int. */ +#ifndef MAX_ABS_EXP +#define MAX_ABS_EXP 1100000000U +#endif +/* Bound on length of pieces of input strings in sb_strtod; specifically, + this is used to bound the total number of digits ignoring leading zeros and + the number of digits that follow the decimal point. Ideally, MAX_DIGITS + should satisfy MAX_DIGITS + 400 < MAX_ABS_EXP; that ensures that the + exponent clipping in sb_strtod can't affect the value of the output. */ +#ifndef MAX_DIGITS +#define MAX_DIGITS 1000000000U +#endif + +/* End sphinxbase #define linking */ + +#ifdef DEBUG +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef IEEE_8087 +#define word0(x) (x)->L[1] +#define word1(x) (x)->L[0] +#else +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] +#endif +#define dval(x) (x)->d + +#ifndef STRTOD_DIGLIM +#define STRTOD_DIGLIM 40 +#endif + +/* maximum permitted exponent value for strtod; exponents larger than + MAX_ABS_EXP in absolute value get truncated to +-MAX_ABS_EXP. MAX_ABS_EXP + should fit into an int. */ +#ifndef MAX_ABS_EXP +#define MAX_ABS_EXP 1100000000U +#endif +/* Bound on length of pieces of input strings in sb_strtod; specifically, + this is used to bound the total number of digits ignoring leading zeros and + the number of digits that follow the decimal point. Ideally, MAX_DIGITS + should satisfy MAX_DIGITS + 400 < MAX_ABS_EXP; that ensures that the + exponent clipping in sb_strtod can't affect the value of the output. */ +#ifndef MAX_DIGITS +#define MAX_DIGITS 1000000000U +#endif + +/* Guard against trying to use the above values on unusual platforms with ints + * of width less than 32 bits. */ +#if MAX_ABS_EXP > 0x7fffffff +#error "MAX_ABS_EXP should fit in an int" +#endif +#if MAX_DIGITS > 0x7fffffff +#error "MAX_DIGITS should fit in an int" +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ + ((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ + ((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Nbits 53 +#define Bias 1023 +#define Emax 1023 +#define Emin (-1022) +#define Etiny (-1074) /* smallest denormal is 2**Etiny */ +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#define Rounding Flt_Rounds + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +/* Standard NaN used by sb_stdnan. */ + +#define NAN_WORD0 0x7ff80000 +#define NAN_WORD1 0 + +/* Bits of the representation of positive infinity. */ + +#define POSINF_WORD0 0x7ff00000 +#define POSINF_WORD1 0 + +/* struct BCinfo is used to pass information from sb_strtod to bigcomp */ + +typedef struct BCinfo BCinfo; +struct +BCinfo { + int e0, nd, nd0, scale; +}; + +#define FFFFFFFF 0xffffffffUL + +#define Kmax 7 + +/* struct Bigint is used to represent arbitrary-precision integers. These + integers are stored in sign-magnitude format, with the magnitude stored as + an array of base 2**32 digits. Bigints are always normalized: if x is a + Bigint then x->wds >= 1, and either x->wds == 1 or x[wds-1] is nonzero. + + The Bigint fields are as follows: + + - next is a header used by Balloc and Bfree to keep track of lists + of freed Bigints; it's also used for the linked list of + powers of 5 of the form 5**2**i used by pow5mult. + - k indicates which pool this Bigint was allocated from + - maxwds is the maximum number of words space was allocated for + (usually maxwds == 2**k) + - sign is 1 for negative Bigints, 0 for positive. The sign is unused + (ignored on inputs, set to 0 on outputs) in almost all operations + involving Bigints: a notable exception is the diff function, which + ignores signs on inputs but sets the sign of the output correctly. + - wds is the actual number of significant words + - x contains the vector of words (digits) for this Bigint, from least + significant (x[0]) to most significant (x[wds-1]). +*/ + +struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; +}; + +typedef struct Bigint Bigint; + +#ifndef Py_USING_MEMORY_DEBUGGER + +/* Memory management: memory is allocated from, and returned to, Kmax+1 pools + of memory, where pool k (0 <= k <= Kmax) is for Bigints b with b->maxwds == + 1 << k. These pools are maintained as linked lists, with freelist[k] + pointing to the head of the list for pool k. + + On allocation, if there's no free slot in the appropriate pool, MALLOC is + called to get more memory. This memory is not returned to the system until + Python quits. There's also a private memory pool that's allocated from + in preference to using MALLOC. + + For Bigints with more than (1 << Kmax) digits (which implies at least 1233 + decimal digits), memory is directly allocated using MALLOC, and freed using + FREE. + + XXX: it would be easy to bypass this memory-management system and + translate each call to Balloc into a call to PyMem_Malloc, and each + Bfree to PyMem_Free. Investigate whether this has any significant + performance on impact. */ + +static Bigint *freelist[Kmax+1]; + +/* Allocate space for a Bigint with up to 1<<k digits */ + +static Bigint * +Balloc(int k) +{ + int x; + Bigint *rv; + unsigned int len; + + if (k <= Kmax && (rv = freelist[k])) + freelist[k] = rv->next; + else { + x = 1 << k; + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else { + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (rv == NULL) + return NULL; + } + rv->k = k; + rv->maxwds = x; + } + rv->sign = rv->wds = 0; + return rv; +} + +/* Free a Bigint allocated with Balloc */ + +static void +Bfree(Bigint *v) +{ + if (v) { + if (v->k > Kmax) + FREE((void*)v); + else { + v->next = freelist[v->k]; + freelist[v->k] = v; + } + } +} + +#else + +/* Alternative versions of Balloc and Bfree that use PyMem_Malloc and + PyMem_Free directly in place of the custom memory allocation scheme above. + These are provided for the benefit of memory debugging tools like + Valgrind. */ + +/* Allocate space for a Bigint with up to 1<<k digits */ + +static Bigint * +Balloc(int k) +{ + int x; + Bigint *rv; + unsigned int len; + + x = 1 << k; + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + + rv = (Bigint*)MALLOC(len*sizeof(double)); + if (rv == NULL) + return NULL; + + rv->k = k; + rv->maxwds = x; + rv->sign = rv->wds = 0; + return rv; +} + +/* Free a Bigint allocated with Balloc */ + +static void +Bfree(Bigint *v) +{ + if (v) { + FREE((void*)v); + } +} + +#endif /* Py_USING_MEMORY_DEBUGGER */ + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ + y->wds*sizeof(Long) + 2*sizeof(int)) + +/* Multiply a Bigint b by m and add a. Either modifies b in place and returns + a pointer to the modified b, or Bfrees b and returns a pointer to a copy. + On failure, return NULL. In this case, b will have been already freed. */ + +static Bigint * +multadd(Bigint *b, int m, int a) /* multiply by m and add a */ +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; + ULong xi, z; +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = (ULong)(y & FFFFFFFF); +#else + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + if (b1 == NULL){ + Bfree(b); + return NULL; + } + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = (ULong)carry; + b->wds = wds; + } + return b; +} + +/* convert a string s containing nd decimal digits (possibly containing a + decimal separator at position nd0, which is ignored) to a Bigint. This + function carries on where the parsing code in sb_strtod leaves off: on + entry, y9 contains the result of converting the first 9 digits. Returns + NULL on failure. */ + +static Bigint * +s2b(const char *s, int nd0, int nd, ULong y9) +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; + b = Balloc(k); + if (b == NULL) + return NULL; + b->x[0] = y9; + b->wds = 1; + + if (nd <= 9) + return b; + + s += 9; + for (i = 9; i < nd0; i++) { + b = multadd(b, 10, *s++ - '0'); + if (b == NULL) + return NULL; + } + s++; + for(; i < nd; i++) { + b = multadd(b, 10, *s++ - '0'); + if (b == NULL) + return NULL; + } + return b; +} + +/* count leading 0 bits in the 32-bit integer x. */ + +static int +hi0bits(ULong x) +{ + int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; +} + +/* count trailing 0 bits in the 32-bit integer y, and shift y right by that + number of bits. */ + +static int +lo0bits(ULong *y) +{ + int k; + ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; +} + +/* convert a small nonnegative integer to a Bigint */ + +static Bigint * +i2b(int i) +{ + Bigint *b; + + b = Balloc(1); + if (b == NULL) + return NULL; + b->x[0] = i; + b->wds = 1; + return b; +} + +/* multiply two Bigints. Returns a new Bigint, or NULL on failure. Ignores + the signs of a and b. */ + +static Bigint * +mult(Bigint *a, Bigint *b) +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; + ULong z2; +#endif + + if ((!a->x[0] && a->wds == 1) || (!b->x[0] && b->wds == 1)) { + c = Balloc(0); + if (c == NULL) + return NULL; + c->wds = 1; + c->x[0] = 0; + return c; + } + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + if (c == NULL) + return NULL; + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if ((y = *xb++)) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = (ULong)(z & FFFFFFFF); + } + while(x < xae); + *xc = (ULong)carry; + } + } +#else + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; +} + +#ifndef Py_USING_MEMORY_DEBUGGER + +/* p5s is a linked list of powers of 5 of the form 5**(2**i), i >= 2 */ + +static Bigint *p5s; + +/* multiply the Bigint b by 5**k. Returns a pointer to the result, or NULL on + failure; if the returned pointer is distinct from b then the original + Bigint b will have been Bfree'd. Ignores the sign of b. */ + +static Bigint * +pow5mult(Bigint *b, int k) +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3)) { + b = multadd(b, p05[i-1], 0); + if (b == NULL) + return NULL; + } + + if (!(k >>= 2)) + return b; + p5 = p5s; + if (!p5) { + /* first time */ + p5 = i2b(625); + if (p5 == NULL) { + Bfree(b); + return NULL; + } + p5s = p5; + p5->next = 0; + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + if (b == NULL) + return NULL; + } + if (!(k >>= 1)) + break; + p51 = p5->next; + if (!p51) { + p51 = mult(p5,p5); + if (p51 == NULL) { + Bfree(b); + return NULL; + } + p51->next = 0; + p5->next = p51; + } + p5 = p51; + } + return b; +} + +#else + +/* Version of pow5mult that doesn't cache powers of 5. Provided for + the benefit of memory debugging tools like Valgrind. */ + +static Bigint * +pow5mult(Bigint *b, int k) +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3)) { + b = multadd(b, p05[i-1], 0); + if (b == NULL) + return NULL; + } + + if (!(k >>= 2)) + return b; + p5 = i2b(625); + if (p5 == NULL) { + Bfree(b); + return NULL; + } + + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + if (b == NULL) { + Bfree(p5); + return NULL; + } + } + if (!(k >>= 1)) + break; + p51 = mult(p5, p5); + Bfree(p5); + p5 = p51; + if (p5 == NULL) { + Bfree(b); + return NULL; + } + } + Bfree(p5); + return b; +} + +#endif /* Py_USING_MEMORY_DEBUGGER */ + +/* shift a Bigint b left by k bits. Return a pointer to the shifted result, + or NULL on failure. If the returned pointer is distinct from b then the + original b will have been Bfree'd. Ignores the sign of b. */ + +static Bigint * +lshift(Bigint *b, int k) +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + + if (!k || (!b->x[0] && b->wds == 1)) + return b; + + n = k >> 5; + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + if (b1 == NULL) { + Bfree(b); + return NULL; + } + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if ((*x1 = z)) + ++n1; + } + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; +} + +/* Do a three-way compare of a and b, returning -1 if a < b, 0 if a == b and + 1 if a > b. Ignores signs of a and b. */ + +static int +cmp(Bigint *a, Bigint *b) +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; +} + +/* Take the difference of Bigints a and b, returning a new Bigint. Returns + NULL on failure. The signs of a and b are ignored, but the sign of the + result is set appropriately. */ + +static Bigint * +diff(Bigint *a, Bigint *b) +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; + ULong z; +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + if (c == NULL) + return NULL; + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + if (c == NULL) + return NULL; + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong)(y & FFFFFFFF); + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong)(y & FFFFFFFF); + } +#else + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; +} + +/* Given a positive normal double x, return the difference between x and the + next double up. Doesn't give correct results for subnormals. */ + +static double +ulp(U *x) +{ + Long L; + U u; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; + word0(&u) = L; + word1(&u) = 0; + return dval(&u); +} + +/* Convert a Bigint to a double plus an exponent */ + +static double +b2d(Bigint *a, int *e) +{ + ULong *xa, *xa0, w, y, z; + int k; + U d; + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; + if (k < Ebits) { + word0(&d) = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + word1(&d) = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + word0(&d) = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + word1(&d) = z << k | y >> (32 - k); + } + else { + word0(&d) = Exp_1 | y; + word1(&d) = z; + } + ret_d: + return dval(&d); +} + +/* Convert a scaled double to a Bigint plus an exponent. Similar to d2b, + except that it accepts the scale parameter used in sb_strtod (which + should be either 0 or 2*P), and the normalization for the return value is + different (see below). On input, d should be finite and nonnegative, and d + / 2**scale should be exactly representable as an IEEE 754 double. + + Returns a Bigint b and an integer e such that + + dval(d) / 2**scale = b * 2**e. + + Unlike d2b, b is not necessarily odd: b and e are normalized so + that either 2**(P-1) <= b < 2**P and e >= Etiny, or b < 2**P + and e == Etiny. This applies equally to an input of 0.0: in that + case the return values are b = 0 and e = Etiny. + + The above normalization ensures that for all possible inputs d, + 2**e gives ulp(d/2**scale). + + Returns NULL on failure. +*/ + +static Bigint * +sd2b(U *d, int scale, int *e) +{ + Bigint *b; + + b = Balloc(1); + if (b == NULL) + return NULL; + + /* First construct b and e assuming that scale == 0. */ + b->wds = 2; + b->x[0] = word1(d); + b->x[1] = word0(d) & Frac_mask; + *e = Etiny - 1 + (int)((word0(d) & Exp_mask) >> Exp_shift); + if (*e < Etiny) + *e = Etiny; + else + b->x[1] |= Exp_msk1; + + /* Now adjust for scale, provided that b != 0. */ + if (scale && (b->x[0] || b->x[1])) { + *e -= scale; + if (*e < Etiny) { + scale = Etiny - *e; + *e = Etiny; + /* We can't shift more than P-1 bits without shifting out a 1. */ + assert(0 < scale && scale <= P - 1); + if (scale >= 32) { + /* The bits shifted out should all be zero. */ + assert(b->x[0] == 0); + b->x[0] = b->x[1]; + b->x[1] = 0; + scale -= 32; + } + if (scale) { + /* The bits shifted out should all be zero. */ + assert(b->x[0] << (32 - scale) == 0); + b->x[0] = (b->x[0] >> scale) | (b->x[1] << (32 - scale)); + b->x[1] >>= scale; + } + } + } + /* Ensure b is normalized. */ + if (!b->x[1]) + b->wds = 1; + + return b; +} + +/* Convert a double to a Bigint plus an exponent. Return NULL on failure. + + Given a finite nonzero double d, return an odd Bigint b and exponent *e + such that fabs(d) = b * 2**e. On return, *bbits gives the number of + significant bits of b; that is, 2**(*bbits-1) <= b < 2**(*bbits). + + If d is zero, then b == 0, *e == -1010, *bbits = 0. + */ + +static Bigint * +d2b(U *d, int *e, int *bits) +{ + Bigint *b; + int de, k; + ULong *x, y, z; + int i; + + b = Balloc(1); + if (b == NULL) + return NULL; + x = b->x; + + z = word0(d) & Frac_mask; + word0(d) &= 0x7fffffff; /* clear sign bit, which we ignore */ + if ((de = (int)(word0(d) >> Exp_shift))) + z |= Exp_msk1; + if ((y = word1(d))) { + if ((k = lo0bits(&y))) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; + i = + b->wds = (x[1] = z) ? 2 : 1; + } + else { + k = lo0bits(&z); + x[0] = z; + i = + b->wds = 1; + k += 32; + } + if (de) { + *e = de - Bias - (P-1) + k; + *bits = P - k; + } + else { + *e = de - Bias - (P-1) + 1 + k; + *bits = 32*i - hi0bits(x[i-1]); + } + return b; +} + +/* Compute the ratio of two Bigints, as a double. The result may have an + error of up to 2.5 ulps. */ + +static double +ratio(Bigint *a, Bigint *b) +{ + U da, db; + int k, ka, kb; + + dval(&da) = b2d(a, &ka); + dval(&db) = b2d(b, &kb); + k = ka - kb + 32*(a->wds - b->wds); + if (k > 0) + word0(&da) += k*Exp_msk1; + else { + k = -k; + word0(&db) += k*Exp_msk1; + } + return dval(&da) / dval(&db); +} + +static const double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +}; + +static const double +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-256 */ +}; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 + +#define ULbits 32 +#define kshift 5 +#define kmask 31 + + +static int +dshift(Bigint *b, int p2) +{ + int rv = hi0bits(b->x[b->wds-1]) - 4; + if (p2 > 0) + rv -= p2; + return rv & kmask; +} + +/* special case of Bigint division. The quotient is always in the range 0 <= + quotient < 10, and on entry the divisor S is normalized so that its top 4 + bits (28--31) are zero and bit 27 is set. */ + +static int +quorem(Bigint *b, Bigint *S) +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; + ULong si, z, zs; +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong)(y & FFFFFFFF); +#else + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong)(y & FFFFFFFF); +#else + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; +} + +/* sulp(x) is a version of ulp(x) that takes bc.scale into account. + + Assuming that x is finite and nonnegative (positive zero is fine + here) and x / 2^bc.scale is exactly representable as a double, + sulp(x) is equivalent to 2^bc.scale * ulp(x / 2^bc.scale). */ + +static double +sulp(U *x, BCinfo *bc) +{ + U u; + + if (bc->scale && 2*P + 1 > (int)((word0(x) & Exp_mask) >> Exp_shift)) { + /* rv/2^bc->scale is subnormal */ + word0(&u) = (P+2)*Exp_msk1; + word1(&u) = 0; + return u.d; + } + else { + assert(word0(x) || word1(x)); /* x != 0.0 */ + return ulp(x); + } +} + +/* The bigcomp function handles some hard cases for strtod, for inputs + with more than STRTOD_DIGLIM digits. It's called once an initial + estimate for the double corresponding to the input string has + already been obtained by the code in sb_strtod. + + The bigcomp function is only called after sb_strtod has found a + double value rv such that either rv or rv + 1ulp represents the + correctly rounded value corresponding to the original string. It + determines which of these two values is the correct one by + computing the decimal digits of rv + 0.5ulp and comparing them with + the corresponding digits of s0. + + In the following, write dv for the absolute value of the number represented + by the input string. + + Inputs: + + s0 points to the first significant digit of the input string. + + rv is a (possibly scaled) estimate for the closest double value to the + value represented by the original input to sb_strtod. If + bc->scale is nonzero, then rv/2^(bc->scale) is the approximation to + the input value. + + bc is a struct containing information gathered during the parsing and + estimation steps of sb_strtod. Description of fields follows: + + bc->e0 gives the exponent of the input value, such that dv = (integer + given by the bd->nd digits of s0) * 10**e0 + + bc->nd gives the total number of significant digits of s0. It will + be at least 1. + + bc->nd0 gives the number of significant digits of s0 before the + decimal separator. If there's no decimal separator, bc->nd0 == + bc->nd. + + bc->scale is the value used to scale rv to avoid doing arithmetic with + subnormal values. It's either 0 or 2*P (=106). + + Outputs: + + On successful exit, rv/2^(bc->scale) is the closest double to dv. + + Returns 0 on success, -1 on failure (e.g., due to a failed malloc call). */ + +static int +bigcomp(U *rv, const char *s0, BCinfo *bc) +{ + Bigint *b, *d; + int b2, d2, dd, i, nd, nd0, odd, p2, p5; + + nd = bc->nd; + nd0 = bc->nd0; + p5 = nd + bc->e0; + b = sd2b(rv, bc->scale, &p2); + if (b == NULL) + return -1; + + /* record whether the lsb of rv/2^(bc->scale) is odd: in the exact halfway + case, this is used for round to even. */ + odd = b->x[0] & 1; + + /* left shift b by 1 bit and or a 1 into the least significant bit; + this gives us b * 2**p2 = rv/2^(bc->scale) + 0.5 ulp. */ + b = lshift(b, 1); + if (b == NULL) + return -1; + b->x[0] |= 1; + p2--; + + p2 -= p5; + d = i2b(1); + if (d == NULL) { + Bfree(b); + return -1; + } + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + */ + if (p5 > 0) { + d = pow5mult(d, p5); + if (d == NULL) { + Bfree(b); + return -1; + } + } + else if (p5 < 0) { + b = pow5mult(b, -p5); + if (b == NULL) { + Bfree(d); + return -1; + } + } + if (p2 > 0) { + b2 = p2; + d2 = 0; + } + else { + b2 = 0; + d2 = -p2; + } + i = dshift(d, d2); + if ((b2 += i) > 0) { + b = lshift(b, b2); + if (b == NULL) { + Bfree(d); + return -1; + } + } + if ((d2 += i) > 0) { + d = lshift(d, d2); + if (d == NULL) { + Bfree(b); + return -1; + } + } + + /* Compare s0 with b/d: set dd to -1, 0, or 1 according as s0 < b/d, s0 == + * b/d, or s0 > b/d. Here the digits of s0 are thought of as representing + * a number in the range [0.1, 1). */ + if (cmp(b, d) >= 0) + /* b/d >= 1 */ + dd = -1; + else { + i = 0; + for(;;) { + b = multadd(b, 10, 0); + if (b == NULL) { + Bfree(d); + return -1; + } + dd = s0[i < nd0 ? i : i+1] - '0' - quorem(b, d); + i++; + + if (dd) + break; + if (!b->x[0] && b->wds == 1) { + /* b/d == 0 */ + dd = i < nd; + break; + } + if (!(i < nd)) { + /* b/d != 0, but digits of s0 exhausted */ + dd = -1; + break; + } + } + } + Bfree(b); + Bfree(d); + if (dd > 0 || (dd == 0 && odd)) + dval(rv) += sulp(rv, bc); + return 0; +} + +/* Return a 'standard' NaN value. + + There are exactly two quiet NaNs that don't arise by 'quieting' signaling + NaNs (see IEEE 754-2008, section 6.2.1). If sign == 0, return the one whose + sign bit is cleared. Otherwise, return the one whose sign bit is set. +*/ + +double +sb_stdnan(int sign) +{ + U rv; + word0(&rv) = NAN_WORD0; + word1(&rv) = NAN_WORD1; + if (sign) + word0(&rv) |= Sign_bit; + return dval(&rv); +} + +/* Return positive or negative infinity, according to the given sign (0 for + * positive infinity, 1 for negative infinity). */ + +double +sb_infinity(int sign) +{ + U rv; + word0(&rv) = POSINF_WORD0; + word1(&rv) = POSINF_WORD1; + return sign ? -dval(&rv) : dval(&rv); +} + +double +sb_strtod(const char *s00, char **se) +{ + int bb2, bb5, bbe, bd2, bd5, bs2, c, dsign, e, e1, error; + int esign, i, j, k, lz, nd, nd0, odd, sign; + const char *s, *s0, *s1; + double aadj, aadj1; + U aadj2, adj, rv, rv0; + ULong y, z, abs_exp; + Long L; + BCinfo bc; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; + size_t ndigits, fraclen; + + dval(&rv) = 0.; + + /* Start parsing. */ + c = *(s = s00); + + /* Parse optional sign, if present. */ + sign = 0; + switch (c) { + case '-': + sign = 1; + /* no break */ + case '+': + c = *++s; + } + + /* Skip leading zeros: lz is true iff there were leading zeros. */ + s1 = s; + while (c == '0') + c = *++s; + lz = s != s1; + + /* Point s0 at the first nonzero digit (if any). fraclen will be the + number of digits between the decimal point and the end of the + digit string. ndigits will be the total number of digits ignoring + leading zeros. */ + s0 = s1 = s; + while ('0' <= c && c <= '9') + c = *++s; + ndigits = s - s1; + fraclen = 0; + + /* Parse decimal point and following digits. */ + if (c == '.') { + c = *++s; + if (!ndigits) { + s1 = s; + while (c == '0') + c = *++s; + lz = lz || s != s1; + fraclen += (s - s1); + s0 = s; + } + s1 = s; + while ('0' <= c && c <= '9') + c = *++s; + ndigits += s - s1; + fraclen += s - s1; + } + + /* Now lz is true if and only if there were leading zero digits, and + ndigits gives the total number of digits ignoring leading zeros. A + valid input must have at least one digit. */ + if (!ndigits && !lz) { + if (se) + *se = (char *)s00; + goto parse_error; + } + + /* Range check ndigits and fraclen to make sure that they, and values + computed with them, can safely fit in an int. */ + if (ndigits > MAX_DIGITS || fraclen > MAX_DIGITS) { + if (se) + *se = (char *)s00; + goto parse_error; + } + nd = (int)ndigits; + nd0 = (int)ndigits - (int)fraclen; + + /* Parse exponent. */ + e = 0; + if (c == 'e' || c == 'E') { + s00 = s; + c = *++s; + + /* Exponent sign. */ + esign = 0; + switch (c) { + case '-': + esign = 1; + /* no break */ + case '+': + c = *++s; + } + + /* Skip zeros. lz is true iff there are leading zeros. */ + s1 = s; + while (c == '0') + c = *++s; + lz = s != s1; + + /* Get absolute value of the exponent. */ + s1 = s; + abs_exp = 0; + while ('0' <= c && c <= '9') { + abs_exp = 10*abs_exp + (c - '0'); + c = *++s; + } + + /* abs_exp will be correct modulo 2**32. But 10**9 < 2**32, so if + there are at most 9 significant exponent digits then overflow is + impossible. */ + if (s - s1 > 9 || abs_exp > MAX_ABS_EXP) + e = (int)MAX_ABS_EXP; + else + e = (int)abs_exp; + if (esign) + e = -e; + + /* A valid exponent must have at least one digit. */ + if (s == s1 && !lz) + s = s00; + } + + /* Adjust exponent to take into account position of the point. */ + e -= nd - nd0; + if (nd0 <= 0) + nd0 = nd; + + /* Finished parsing. Set se to indicate how far we parsed */ + if (se) + *se = (char *)s; + + /* If all digits were zero, exit with return value +-0.0. Otherwise, + strip trailing zeros: scan back until we hit a nonzero digit. */ + if (!nd) + goto ret; + for (i = nd; i > 0; ) { + --i; + if (s0[i < nd0 ? i : i+1] != '0') { + ++i; + break; + } + } + e += nd - i; + nd = i; + if (nd0 > nd) + nd0 = nd; + + /* Summary of parsing results. After parsing, and dealing with zero + * inputs, we have values s0, nd0, nd, e, sign, where: + * + * - s0 points to the first significant digit of the input string + * + * - nd is the total number of significant digits (here, and + * below, 'significant digits' means the set of digits of the + * significand of the input that remain after ignoring leading + * and trailing zeros). + * + * - nd0 indicates the position of the decimal point, if present; it + * satisfies 1 <= nd0 <= nd. The nd significant digits are in + * s0[0:nd0] and s0[nd0+1:nd+1] using the usual Python half-open slice + * notation. (If nd0 < nd, then s0[nd0] contains a '.' character; if + * nd0 == nd, then s0[nd0] could be any non-digit character.) + * + * - e is the adjusted exponent: the absolute value of the number + * represented by the original input string is n * 10**e, where + * n is the integer represented by the concatenation of + * s0[0:nd0] and s0[nd0+1:nd+1] + * + * - sign gives the sign of the input: 1 for negative, 0 for positive + * + * - the first and last significant digits are nonzero + */ + + /* put first DBL_DIG+1 digits into integer y and z. + * + * - y contains the value represented by the first min(9, nd) + * significant digits + * + * - if nd > 9, z contains the value represented by significant digits + * with indices in [9, min(16, nd)). So y * 10**(min(16, nd) - 9) + z + * gives the value represented by the first min(16, nd) sig. digits. + */ + + bc.e0 = e1 = e; + y = z = 0; + for (i = 0; i < nd; i++) { + if (i < 9) + y = 10*y + s0[i < nd0 ? i : i+1] - '0'; + else if (i < DBL_DIG+1) + z = 10*z + s0[i < nd0 ? i : i+1] - '0'; + else + break; + } + + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(&rv) = y; + if (k > 9) { + dval(&rv) = tens[k - 9] * dval(&rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG + && Flt_Rounds == 1 + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { + dval(&rv) *= tens[e]; + goto ret; + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ + e -= i; + dval(&rv) *= tens[i]; + dval(&rv) *= tens[e]; + goto ret; + } + } + else if (e >= -Ten_pmax) { + dval(&rv) /= tens[-e]; + goto ret; + } + } + e1 += nd - k; + + bc.scale = 0; + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15)) + dval(&rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) + goto ovfl; + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(&rv) -= P*Exp_msk1; + dval(&rv) *= bigtens[j]; + if ((z = word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(&rv) = Big0; + word1(&rv) = Big1; + } + else + word0(&rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + /* The input decimal value lies in [10**e1, 10**(e1+16)). + + If e1 <= -512, underflow immediately. + If e1 <= -256, set bc.scale to 2*P. + + So for input value < 1e-256, bc.scale is always set; + for input value >= 1e-240, bc.scale is never set. + For input values in [1e-256, 1e-240), bc.scale may or may + not be set. */ + + e1 = -e1; + if ((i = e1 & 15)) + dval(&rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; + if (e1 & Scale_Bit) + bc.scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; clear j low bits */ + if (j >= 32) { + word1(&rv) = 0; + if (j >= 53) + word0(&rv) = (P+2)*Exp_msk1; + else + word0(&rv) &= 0xffffffff << (j-32); + } + else + word1(&rv) &= 0xffffffff << j; + } + if (!dval(&rv)) + goto undfl; + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bc.nd = nd; + bc.nd0 = nd0; /* Only needed if nd > STRTOD_DIGLIM, but done here */ + /* to silence an erroneous warning about bc.nd0 */ + /* possibly not being initialized. */ + if (nd > STRTOD_DIGLIM) { + /* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */ + /* minimum number of decimal digits to distinguish double values */ + /* in IEEE arithmetic. */ + + /* Truncate input to 18 significant digits, then discard any trailing + zeros on the result by updating nd, nd0, e and y suitably. (There's + no need to update z; it's not reused beyond this point.) */ + for (i = 18; i > 0; ) { + /* scan back until we hit a nonzero digit. significant digit 'i' + is s0[i] if i < nd0, s0[i+1] if i >= nd0. */ + --i; + if (s0[i < nd0 ? i : i+1] != '0') { + ++i; + break; + } + } + e += nd - i; + nd = i; + if (nd0 > nd) + nd0 = nd; + if (nd < 9) { /* must recompute y */ + y = 0; + for(i = 0; i < nd0; ++i) + y = 10*y + s0[i] - '0'; + for(; i < nd; ++i) + y = 10*y + s0[i+1] - '0'; + } + } + bd0 = s2b(s0, nd0, nd, y); + if (bd0 == NULL) + goto failed_malloc; + + /* Notation for the comments below. Write: + + - dv for the absolute value of the number represented by the original + decimal input string. + + - if we've truncated dv, write tdv for the truncated value. + Otherwise, set tdv == dv. + + - srv for the quantity rv/2^bc.scale; so srv is the current binary + approximation to tdv (and dv). It should be exactly representable + in an IEEE 754 double. + */ + + for(;;) { + + /* This is the main correction loop for sb_strtod. + + We've got a decimal value tdv, and a floating-point approximation + srv=rv/2^bc.scale to tdv. The aim is to determine whether srv is + close enough (i.e., within 0.5 ulps) to tdv, and to compute a new + approximation if not. + + To determine whether srv is close enough to tdv, compute integers + bd, bb and bs proportional to tdv, srv and 0.5 ulp(srv) + respectively, and then use integer arithmetic to determine whether + |tdv - srv| is less than, equal to, or greater than 0.5 ulp(srv). + */ + + bd = Balloc(bd0->k); + if (bd == NULL) { + Bfree(bd0); + goto failed_malloc; + } + Bcopy(bd, bd0); + bb = sd2b(&rv, bc.scale, &bbe); /* srv = bb * 2^bbe */ + if (bb == NULL) { + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + /* Record whether lsb of bb is odd, in case we need this + for the round-to-even step later. */ + odd = bb->x[0] & 1; + + /* tdv = bd * 10**e; srv = bb * 2**bbe */ + bs = i2b(1); + if (bs == NULL) { + Bfree(bb); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; + bb2++; + bd2++; + + /* At this stage bd5 - bb5 == e == bd2 - bb2 + bbe, bb2 - bs2 == 1, + and bs == 1, so: + + tdv == bd * 10**e = bd * 2**(bbe - bb2 + bd2) * 5**(bd5 - bb5) + srv == bb * 2**bbe = bb * 2**(bbe - bb2 + bb2) + 0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2) + + It follows that: + + M * tdv = bd * 2**bd2 * 5**bd5 + M * srv = bb * 2**bb2 * 5**bb5 + M * 0.5 ulp(srv) = bs * 2**bs2 * 5**bb5 + + for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but + this fact is not needed below.) + */ + + /* Remove factor of 2**i, where i = min(bb2, bd2, bs2). */ + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + + /* Scale bb, bd, bs by the appropriate powers of 2 and 5. */ + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + if (bs == NULL) { + Bfree(bb); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + if (bb == NULL) { + Bfree(bs); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + } + if (bb2 > 0) { + bb = lshift(bb, bb2); + if (bb == NULL) { + Bfree(bs); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + } + if (bd5 > 0) { + bd = pow5mult(bd, bd5); + if (bd == NULL) { + Bfree(bb); + Bfree(bs); + Bfree(bd0); + goto failed_malloc; + } + } + if (bd2 > 0) { + bd = lshift(bd, bd2); + if (bd == NULL) { + Bfree(bb); + Bfree(bs); + Bfree(bd0); + goto failed_malloc; + } + } + if (bs2 > 0) { + bs = lshift(bs, bs2); + if (bs == NULL) { + Bfree(bb); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + } + + /* Now bd, bb and bs are scaled versions of tdv, srv and 0.5 ulp(srv), + respectively. Compute the difference |tdv - srv|, and compare + with 0.5 ulp(srv). */ + + delta = diff(bb, bd); + if (delta == NULL) { + Bfree(bb); + Bfree(bs); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); + if (bc.nd > nd && i <= 0) { + if (dsign) + break; /* Must use bigcomp(). */ + + /* Here rv overestimates the truncated decimal value by at most + 0.5 ulp(rv). Hence rv either overestimates the true decimal + value by <= 0.5 ulp(rv), or underestimates it by some small + amount (< 0.1 ulp(rv)); either way, rv is within 0.5 ulps of + the true decimal value, so it's possible to exit. + + Exception: if scaled rv is a normal exact power of 2, but not + DBL_MIN, then rv - 0.5 ulp(rv) takes us all the way down to the + next double, so the correctly rounded result is either rv - 0.5 + ulp(rv) or rv; in this case, use bigcomp to distinguish. */ + + if (!word1(&rv) && !(word0(&rv) & Bndry_mask)) { + /* rv can't be 0, since it's an overestimate for some + nonzero value. So rv is a normal power of 2. */ + j = (int)(word0(&rv) & Exp_mask) >> Exp_shift; + /* rv / 2^bc.scale = 2^(j - 1023 - bc.scale); use bigcomp if + rv / 2^bc.scale >= 2^-1021. */ + if (j - bc.scale >= 2) { + dval(&rv) -= 0.5 * sulp(&rv, &bc); + break; /* Use bigcomp. */ + } + } + + { + bc.nd = nd; + i = -1; /* Discarded digits make delta smaller. */ + } + } + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(&rv) || word0(&rv) & Bndry_mask + || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 + ) { + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ + break; + } + delta = lshift(delta,Log2P); + if (delta == NULL) { + Bfree(bb); + Bfree(bs); + Bfree(bd); + Bfree(bd0); + goto failed_malloc; + } + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 + && word1(&rv) == ( + (bc.scale && + (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) ? + (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(&rv) = (word0(&rv) & Exp_mask) + + Exp_msk1 + ; + word1(&rv) = 0; + /* dsign = 0; */ + break; + } + } + else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { + drop_down: + /* boundary case -- decrement exponent */ + if (bc.scale) { + L = word0(&rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + if (bc.nd > nd) + break; + goto undfl; + } + } + L = (word0(&rv) & Exp_mask) - Exp_msk1; + word0(&rv) = L | Bndry_mask1; + word1(&rv) = 0xffffffff; + break; + } + if (!odd) + break; + if (dsign) + dval(&rv) += sulp(&rv, &bc); + else { + dval(&rv) -= sulp(&rv, &bc); + if (!dval(&rv)) { + if (bc.nd >nd) + break; + goto undfl; + } + } + /* dsign = 1 - dsign; */ + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = aadj1 = 1.; + else if (word1(&rv) || word0(&rv) & Bndry_mask) { + if (word1(&rv) == Tiny1 && !word0(&rv)) { + if (bc.nd >nd) + break; + goto undfl; + } + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = dsign ? aadj : -aadj; + if (Flt_Rounds == 0) + aadj1 += 0.5; + } + y = word0(&rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(&rv0) = dval(&rv); + word0(&rv) -= P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + if ((word0(&rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(&rv0) == Big0 && word1(&rv0) == Big1) { + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + goto ovfl; + } + word0(&rv) = Big0; + word1(&rv) = Big1; + goto cont; + } + else + word0(&rv) += P*Exp_msk1; + } + else { + if (bc.scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = (ULong)aadj) <= 0) + z = 1; + aadj = z; + aadj1 = dsign ? aadj : -aadj; + } + dval(&aadj2) = aadj1; + word0(&aadj2) += (2*P+1)*Exp_msk1 - y; + aadj1 = dval(&aadj2); + } + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + } + z = word0(&rv) & Exp_mask; + if (bc.nd == nd) { + if (!bc.scale) + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + } + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + if (bc.nd > nd) { + error = bigcomp(&rv, s0, &bc); + if (error) + goto failed_malloc; + } + + if (bc.scale) { + word0(&rv0) = Exp_1 - 2*P*Exp_msk1; + word1(&rv0) = 0; + dval(&rv) *= dval(&rv0); + } + + ret: + return sign ? -dval(&rv) : dval(&rv); + + parse_error: + return 0.0; + + failed_malloc: + errno = ENOMEM; + return -1.0; + + undfl: + return sign ? -0.0 : 0.0; + + ovfl: + errno = ERANGE; + /* Can't trust HUGE_VAL */ + word0(&rv) = Exp_mask; + word1(&rv) = 0; + return sign ? -dval(&rv) : dval(&rv); + +} + +static char * +rv_alloc(int i) +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned)i; + j <<= 1) + k++; + r = (int*)Balloc(k); + if (r == NULL) + return NULL; + *r = k; + return (char *)(r+1); +} + +static char * +nrv_alloc(char *s, char **rve, int n) +{ + char *rv, *t; + + rv = rv_alloc(n); + if (rv == NULL) + return NULL; + t = rv; + while((*t = *s++)) t++; + if (rve) + *rve = t; + return rv; +} + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + +void +sb_freedtoa(char *s) +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +} + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + +/* Additional notes (METD): (1) returns NULL on failure. (2) to avoid memory + leakage, a successful call to sb_dtoa should always be matched by a + call to sb_freedtoa. */ + +char * +sb_dtoa(double dd, int mode, int ndigits, + int *decpt, int *sign, char **rve) +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; + int denorm; + ULong x; + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + U d2, eps, u; + double ds; + char *s, *s0; + + /* set pointers to NULL, to silence gcc compiler warnings and make + cleanup easier on error */ + mlo = mhi = S = 0; + s0 = 0; + + u.d = dd; + if (word0(&u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(&u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + + /* quick return for Infinities, NaNs and zeros */ + if ((word0(&u) & Exp_mask) == Exp_mask) + { + /* Infinity or NaN */ + *decpt = 9999; + if (!word1(&u) && !(word0(&u) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); + return nrv_alloc("NaN", rve, 3); + } + if (!dval(&u)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + + /* compute k = floor(log10(d)). The computation may leave k + one too large, but should never leave k too small. */ + b = d2b(&u, &be, &bbits); + if (b == NULL) + goto failed_malloc; + if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { + dval(&d2) = dval(&u); + word0(&d2) &= Frac_mask1; + word0(&d2) |= Exp_11; + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) + : word1(&u) << (32 - i); + dval(&d2) = x; + word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } + ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(&u) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + + try_quick = 1; + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ + /* silence erroneous "gcc -Wall" warning. */ + switch(mode) { + case 0: + case 1: + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s0 = rv_alloc(i); + if (s0 == NULL) + goto failed_malloc; + s = s0; + + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(&d2) = dval(&u); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(&u) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(&u) /= ds; + } + else if ((j1 = -k)) { + dval(&u) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(&u) *= bigtens[i]; + } + } + if (k_check && dval(&u) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(&u) *= 10.; + ieps++; + } + dval(&eps) = ieps*dval(&u) + 7.; + word0(&eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(&u) -= 5.; + if (dval(&u) > dval(&eps)) + goto one_digit; + if (dval(&u) < -dval(&eps)) + goto no_digits; + goto fast_failed; + } + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); + for(i = 0;;) { + L = (Long)dval(&u); + dval(&u) -= L; + *s++ = '0' + (int)L; + if (dval(&u) < dval(&eps)) + goto ret1; + if (1. - dval(&u) < dval(&eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(&eps) *= 10.; + dval(&u) *= 10.; + } + } + else { + /* Generate ilim digits, then fix them up. */ + dval(&eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u)); + if (!(dval(&u) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(&u) > 0.5 + dval(&eps)) + goto bump_up; + else if (dval(&u) < 0.5 - dval(&eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } + } + fast_failed: + s = s0; + dval(&u) = dval(&d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(&u) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u) / ds); + dval(&u) -= L*ds; + *s++ = '0' + (int)L; + if (!dval(&u)) { + break; + } + if (i == ilim) { + dval(&u) += dval(&u); + if (dval(&u) > ds || (dval(&u) == ds && L & 1)) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + if (leftright) { + i = + denorm ? be + (Bias + (P-1) - 1 + 1) : + 1 + P - bbits; + b2 += i; + s2 += i; + mhi = i2b(1); + if (mhi == NULL) + goto failed_malloc; + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + if (mhi == NULL) + goto failed_malloc; + b1 = mult(mhi, b); + Bfree(b); + b = b1; + if (b == NULL) + goto failed_malloc; + } + if ((j = b5 - m5)) { + b = pow5mult(b, j); + if (b == NULL) + goto failed_malloc; + } + } + else { + b = pow5mult(b, b5); + if (b == NULL) + goto failed_malloc; + } + } + S = i2b(1); + if (S == NULL) + goto failed_malloc; + if (s5 > 0) { + S = pow5mult(S, s5); + if (S == NULL) + goto failed_malloc; + } + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) + ) { + if (!word1(&u) && !(word0(&u) & Bndry_mask) + && word0(&u) & (Exp_mask & ~Exp_msk1) + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#define iInc 28 + i = dshift(S, s2); + b2 += i; + m2 += i; + s2 += i; + if (b2 > 0) { + b = lshift(b, b2); + if (b == NULL) + goto failed_malloc; + } + if (s2 > 0) { + S = lshift(S, s2); + if (S == NULL) + goto failed_malloc; + } + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (b == NULL) + goto failed_malloc; + if (leftright) { + mhi = multadd(mhi, 10, 0); + if (mhi == NULL) + goto failed_malloc; + } + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + else { + S = multadd(S, 5, 0); + if (S == NULL) + goto failed_malloc; + if (cmp(b, S) <= 0) + goto no_digits; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) { + mhi = lshift(mhi, m2); + if (mhi == NULL) + goto failed_malloc; + } + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + if (mhi == NULL) + goto failed_malloc; + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + if (mhi == NULL) + goto failed_malloc; + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + if (delta == NULL) + goto failed_malloc; + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); + if (j1 == 0 && mode != 1 && !(word1(&u) & 1) + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; + *s++ = dig; + goto ret; + } + if (j < 0 || (j == 0 && mode != 1 + && !(word1(&u) & 1) + )) { + if (!b->x[0] && b->wds <= 1) { + goto accept_dig; + } + if (j1 > 0) { + b = lshift(b, 1); + if (b == NULL) + goto failed_malloc; + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && dig & 1)) + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (b == NULL) + goto failed_malloc; + if (mlo == mhi) { + mlo = mhi = multadd(mhi, 10, 0); + if (mlo == NULL) + goto failed_malloc; + } + else { + mlo = multadd(mlo, 10, 0); + if (mlo == NULL) + goto failed_malloc; + mhi = multadd(mhi, 10, 0); + if (mhi == NULL) + goto failed_malloc; + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + if (b == NULL) + goto failed_malloc; + } + + /* Round off last digit */ + + b = lshift(b, 1); + if (b == NULL) + goto failed_malloc; + j = cmp(b, S); + if (j > 0 || (j == 0 && dig & 1)) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + failed_malloc: + if (S) + Bfree(S); + if (mlo && mlo != mhi) + Bfree(mlo); + if (mhi) + Bfree(mhi); + if (b) + Bfree(b); + if (s0) + sb_freedtoa(s0); + return NULL; +} +#ifdef __cplusplus +} +#endif diff --git a/media/sphinxbase/src/libsphinxbase/util/err.c b/media/sphinxbase/src/libsphinxbase/util/err.c new file mode 100644 index 000000000..1a498b639 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/err.c @@ -0,0 +1,297 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/** + * @file err.c + * @brief Somewhat antiquated logging and error interface. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> + +#include "sphinxbase/err.h" +#include "sphinxbase/prim_type.h" +#include "sphinxbase/filename.h" +#include "sphinxbase/ckd_alloc.h" + +static FILE* logfp = NULL; +static int logfp_disabled = FALSE; + +static int sphinx_debug_level; + +#if defined(__ANDROID__) +#include <android/log.h> +static void +err_logcat_cb(void* user_data, err_lvl_t level, const char *fmt, ...); +#elif defined(_WIN32_WCE) +#include <windows.h> +#define vsnprintf _vsnprintf +static void +err_wince_cb(void* user_data, err_lvl_t level, const char *fmt, ...); +#endif + +#if defined(__ANDROID__) +static err_cb_f err_cb = err_logcat_cb; +#elif defined(_WIN32_WCE) +static err_cb_f err_cb = err_wince_cb; +#else +static err_cb_f err_cb = err_logfp_cb; +#endif +static void* err_user_data; + +void +err_msg(err_lvl_t lvl, const char *path, long ln, const char *fmt, ...) +{ + static const char *err_prefix[ERR_MAX] = { + "DEBUG", "INFO", "INFOCONT", "WARN", "ERROR", "FATAL" + }; + + char msg[1024]; + va_list ap; + + if (!err_cb) + return; + + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + if (path) { + const char *fname = path2basename(path); + if (lvl == ERR_INFOCONT) + err_cb(err_user_data, lvl, "%s(%ld): %s", fname, ln, msg); + else if (lvl == ERR_INFO) + err_cb(err_user_data, lvl, "%s: %s(%ld): %s", err_prefix[lvl], fname, ln, msg); + else + err_cb(err_user_data, lvl, "%s: \"%s\", line %ld: %s", err_prefix[lvl], fname, ln, msg); + } else { + err_cb(err_user_data, lvl, "%s", msg); + } +} + +#ifdef _WIN32_WCE /* No strerror for WinCE, so a separate implementation */ +void +err_msg_system(err_lvl_t lvl, const char *path, long ln, const char *fmt, ...) +{ + static const char *err_prefix[ERR_MAX] = { + "DEBUG", "INFO", "INFOCONT", "WARN", "ERROR", "FATAL" + }; + + va_list ap; + LPVOID error_wstring; + DWORD error; + char msg[1024]; + char error_string[1024]; + + if (!err_cb) + return; + + error = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + 0, // Default language + (LPTSTR) &error_wstring, + 0, + NULL); + wcstombs(error_string, error_wstring, 1023); + LocalFree(error_wstring); + + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + if (path) { + const char *fname = path2basename(path); + if (lvl == ERR_INFOCONT) + err_cb(err_user_data, lvl, "%s(%ld): %s: %s\n", fname, ln, msg, error_string); + else if (lvl == ERR_INFO) + err_cb(err_user_data, lvl, "%s: %s(%ld): %s: %s\n", err_prefix[lvl], fname, ln, msg, error_string); + else + err_cb(err_user_data, lvl, "%s: \"%s\", line %ld: %s: %s\n", err_prefix[lvl], fname, ln, msg, error_string); + } else { + err_cb(err_user_data, lvl, "%s: %s\n", msg, error_string); + } +} +#else +void +err_msg_system(err_lvl_t lvl, const char *path, long ln, const char *fmt, ...) +{ + int local_errno = errno; + + static const char *err_prefix[ERR_MAX] = { + "DEBUG", "INFO", "INFOCONT", "WARN", "ERROR", "FATAL" + }; + + char msg[1024]; + va_list ap; + + if (!err_cb) + return; + + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + if (path) { + const char *fname = path2basename(path); + if (lvl == ERR_INFOCONT) + err_cb(err_user_data, lvl, "%s(%ld): %s: %s\n", fname, ln, msg, strerror(local_errno)); + else if (lvl == ERR_INFO) + err_cb(err_user_data, lvl, "%s: %s(%ld): %s: %s\n", err_prefix[lvl], fname, ln, msg, strerror(local_errno)); + else + err_cb(err_user_data, lvl, "%s: \"%s\", line %ld: %s: %s\n", err_prefix[lvl], fname, ln, msg, strerror(local_errno)); + } else { + err_cb(err_user_data, lvl, "%s: %s\n", msg, strerror(local_errno)); + } +} +#endif + +#if defined(__ANDROID__) +static void +err_logcat_cb(void *user_data, err_lvl_t lvl, const char *fmt, ...) +{ + static const int android_level[ERR_MAX] = {ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, + ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_ERROR}; + + va_list ap; + va_start(ap, fmt); + __android_log_vprint(android_level[lvl], "cmusphinx", fmt, ap); + va_end(ap); +} +#elif defined(_WIN32_WCE) +static void +err_wince_cb(void *user_data, err_lvl_t lvl, const char *fmt, ...) +{ + char msg[1024]; + WCHAR *wmsg; + size_t size; + va_list ap; + + va_start(ap, fmt); + _vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + size = mbstowcs(NULL, msg, 0) + 1; + wmsg = ckd_calloc(size, sizeof(*wmsg)); + mbstowcs(wmsg, msg, size); + + OutputDebugStringW(wmsg); + ckd_free(wmsg); +} +#else +void +err_logfp_cb(void *user_data, err_lvl_t lvl, const char *fmt, ...) +{ + va_list ap; + FILE *fp = err_get_logfp(); + + if (!fp) + return; + + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); +} +#endif + +int +err_set_logfile(const char *path) +{ + FILE *newfp, *oldfp; + + if ((newfp = fopen(path, "a")) == NULL) + return -1; + oldfp = err_get_logfp(); + err_set_logfp(newfp); + if (oldfp != NULL && oldfp != stdout && oldfp != stderr) + fclose(oldfp); + return 0; +} + +void +err_set_logfp(FILE *stream) +{ + if (stream == NULL) { + logfp_disabled = TRUE; + logfp = NULL; + return; + } + logfp_disabled = FALSE; + logfp = stream; + return; +} + +FILE * +err_get_logfp(void) +{ + if (logfp_disabled) + return NULL; + if (logfp == NULL) + return stderr; + + return logfp; +} + +int +err_set_debug_level(int level) +{ + int prev = sphinx_debug_level; + sphinx_debug_level = level; + return prev; +} + +int +err_get_debug_level(void) +{ + return sphinx_debug_level; +} + +void +err_set_callback(err_cb_f cb, void* user_data) +{ + err_cb = cb; + err_user_data= user_data; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/errno.c b/media/sphinxbase/src/libsphinxbase/util/errno.c new file mode 100644 index 000000000..844b6f538 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/errno.c @@ -0,0 +1,51 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 2007 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + */ +/********************************************************************* + * + * File: errno.c + * + * Description: functions and variables missing from Windows CE standard + * library + * + * Author: Silvio Moioli <silvio@moioli.net> + * + *********************************************************************/ + +#include <errno.h> + +#if defined(_WIN32_WCE) +int errno; +#endif diff --git a/media/sphinxbase/src/libsphinxbase/util/f2c_lite.c b/media/sphinxbase/src/libsphinxbase/util/f2c_lite.c new file mode 100644 index 000000000..58fbc4ee6 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/f2c_lite.c @@ -0,0 +1,551 @@ +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "sphinxbase/f2c.h" + +#ifdef _MSC_VER +#pragma warning (disable: 4244) +#endif + + +extern void +s_wsfe(cilist * f) +{; +} +extern void +e_wsfe(void) +{; +} +extern void +do_fio(integer * c, char *s, ftnlen l) +{; +} + +/* You'll want this if you redo the *_lite.c files with the -C option + * to f2c for checking array subscripts. (It's not suggested you do that + * for production use, of course.) */ +extern int +s_rnge(char *var, int index, char *routine, int lineno) +{ + fprintf(stderr, + "array index out-of-bounds for %s[%d] in routine %s:%d\n", var, + index, routine, lineno); + fflush(stderr); + assert(2+2 == 5); + return 0; +} + + +#ifdef KR_headers +extern double sqrt(); +float +f__cabs(real, imag) +float real, imag; +#else +#undef abs + +float +f__cabs(float real, float imag) +#endif +{ + float temp; + + if (real < 0) + real = -real; + if (imag < 0) + imag = -imag; + if (imag > real) { + temp = real; + real = imag; + imag = temp; + } + if ((imag + real) == real) + return ((float) real); + + temp = imag / real; + temp = real * sqrt(1.0 + temp * temp); /*overflow!! */ + return (temp); +} + + +VOID +#ifdef KR_headers +s_cnjg(r, z) +complex *r, *z; +#else +s_cnjg(complex * r, complex * z) +#endif +{ + r->r = z->r; + r->i = -z->i; +} + + +#ifdef KR_headers +float +r_imag(z) +complex *z; +#else +float +r_imag(complex * z) +#endif +{ + return (z->i); +} + + +#define log10e 0.43429448190325182765 + +#ifdef KR_headers +double log(); +float +r_lg10(x) +real *x; +#else +#undef abs + +float +r_lg10(real * x) +#endif +{ + return (log10e * log(*x)); +} + + +#ifdef KR_headers +float +r_sign(a, b) +real *a, *b; +#else +float +r_sign(real * a, real * b) +#endif +{ + float x; + x = (*a >= 0 ? *a : -*a); + return (*b >= 0 ? x : -x); +} + + +#ifdef KR_headers +double floor(); +integer +i_dnnt(x) +real *x; +#else +#undef abs + +integer +i_dnnt(real * x) +#endif +{ + return ((*x) >= 0 ? floor(*x + .5) : -floor(.5 - *x)); +} + + +#ifdef KR_headers +double pow(); +double +pow_dd(ap, bp) +doublereal *ap, *bp; +#else +#undef abs + +double +pow_dd(doublereal * ap, doublereal * bp) +#endif +{ + return (pow(*ap, *bp)); +} + + +#ifdef KR_headers +float +pow_ri(ap, bp) +real *ap; +integer *bp; +#else +float +pow_ri(real * ap, integer * bp) +#endif +{ + float pow, x; + integer n; + unsigned long u; + + pow = 1; + x = *ap; + n = *bp; + + if (n != 0) { + if (n < 0) { + n = -n; + x = 1 / x; + } + for (u = n;;) { + if (u & 01) + pow *= x; + if (u >>= 1) + x *= x; + else + break; + } + } + return (pow); +} + +/* Unless compiled with -DNO_OVERWRITE, this variant of s_cat allows the + * target of a concatenation to appear on its right-hand side (contrary + * to the Fortran 77 Standard, but in accordance with Fortran 90). + */ +#define NO_OVERWRITE + + +#ifndef NO_OVERWRITE + +#undef abs +#ifdef KR_headers +extern char *F77_aloc(); +extern void free(); +extern void exit_(); +#else + +extern char *F77_aloc(ftnlen, char *); +#endif + +#endif /* NO_OVERWRITE */ + +VOID +#ifdef KR_headers +s_cat(lp, rpp, rnp, np, ll) +char *lp, *rpp[]; +ftnlen rnp[], *np, ll; +#else +s_cat(char *lp, char *rpp[], ftnlen rnp[], ftnlen * np, ftnlen ll) +#endif +{ + ftnlen i, nc; + char *rp; + ftnlen n = *np; +#ifndef NO_OVERWRITE + ftnlen L, m; + char *lp0, *lp1; + + lp0 = 0; + lp1 = lp; + L = ll; + i = 0; + while (i < n) { + rp = rpp[i]; + m = rnp[i++]; + if (rp >= lp1 || rp + m <= lp) { + if ((L -= m) <= 0) { + n = i; + break; + } + lp1 += m; + continue; + } + lp0 = lp; + lp = lp1 = F77_aloc(L = ll, "s_cat"); + break; + } + lp1 = lp; +#endif /* NO_OVERWRITE */ + for (i = 0; i < n; ++i) { + nc = ll; + if (rnp[i] < nc) + nc = rnp[i]; + ll -= nc; + rp = rpp[i]; + while (--nc >= 0) + *lp++ = *rp++; + } + while (--ll >= 0) + *lp++ = ' '; +#ifndef NO_OVERWRITE + if (lp0) { + memmove(lp0, lp1, L); + free(lp1); + } +#endif +} + + +/* compare two strings */ + +#ifdef KR_headers +integer +s_cmp(a0, b0, la, lb) +char *a0, *b0; +ftnlen la, lb; +#else +integer +s_cmp(char *a0, char *b0, ftnlen la, ftnlen lb) +#endif +{ + register unsigned char *a, *aend, *b, *bend; + a = (unsigned char *) a0; + b = (unsigned char *) b0; + aend = a + la; + bend = b + lb; + + if (la <= lb) { + while (a < aend) + if (*a != *b) + return (*a - *b); + else { + ++a; + ++b; + } + + while (b < bend) + if (*b != ' ') + return (' ' - *b); + else + ++b; + } + + else { + while (b < bend) + if (*a == *b) { + ++a; + ++b; + } + else + return (*a - *b); + while (a < aend) + if (*a != ' ') + return (*a - ' '); + else + ++a; + } + return (0); +} + +/* Unless compiled with -DNO_OVERWRITE, this variant of s_copy allows the + * target of an assignment to appear on its right-hand side (contrary + * to the Fortran 77 Standard, but in accordance with Fortran 90), + * as in a(2:5) = a(4:7) . + */ + + + +/* assign strings: a = b */ + +#ifdef KR_headers +VOID +s_copy(a, b, la, lb) +register char *a, *b; +ftnlen la, lb; +#else +void +s_copy(register char *a, register char *b, ftnlen la, ftnlen lb) +#endif +{ + register char *aend, *bend; + + aend = a + la; + + if (la <= lb) +#ifndef NO_OVERWRITE + if (a <= b || a >= b + la) +#endif + while (a < aend) + *a++ = *b++; +#ifndef NO_OVERWRITE + else + for (b += la; a < aend;) + *--aend = *--b; +#endif + + else { + bend = b + lb; +#ifndef NO_OVERWRITE + if (a <= b || a >= bend) +#endif + while (b < bend) + *a++ = *b++; +#ifndef NO_OVERWRITE + else { + a += lb; + while (b < bend) + *--a = *--bend; + a += lb; + } +#endif + while (a < aend) + *a++ = ' '; + } +} + + +#ifdef KR_headers +float f__cabs(); +float +z_abs(z) +complex *z; +#else +float f__cabs(float, float); +float +z_abs(complex * z) +#endif +{ + return (f__cabs(z->r, z->i)); +} + + +#ifdef KR_headers +extern void sig_die(); +VOID +z_div(c, a, b) +complex *a, *b, *c; +#else +extern void sig_die(char *, int); +void +z_div(complex * c, complex * a, complex * b) +#endif +{ + float ratio, den; + float abr, abi; + + if ((abr = b->r) < 0.) + abr = -abr; + if ((abi = b->i) < 0.) + abi = -abi; + if (abr <= abi) { + /*Let IEEE Infinties handle this ;( */ + /*if(abi == 0) + sig_die("complex division by zero", 1); */ + ratio = b->r / b->i; + den = b->i * (1 + ratio * ratio); + c->r = (a->r * ratio + a->i) / den; + c->i = (a->i * ratio - a->r) / den; + } + + else { + ratio = b->i / b->r; + den = b->r * (1 + ratio * ratio); + c->r = (a->r + a->i * ratio) / den; + c->i = (a->i - a->r * ratio) / den; + } + +} + + +#ifdef KR_headers +double sqrt(); +double f__cabs(); +VOID +z_sqrt(r, z) +complex *r, *z; +#else +#undef abs + +extern float f__cabs(float, float); +void +z_sqrt(complex * r, complex * z) +#endif +{ + float mag; + + if ((mag = f__cabs(z->r, z->i)) == 0.) + r->r = r->i = 0.; + else if (z->r > 0) { + r->r = sqrt(0.5 * (mag + z->r)); + r->i = z->i / r->r / 2; + } + else { + r->i = sqrt(0.5 * (mag - z->r)); + if (z->i < 0) + r->i = -r->i; + r->r = z->i / r->i / 2; + } +} + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef KR_headers + integer pow_ii(ap, bp) integer *ap, *bp; +#else + integer pow_ii(integer * ap, integer * bp) +#endif + { + integer pow, x, n; + unsigned long u; + + x = *ap; + n = *bp; + + if (n <= 0) { + if (n == 0 || x == 1) + return 1; + if (x != -1) + return x != 0 ? 1 / x : 0; + n = -n; + } u = n; + for (pow = 1;;) { + if (u & 01) + pow *= x; + if (u >>= 1) + x *= x; + else + break; + } + return (pow); + } +#ifdef __cplusplus +} +#endif + +#ifdef KR_headers +extern void f_exit(); +VOID +s_stop(s, n) +char *s; +ftnlen n; +#else +#undef abs +#undef min +#undef max +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus + extern "C" { +#endif + void f_exit(void); + + int s_stop(char *s, ftnlen n) +#endif + { + int i; + + if (n > 0) { + fprintf(stderr, "STOP "); + for (i = 0; i < n; ++i) + putc(*s++, stderr); + fprintf(stderr, " statement executed\n"); + } +#ifdef NO_ONEXIT + f_exit(); +#endif + exit(0); + +/* We cannot avoid (useless) compiler diagnostics here: */ +/* some compilers complain if there is no return statement, */ +/* and others complain that this one cannot be reached. */ + + return 0; /* NOT REACHED */ + } +#ifdef __cplusplus + } +#endif +#ifdef __cplusplus +} +#endif diff --git a/media/sphinxbase/src/libsphinxbase/util/filename.c b/media/sphinxbase/src/libsphinxbase/util/filename.c new file mode 100644 index 000000000..3f4ae4750 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/filename.c @@ -0,0 +1,120 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * filename.c -- File and path name operations. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "sphinxbase/filename.h" + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +const char * +path2basename(const char *path) +{ + const char *result; + +#if defined(_WIN32) || defined(__CYGWIN__) + result = strrchr(path, '\\'); +#else + result = strrchr(path, '/'); +#endif + + return (result == NULL ? path : result + 1); +} + +/* Return all leading pathname components */ +void +path2dirname(const char *path, char *dir) +{ + size_t i, l; + + l = strlen(path); +#if defined(_WIN32) || defined(__CYGWIN__) + for (i = l - 1; (i > 0) && !(path[i] == '/' || path[i] == '\\'); --i); +#else + for (i = l - 1; (i > 0) && !(path[i] == '/'); --i); +#endif + if (i == 0) { + dir[0] = '.'; + dir[1] = '\0'; + } else { + memcpy(dir, path, i); + dir[i] = '\0'; + } +} + + +/* Strip off the shortest trailing .xyz suffix */ +void +strip_fileext(const char *path, char *root) +{ + size_t i, l; + + l = strlen(path); + for (i = l - 1; (i > 0) && (path[i] != '.'); --i); + if (i == 0) { + strcpy(root, path); /* Didn't find a . */ + } else { + strncpy(root, path, i); + } +} + +/* Test if this path is absolute. */ +int +path_is_absolute(const char *path) +{ +#if defined(_WIN32) && !defined(_WIN32_WCE) /* FIXME: Also SymbianOS */ + return /* Starts with drive letter : \ or / */ + (strlen(path) >= 3 + && + ((path[0] >= 'A' && path[0] <= 'Z') + || (path[0] >= 'a' && path[0] <= 'z')) + && path[1] == ':' + && (path[2] == '/' || path[2] == '\\')); +#elif defined(_WIN32_WCE) + return path[0] == '\\' || path[0] == '/'; +#else /* Assume Unix */ + return path[0] == '/'; +#endif +} diff --git a/media/sphinxbase/src/libsphinxbase/util/genrand.c b/media/sphinxbase/src/libsphinxbase/util/genrand.c new file mode 100644 index 000000000..a6c69cb4d --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/genrand.c @@ -0,0 +1,234 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + 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. + + 3. The names of its contributors may not 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. + + + Any feedback is very welcome. + http://www.math.keio.ac.jp/matumoto/emt.html + email: matumoto@math.keio.ac.jp +*/ + + +/* + * randgen.c : a portable random generator + * + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: genrand.c,v $ + * Revision 1.2 2005/06/22 03:01:50 arthchan2003 + * Added keyword + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 18-Nov-04 ARCHAN (archan@cs.cmu.edu) at Carnegie Mellon University + * First incorporated from the Mersenne Twister Random + * Number Generator package. It was chosen because it is + * in BSD-license and its performance is quite + * reasonable. Of course if you look at the inventors's + * page. This random generator can actually gives + * 19937-bits period. This is already far from we need. + * This will possibly good enough for the next 10 years. + * + * I also downgrade the code a little bit to avoid Sphinx's + * developers misused it. + */ + + + +#include <stdio.h> + +#include "sphinxbase/genrand.h" + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +void init_genrand(unsigned long s); + +void +genrand_seed(unsigned long s) +{ + init_genrand(s); +} + + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializes mt[N] with a seed */ +void +init_genrand(unsigned long s) +{ + mt[0] = s & 0xffffffffUL; + for (mti = 1; mti < N; mti++) { + mt[mti] = + (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } +} + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long +genrand_int32(void) +{ + unsigned long y; + static unsigned long mag01[2] = { 0x0UL, MATRIX_A }; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N + 1) /* if init_genrand() has not been called, */ + init_genrand(5489UL); /* a default initial seed is used */ + + for (kk = 0; kk < N - M; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); + mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (; kk < N - 1; kk++) { + y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); + mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +/* generates a random number on [0,0x7fffffff]-interval */ +long +genrand_int31(void) +{ + return (long) (genrand_int32() >> 1); +} + +/* generates a random number on [0,1]-real-interval */ +double +genrand_real1(void) +{ + return genrand_int32() * (1.0 / 4294967295.0); + /* divided by 2^32-1 */ +} + +/* generates a random number on [0,1)-real-interval */ +double +genrand_real2(void) +{ + return genrand_int32() * (1.0 / 4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on (0,1)-real-interval */ +double +genrand_real3(void) +{ + return (((double) genrand_int32()) + 0.5) * (1.0 / 4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on [0,1) with 53-bit resolution*/ +double +genrand_res53(void) +{ + unsigned long a = genrand_int32() >> 5, b = genrand_int32() >> 6; + return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); +} + +/* These real versions are due to Isaku Wada, 2002/01/09 added */ diff --git a/media/sphinxbase/src/libsphinxbase/util/glist.c b/media/sphinxbase/src/libsphinxbase/util/glist.c new file mode 100644 index 000000000..a97e71978 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/glist.c @@ -0,0 +1,271 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * glist.h -- Module for maintaining a generic, linear linked-list structure. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: glist.c,v $ + * Revision 1.8 2005/06/22 03:02:51 arthchan2003 + * 1, Fixed doxygen documentation, 2, add keyword. + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 09-Mar-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Added glist_chkdup_*(). + * + * 13-Feb-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Created from earlier version. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "sphinxbase/glist.h" +#include "sphinxbase/ckd_alloc.h" + + +glist_t +glist_add_ptr(glist_t g, void *ptr) +{ + gnode_t *gn; + + gn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + gn->data.ptr = ptr; + gn->next = g; + return ((glist_t) gn); /* Return the new head of the list */ +} + + +glist_t +glist_add_int32(glist_t g, int32 val) +{ + gnode_t *gn; + + gn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + gn->data.i = (long)val; + gn->next = g; + return ((glist_t) gn); /* Return the new head of the list */ +} + + +glist_t +glist_add_uint32(glist_t g, uint32 val) +{ + gnode_t *gn; + + gn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + gn->data.ui = (unsigned long)val; + gn->next = g; + return ((glist_t) gn); /* Return the new head of the list */ +} + + +glist_t +glist_add_float32(glist_t g, float32 val) +{ + gnode_t *gn; + + gn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + gn->data.fl = (double)val; + gn->next = g; + return ((glist_t) gn); /* Return the new head of the list */ +} + + +glist_t +glist_add_float64(glist_t g, float64 val) +{ + gnode_t *gn; + + gn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + gn->data.fl = (double)val; + gn->next = g; + return ((glist_t) gn); /* Return the new head of the list */ +} + +void +glist_free(glist_t g) +{ + gnode_t *gn; + + while (g) { + gn = g; + g = gn->next; + ckd_free((void *) gn); + } +} + +int32 +glist_count(glist_t g) +{ + gnode_t *gn; + int32 n; + + for (gn = g, n = 0; gn; gn = gn->next, n++); + return n; +} + + +gnode_t * +glist_tail(glist_t g) +{ + gnode_t *gn; + + if (!g) + return NULL; + + for (gn = g; gn->next; gn = gn->next); + return gn; +} + + +glist_t +glist_reverse(glist_t g) +{ + gnode_t *gn, *nextgn; + gnode_t *rev; + + rev = NULL; + for (gn = g; gn; gn = nextgn) { + nextgn = gn->next; + + gn->next = rev; + rev = gn; + } + + return rev; +} + + +gnode_t * +glist_insert_ptr(gnode_t * gn, void *ptr) +{ + gnode_t *newgn; + + newgn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + newgn->data.ptr = ptr; + newgn->next = gn->next; + gn->next = newgn; + + return newgn; +} + + +gnode_t * +glist_insert_int32(gnode_t * gn, int32 val) +{ + gnode_t *newgn; + + newgn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + newgn->data.i = val; + newgn->next = gn->next; + gn->next = newgn; + + return newgn; +} + + +gnode_t * +glist_insert_uint32(gnode_t * gn, uint32 val) +{ + gnode_t *newgn; + + newgn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + newgn->data.ui = val; + newgn->next = gn->next; + + gn->next = newgn; + + return newgn; +} + + +gnode_t * +glist_insert_float32(gnode_t * gn, float32 val) +{ + gnode_t *newgn; + + newgn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + newgn->data.fl = (double)val; + newgn->next = gn->next; + gn->next = newgn; + + return newgn; +} + + +gnode_t * +glist_insert_float64(gnode_t * gn, float64 val) +{ + gnode_t *newgn; + + newgn = (gnode_t *) ckd_calloc(1, sizeof(gnode_t)); + newgn->data.fl = (double)val; + newgn->next = gn->next; + gn->next = newgn; + + return newgn; +} + +gnode_t * +gnode_free(gnode_t * gn, gnode_t * pred) +{ + gnode_t *next; + + next = gn->next; + if (pred) { + assert(pred->next == gn); + + pred->next = next; + } + + ckd_free((char *) gn); + + return next; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/hash_table.c b/media/sphinxbase/src/libsphinxbase/util/hash_table.c new file mode 100644 index 000000000..eaadc7884 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/hash_table.c @@ -0,0 +1,713 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * hash.c -- Hash table module. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: hash.c,v $ + * Revision 1.5 2005/06/22 03:04:01 arthchan2003 + * 1, Implemented hash_delete and hash_display, 2, Fixed doxygen documentation, 3, Added keyword. + * + * Revision 1.9 2005/05/25 06:17:53 archan + * Delete the test code in cmd_ln.c and fixed platform specific code of hash.c + * + * Revision 1.8 2005/05/24 01:10:54 archan + * Fix a bug when the value only appear in the hash but there is no chain. Also make sure that prev was initialized to NULL. All success cases were tested, but not tested with the deletion is tested. + * + * Revision 1.6 2005/05/24 00:00:45 archan + * Added basic functionalities to hash_t: 1, display and 2, delete a key from a hash. \n + * + * Revision 1.5 2005/05/11 07:01:38 archan + * Added comments on the usage of the current implementation of hash tables. + * + * Revision 1.4 2005/05/03 04:09:11 archan + * Implemented the heart of word copy search. For every ci-phone, every word end, a tree will be allocated to preserve its pathscore. This is different from 3.5 or below, only the best score for a particular ci-phone, regardless of the word-ends will be preserved at every frame. The graph propagation will not collect unused word tree at this point. srch_WST_propagate_wd_lv2 is also as the most stupid in the century. But well, after all, everything needs a start. I will then really get the results from the search and see how it looks. + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 05-May-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Removed hash_key2hash(). Added hash_enter_bkey() and hash_lookup_bkey(), + * and len attribute to hash_entry_t. + * + * 30-Apr-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Added hash_key2hash(). + * + * 18-Jun-97 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Included case sensitive/insensitive option. Removed local, static + * maintenance of all hash tables. + * + * 31-Jul-95 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon + * Created. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#ifdef _MSC_VER +#pragma warning (disable: 4018) +#endif + +#include "sphinxbase/hash_table.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/case.h" + + +#if 0 +static void +prime_sieve(int32 max) +{ + char *notprime; + int32 p, pp; + + notprime = (char *) ckd_calloc(max + 1, 1); + p = 2; + for (;;) { + printf("%d\n", p); + for (pp = p + p; pp <= max; pp += p) + notprime[pp] = 1; + for (++p; (p <= max) && notprime[p]; p++); + if (p > max) + break; + } +} +#endif + + +/* + * HACK!! Initial hash table size is restricted by this set of primes. (Of course, + * collision resolution by chaining will accommodate more entries indefinitely, but + * efficiency will drop.) + */ +const int32 prime[] = { + 101, 211, 307, 401, 503, 601, 701, 809, 907, + 1009, 1201, 1601, 2003, 2411, 3001, 4001, 5003, 6007, 7001, 8009, + 9001, + 10007, 12007, 16001, 20011, 24001, 30011, 40009, 50021, 60013, + 70001, 80021, 90001, + 100003, 120011, 160001, 200003, 240007, 300007, 400009, 500009, + 600011, 700001, 800011, 900001, + -1 +}; + + +/** + * This function returns a very large prime. + */ +static int32 +prime_size(int32 size) +{ + int32 i; + + for (i = 0; (prime[i] > 0) && (prime[i] < size); i++); + if (prime[i] <= 0) { + E_WARN("Very large hash table requested (%d entries)\n", size); + --i; + } + return (prime[i]); +} + + +hash_table_t * +hash_table_new(int32 size, int32 casearg) +{ + hash_table_t *h; + + h = (hash_table_t *) ckd_calloc(1, sizeof(hash_table_t)); + h->size = prime_size(size + (size >> 1)); + h->nocase = (casearg == HASH_CASE_NO); + h->table = (hash_entry_t *) ckd_calloc(h->size, sizeof(hash_entry_t)); + /* The above calloc clears h->table[*].key and .next to NULL, i.e. an empty table */ + + return h; +} + + +/* + * Compute hash value for given key string. + * Somewhat tuned for English text word strings. + */ +static uint32 +key2hash(hash_table_t * h, const char *key) +{ + + register const char *cp; + + /** ARCHAN 20050712: + [1236322] libutil\str2words special character bgu + HACK Apply suggested hack of fixing the hash table such that + it can work with extended ascii code . This is a hack because + the best way to solve it is to make sure all character + representation is unsigned character in the first place. (or + better unicode.) + **/ + + /*register char c; */ + register unsigned char c; + register int32 s; + register uint32 hash; + + hash = 0; + s = 0; + + if (h->nocase) { + for (cp = key; *cp; cp++) { + c = *cp; + c = UPPER_CASE(c); + hash += c << s; + s += 5; + if (s >= 25) + s -= 24; + } + } + else { + for (cp = key; *cp; cp++) { + hash += (*cp) << s; + s += 5; + if (s >= 25) + s -= 24; + } + } + + return (hash % h->size); +} + + +static char * +makekey(uint8 * data, size_t len, char *key) +{ + size_t i, j; + + if (!key) + key = (char *) ckd_calloc(len * 2 + 1, sizeof(char)); + + for (i = 0, j = 0; i < len; i++, j += 2) { + key[j] = 'A' + (data[i] & 0x000f); + key[j + 1] = 'J' + ((data[i] >> 4) & 0x000f); + } + key[j] = '\0'; + + return key; +} + + +static int32 +keycmp_nocase(hash_entry_t * entry, const char *key) +{ + char c1, c2; + int32 i; + const char *str; + + str = entry->key; + for (i = 0; i < entry->len; i++) { + c1 = *(str++); + c1 = UPPER_CASE(c1); + c2 = *(key++); + c2 = UPPER_CASE(c2); + if (c1 != c2) + return (c1 - c2); + } + + return 0; +} + + +static int32 +keycmp_case(hash_entry_t * entry, const char *key) +{ + char c1, c2; + int32 i; + const char *str; + + str = entry->key; + for (i = 0; i < entry->len; i++) { + c1 = *(str++); + c2 = *(key++); + if (c1 != c2) + return (c1 - c2); + } + + return 0; +} + + +/* + * Lookup entry with hash-value hash in table h for given key + * Return value: hash_entry_t for key + */ +static hash_entry_t * +lookup(hash_table_t * h, uint32 hash, const char *key, size_t len) +{ + hash_entry_t *entry; + + entry = &(h->table[hash]); + if (entry->key == NULL) + return NULL; + + if (h->nocase) { + while (entry && ((entry->len != len) + || (keycmp_nocase(entry, key) != 0))) + entry = entry->next; + } + else { + while (entry && ((entry->len != len) + || (keycmp_case(entry, key) != 0))) + entry = entry->next; + } + + return entry; +} + + +int32 +hash_table_lookup(hash_table_t * h, const char *key, void ** val) +{ + hash_entry_t *entry; + uint32 hash; + size_t len; + + hash = key2hash(h, key); + len = strlen(key); + + entry = lookup(h, hash, key, len); + if (entry) { + if (val) + *val = entry->val; + return 0; + } + else + return -1; +} + +int32 +hash_table_lookup_int32(hash_table_t * h, const char *key, int32 *val) +{ + void *vval; + int32 rv; + + rv = hash_table_lookup(h, key, &vval); + if (rv != 0) + return rv; + if (val) + *val = (int32)(long)vval; + return 0; +} + + +int32 +hash_table_lookup_bkey(hash_table_t * h, const char *key, size_t len, void ** val) +{ + hash_entry_t *entry; + uint32 hash; + char *str; + + str = makekey((uint8 *) key, len, NULL); + hash = key2hash(h, str); + ckd_free(str); + + entry = lookup(h, hash, key, len); + if (entry) { + if (val) + *val = entry->val; + return 0; + } + else + return -1; +} + +int32 +hash_table_lookup_bkey_int32(hash_table_t * h, const char *key, size_t len, int32 *val) +{ + void *vval; + int32 rv; + + rv = hash_table_lookup_bkey(h, key, len, &vval); + if (rv != 0) + return rv; + if (val) + *val = (int32)(long)vval; + return 0; +} + + +static void * +enter(hash_table_t * h, uint32 hash, const char *key, size_t len, void *val, int32 replace) +{ + hash_entry_t *cur, *new; + + if ((cur = lookup(h, hash, key, len)) != NULL) { + void *oldval; + /* Key already exists. */ + oldval = cur->val; + if (replace) { + /* Replace the pointer if replacement is requested, + * because this might be a different instance of the same + * string (this verges on magic, sorry) */ + cur->key = key; + cur->val = val; + } + return oldval; + } + + cur = &(h->table[hash]); + if (cur->key == NULL) { + /* Empty slot at hashed location; add this entry */ + cur->key = key; + cur->len = len; + cur->val = val; + + /* Added by ARCHAN at 20050515. This allows deletion could work. */ + cur->next = NULL; + + } + else { + /* Key collision; create new entry and link to hashed location */ + new = (hash_entry_t *) ckd_calloc(1, sizeof(hash_entry_t)); + new->key = key; + new->len = len; + new->val = val; + new->next = cur->next; + cur->next = new; + } + ++h->inuse; + + return val; +} + +/* 20050523 Added by ARCHAN to delete a key from a hash table */ +static void * +delete(hash_table_t * h, uint32 hash, const char *key, size_t len) +{ + hash_entry_t *entry, *prev; + void *val; + + prev = NULL; + entry = &(h->table[hash]); + if (entry->key == NULL) + return NULL; + + if (h->nocase) { + while (entry && ((entry->len != len) + || (keycmp_nocase(entry, key) != 0))) { + prev = entry; + entry = entry->next; + } + } + else { + while (entry && ((entry->len != len) + || (keycmp_case(entry, key) != 0))) { + prev = entry; + entry = entry->next; + } + } + + if (entry == NULL) + return NULL; + + /* At this point, entry will be the one required to be deleted, prev + will contain the previous entry + */ + val = entry->val; + + if (prev == NULL) { + /* That is to say the entry in the hash table (not the chain) matched the key. */ + /* We will then copy the things from the next entry to the hash table */ + prev = entry; + if (entry->next) { /* There is a next entry, great, copy it. */ + entry = entry->next; + prev->key = entry->key; + prev->len = entry->len; + prev->val = entry->val; + prev->next = entry->next; + ckd_free(entry); + } + else { /* There is not a next entry, just set the key to null */ + prev->key = NULL; + prev->len = 0; + prev->next = NULL; + } + + } + else { /* This case is simple */ + prev->next = entry->next; + ckd_free(entry); + } + + /* Do wiring and free the entry */ + + --h->inuse; + + return val; +} + +void +hash_table_empty(hash_table_t *h) +{ + hash_entry_t *e, *e2; + int32 i; + + for (i = 0; i < h->size; i++) { + /* Free collision lists. */ + for (e = h->table[i].next; e; e = e2) { + e2 = e->next; + ckd_free((void *) e); + } + memset(&h->table[i], 0, sizeof(h->table[i])); + } + h->inuse = 0; +} + + +void * +hash_table_enter(hash_table_t * h, const char *key, void *val) +{ + uint32 hash; + size_t len; + + hash = key2hash(h, key); + len = strlen(key); + return (enter(h, hash, key, len, val, 0)); +} + +void * +hash_table_replace(hash_table_t * h, const char *key, void *val) +{ + uint32 hash; + size_t len; + + hash = key2hash(h, key); + len = strlen(key); + return (enter(h, hash, key, len, val, 1)); +} + +void * +hash_table_delete(hash_table_t * h, const char *key) +{ + uint32 hash; + size_t len; + + hash = key2hash(h, key); + len = strlen(key); + + return (delete(h, hash, key, len)); +} + +void * +hash_table_enter_bkey(hash_table_t * h, const char *key, size_t len, void *val) +{ + uint32 hash; + char *str; + + str = makekey((uint8 *) key, len, NULL); + hash = key2hash(h, str); + ckd_free(str); + + return (enter(h, hash, key, len, val, 0)); +} + +void * +hash_table_replace_bkey(hash_table_t * h, const char *key, size_t len, void *val) +{ + uint32 hash; + char *str; + + str = makekey((uint8 *) key, len, NULL); + hash = key2hash(h, str); + ckd_free(str); + + return (enter(h, hash, key, len, val, 1)); +} + +void * +hash_table_delete_bkey(hash_table_t * h, const char *key, size_t len) +{ + uint32 hash; + char *str; + + str = makekey((uint8 *) key, len, NULL); + hash = key2hash(h, str); + ckd_free(str); + + return (delete(h, hash, key, len)); +} + +void +hash_table_display(hash_table_t * h, int32 showdisplay) +{ + hash_entry_t *e; + int i, j; + j = 0; + + printf("Hash with chaining representation of the hash table\n"); + + for (i = 0; i < h->size; i++) { + e = &(h->table[i]); + if (e->key != NULL) { + printf("|key:"); + if (showdisplay) + printf("%s", e->key); + else + printf("%p", e->key); + + printf("|len:%zd|val=%ld|->", e->len, (long)e->val); + if (e->next == NULL) { + printf("NULL\n"); + } + j++; + + for (e = e->next; e; e = e->next) { + printf("|key:"); + if (showdisplay) + printf("%s", e->key); + + printf("|len:%zd|val=%ld|->", e->len, (long)e->val); + if (e->next == NULL) { + printf("NULL\n"); + } + j++; + } + } + } + + printf("The total number of keys =%d\n", j); +} + + +glist_t +hash_table_tolist(hash_table_t * h, int32 * count) +{ + glist_t g; + hash_entry_t *e; + int32 i, j; + + g = NULL; + + j = 0; + for (i = 0; i < h->size; i++) { + e = &(h->table[i]); + + if (e->key != NULL) { + g = glist_add_ptr(g, (void *) e); + j++; + + for (e = e->next; e; e = e->next) { + g = glist_add_ptr(g, (void *) e); + j++; + } + } + } + + if (count) + *count = j; + + return g; +} + +hash_iter_t * +hash_table_iter(hash_table_t *h) +{ + hash_iter_t *itor; + + itor = ckd_calloc(1, sizeof(*itor)); + itor->ht = h; + return hash_table_iter_next(itor); +} + +hash_iter_t * +hash_table_iter_next(hash_iter_t *itor) +{ + /* If there is an entry, walk down its list. */ + if (itor->ent) + itor->ent = itor->ent->next; + /* If we got to the end of the chain, or we had no entry, scan + * forward in the table to find the next non-empty bucket. */ + if (itor->ent == NULL) { + while (itor->idx < itor->ht->size + && itor->ht->table[itor->idx].key == NULL) + ++itor->idx; + /* If we did not find one then delete the iterator and + * return NULL. */ + if (itor->idx == itor->ht->size) { + hash_table_iter_free(itor); + return NULL; + } + /* Otherwise use this next entry. */ + itor->ent = itor->ht->table + itor->idx; + /* Increase idx for the next time around. */ + ++itor->idx; + } + return itor; +} + +void +hash_table_iter_free(hash_iter_t *itor) +{ + ckd_free(itor); +} + +void +hash_table_free(hash_table_t * h) +{ + hash_entry_t *e, *e2; + int32 i; + + if (h == NULL) + return; + + /* Free additional entries created for key collision cases */ + for (i = 0; i < h->size; i++) { + for (e = h->table[i].next; e; e = e2) { + e2 = e->next; + ckd_free((void *) e); + } + } + + ckd_free((void *) h->table); + ckd_free((void *) h); +} diff --git a/media/sphinxbase/src/libsphinxbase/util/heap.c b/media/sphinxbase/src/libsphinxbase/util/heap.c new file mode 100644 index 000000000..2209a0393 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/heap.c @@ -0,0 +1,292 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * heap.c -- Generic heap structure for inserting in any and popping in sorted + * order. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: heap.c,v $ + * Revision 1.4 2005/06/22 03:05:49 arthchan2003 + * 1, Fixed doxygen documentation, 2, Add keyword. + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 05-Mar-99 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Fixed bug in heap_destroy() (in while loop exit condition). + * + * 23-Dec-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Started. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "sphinxbase/heap.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" + +/** + * One node on the heap + */ +typedef struct heapnode_s { + void *data; /**< Application data at this node */ + int32 val; /**< Associated with above application data; according to which + heap is sorted (in ascending order) */ + int32 nl, nr; /**< #left/right descendants of this node (for balancing heap) */ + struct heapnode_s *l; /**< Root of left descendant heap */ + struct heapnode_s *r; /**< Root of right descendant heap */ +} heapnode_t; + +/** + * Internal heap data structure. + */ +struct heap_s { + heapnode_t *top; +}; + + +#if 0 +static void +heap_dump(heapnode_t * top, int32 level) +{ + int32 i; + + if (!top) + return; + + for (i = 0; i < level; i++) + printf(" "); + /* print top info */ + heap_dump(top->l, level + 1); + heap_dump(top->r, level + 1); +} +#endif + + +heap_t * +heap_new(void) +{ + heap_t *h = ckd_calloc(1, sizeof(*h)); + return h; +} + + +static heapnode_t * +subheap_insert(heapnode_t * root, void *data, int32 val) +{ + heapnode_t *h; + void *tmpdata; + int32 tmpval; + + if (!root) { + h = (heapnode_t *) ckd_calloc(1, sizeof(heapnode_t)); + h->data = data; + h->val = val; + h->l = h->r = NULL; + h->nl = h->nr = 0; + return h; + } + + /* Root already exists; if new value is less, replace root node */ + if (root->val > val) { + tmpdata = root->data; + tmpval = root->val; + root->data = data; + root->val = val; + data = tmpdata; + val = tmpval; + } + + /* Insert new or old (replaced) node in right or left subtree; keep them balanced */ + if (root->nl > root->nr) { + root->r = subheap_insert(root->r, data, val); + root->nr++; + } + else { + root->l = subheap_insert(root->l, data, val); + root->nl++; + } + + return root; +} + + +int +heap_insert(heap_t *heap, void *data, int32 val) +{ + heap->top = subheap_insert(heap->top, data, val); + return 0; +} + + +static heapnode_t * +subheap_pop(heapnode_t * root) +{ + heapnode_t *l, *r; + + /* Propagate best value from below into root, if any */ + l = root->l; + r = root->r; + + if (!l) { + if (!r) { + ckd_free((char *) root); + return NULL; + } + else { + root->data = r->data; + root->val = r->val; + root->r = subheap_pop(r); + root->nr--; + } + } + else { + if ((!r) || (l->val < r->val)) { + root->data = l->data; + root->val = l->val; + root->l = subheap_pop(l); + root->nl--; + } + else { + root->data = r->data; + root->val = r->val; + root->r = subheap_pop(r); + root->nr--; + } + } + + return root; +} + + +int +heap_pop(heap_t *heap, void **data, int32 * val) +{ + if (heap->top == NULL) + return 0; + *data = heap->top->data; + *val = heap->top->val; + heap->top = subheap_pop(heap->top); + return 1; +} + + +int +heap_top(heap_t *heap, void **data, int32 * val) +{ + if (heap->top == NULL) + return 0; + *data = heap->top->data; + *val = heap->top->val; + return 1; +} + +static int +heap_remove_one(heap_t *heap, heapnode_t *top, void *data) +{ + if (top == NULL) + return -1; + else if (top->data == data) { + assert(top == heap->top); + heap->top = subheap_pop(heap->top); + return 0; + } + if (top->l) { + if (top->l->data == data) { + top->l = subheap_pop(top->l); + --top->nl; + return 0; + } + else if (heap_remove_one(heap, top->l, data) == 0) { + --top->nl; + return 0; + } + } + if (top->r) { + if (top->r->data == data) { + top->r = subheap_pop(top->r); + --top->nr; + return 0; + } + else if (heap_remove_one(heap, top->r, data) == 0) { + --top->nr; + return 0; + } + } + return -1; +} + +int +heap_remove(heap_t *heap, void *data) +{ + return heap_remove_one(heap, heap->top, data); +} + + +size_t +heap_size(heap_t *heap) +{ + if (heap->top == NULL) + return 0; + return heap->top->nl + heap->top->nr + 1; +} + +int +heap_destroy(heap_t *heap) +{ + void *data; + int32 val; + + /* Empty the heap and free it */ + while (heap_pop(heap, &data, &val) > 0) + ; + ckd_free(heap); + + return 0; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/huff_code.c b/media/sphinxbase/src/libsphinxbase/util/huff_code.c new file mode 100644 index 000000000..dd3fb582d --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/huff_code.c @@ -0,0 +1,651 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 2009 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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 <string.h> + +#include "sphinxbase/huff_code.h" +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/hash_table.h" +#include "sphinxbase/byteorder.h" +#include "sphinxbase/heap.h" +#include "sphinxbase/pio.h" +#include "sphinxbase/err.h" + +typedef struct huff_node_s { + int nbits; + struct huff_node_s *l; + union { + int32 ival; + char *sval; + struct huff_node_s *r; + } r; +} huff_node_t; + +typedef struct huff_codeword_s { + union { + int32 ival; + char *sval; + } r; + uint32 nbits, codeword; +} huff_codeword_t; + +enum { + HUFF_CODE_INT, + HUFF_CODE_STR +}; + +struct huff_code_s { + int16 refcount; + uint8 maxbits; + uint8 type; + uint32 *firstcode; + uint32 *numl; + huff_codeword_t **syms; + hash_table_t *codewords; + FILE *fh; + bit_encode_t *be; + int boff; +}; + +static huff_node_t * +huff_node_new_int(int32 val) +{ + huff_node_t *hn = ckd_calloc(1, sizeof(*hn)); + hn->r.ival = val; + return hn; +} + +static huff_node_t * +huff_node_new_str(char const *val) +{ + huff_node_t *hn = ckd_calloc(1, sizeof(*hn)); + hn->r.sval = ckd_salloc(val); + return hn; +} + +static huff_node_t * +huff_node_new_parent(huff_node_t *l, huff_node_t *r) +{ + huff_node_t *hn = ckd_calloc(1, sizeof(*hn)); + hn->l = l; + hn->r.r = r; + /* Propagate maximum bit length. */ + if (r->nbits > l->nbits) + hn->nbits = r->nbits + 1; + else + hn->nbits = l->nbits + 1; + return hn; +} + +static void +huff_node_free_int(huff_node_t *root) +{ + if (root->l) { + huff_node_free_int(root->l); + huff_node_free_int(root->r.r); + } + ckd_free(root); +} + +static void +huff_node_free_str(huff_node_t *root, int freestr) +{ + if (root->l) { + huff_node_free_str(root->l, freestr); + huff_node_free_str(root->r.r, freestr); + } + else { + if (freestr) + ckd_free(root->r.sval); + } + ckd_free(root); +} + +static huff_node_t * +huff_code_build_tree(heap_t *q) +{ + huff_node_t *root = NULL; + int32 rf; + + while (heap_size(q) > 1) { + huff_node_t *l, *r, *p; + int32 lf, rf; + + heap_pop(q, (void *)&l, &lf); + heap_pop(q, (void *)&r, &rf); + p = huff_node_new_parent(l, r); + heap_insert(q, p, lf + rf); + } + heap_pop(q, (void **)&root, &rf); + return root; +} + +static void +huff_code_canonicalize(huff_code_t *hc, huff_node_t *root) +{ + glist_t agenda; + uint32 *nextcode; + int i, ncw; + + hc->firstcode = ckd_calloc(hc->maxbits+1, sizeof(*hc->firstcode)); + hc->syms = ckd_calloc(hc->maxbits+1, sizeof(*hc->syms)); + hc->numl = ckd_calloc(hc->maxbits+1, sizeof(*nextcode)); + nextcode = ckd_calloc(hc->maxbits+1, sizeof(*nextcode)); + + /* Traverse the tree, annotating it with the actual bit + * lengths, and histogramming them in numl. */ + root->nbits = 0; + ncw = 0; + agenda = glist_add_ptr(NULL, root); + while (agenda) { + huff_node_t *node = gnode_ptr(agenda); + agenda = gnode_free(agenda, NULL); + if (node->l) { + node->l->nbits = node->nbits + 1; + agenda = glist_add_ptr(agenda, node->l); + node->r.r->nbits = node->nbits + 1; + agenda = glist_add_ptr(agenda, node->r.r); + } + else { + hc->numl[node->nbits]++; + ncw++; + } + } + /* Create starting codes and symbol tables for each bit length. */ + hc->syms[hc->maxbits] = ckd_calloc(hc->numl[hc->maxbits], sizeof(**hc->syms)); + for (i = hc->maxbits - 1; i > 0; --i) { + hc->firstcode[i] = (hc->firstcode[i+1] + hc->numl[i+1]) / 2; + hc->syms[i] = ckd_calloc(hc->numl[i], sizeof(**hc->syms)); + } + memcpy(nextcode, hc->firstcode, (hc->maxbits + 1) * sizeof(*nextcode)); + /* Traverse the tree again to produce the codebook itself. */ + hc->codewords = hash_table_new(ncw, HASH_CASE_YES); + agenda = glist_add_ptr(NULL, root); + while (agenda) { + huff_node_t *node = gnode_ptr(agenda); + agenda = gnode_free(agenda, NULL); + if (node->l) { + agenda = glist_add_ptr(agenda, node->l); + agenda = glist_add_ptr(agenda, node->r.r); + } + else { + /* Initialize codebook entry, which also retains symbol pointer. */ + huff_codeword_t *cw; + uint32 codeword = nextcode[node->nbits] & ((1 << node->nbits) - 1); + cw = hc->syms[node->nbits] + (codeword - hc->firstcode[node->nbits]); + cw->nbits = node->nbits; + cw->r.sval = node->r.sval; /* Will copy ints too... */ + cw->codeword = codeword; + if (hc->type == HUFF_CODE_INT) { + hash_table_enter_bkey(hc->codewords, + (char const *)&cw->r.ival, + sizeof(cw->r.ival), + (void *)cw); + } + else { + hash_table_enter(hc->codewords, cw->r.sval, (void *)cw); + } + ++nextcode[node->nbits]; + } + } + ckd_free(nextcode); +} + +huff_code_t * +huff_code_build_int(int32 const *values, int32 const *frequencies, int nvals) +{ + huff_code_t *hc; + huff_node_t *root; + heap_t *q; + int i; + + hc = ckd_calloc(1, sizeof(*hc)); + hc->refcount = 1; + hc->type = HUFF_CODE_INT; + + /* Initialize the heap with nodes for each symbol. */ + q = heap_new(); + for (i = 0; i < nvals; ++i) { + heap_insert(q, + huff_node_new_int(values[i]), + frequencies[i]); + } + + /* Now build the tree, which gives us codeword lengths. */ + root = huff_code_build_tree(q); + heap_destroy(q); + if (root == NULL || root->nbits > 32) { + E_ERROR("Huffman trees currently limited to 32 bits\n"); + huff_node_free_int(root); + huff_code_free(hc); + return NULL; + } + + /* Build a canonical codebook. */ + hc->maxbits = root->nbits; + huff_code_canonicalize(hc, root); + + /* Tree no longer needed. */ + huff_node_free_int(root); + + return hc; +} + +huff_code_t * +huff_code_build_str(char * const *values, int32 const *frequencies, int nvals) +{ + huff_code_t *hc; + huff_node_t *root; + heap_t *q; + int i; + + hc = ckd_calloc(1, sizeof(*hc)); + hc->refcount = 1; + hc->type = HUFF_CODE_STR; + + /* Initialize the heap with nodes for each symbol. */ + q = heap_new(); + for (i = 0; i < nvals; ++i) { + heap_insert(q, + huff_node_new_str(values[i]), + frequencies[i]); + } + + /* Now build the tree, which gives us codeword lengths. */ + root = huff_code_build_tree(q); + heap_destroy(q); + if (root == NULL || root->nbits > 32) { + E_ERROR("Huffman trees currently limited to 32 bits\n"); + huff_node_free_str(root, TRUE); + huff_code_free(hc); + return NULL; + } + + /* Build a canonical codebook. */ + hc->maxbits = root->nbits; + huff_code_canonicalize(hc, root); + + /* Tree no longer needed (note we retain pointers to its strings). */ + huff_node_free_str(root, FALSE); + + return hc; +} + +huff_code_t * +huff_code_read(FILE *infh) +{ + huff_code_t *hc; + int i, j; + + hc = ckd_calloc(1, sizeof(*hc)); + hc->refcount = 1; + + hc->maxbits = fgetc(infh); + hc->type = fgetc(infh); + + /* Two bytes of padding. */ + fgetc(infh); + fgetc(infh); + + /* Allocate stuff. */ + hc->firstcode = ckd_calloc(hc->maxbits + 1, sizeof(*hc->firstcode)); + hc->numl = ckd_calloc(hc->maxbits + 1, sizeof(*hc->numl)); + hc->syms = ckd_calloc(hc->maxbits + 1, sizeof(*hc->syms)); + + /* Read the symbol tables. */ + hc->codewords = hash_table_new(hc->maxbits, HASH_CASE_YES); + for (i = 1; i <= hc->maxbits; ++i) { + if (fread(&hc->firstcode[i], 4, 1, infh) != 1) + goto error_out; + SWAP_BE_32(&hc->firstcode[i]); + if (fread(&hc->numl[i], 4, 1, infh) != 1) + goto error_out; + SWAP_BE_32(&hc->numl[i]); + hc->syms[i] = ckd_calloc(hc->numl[i], sizeof(**hc->syms)); + for (j = 0; j < hc->numl[i]; ++j) { + huff_codeword_t *cw = &hc->syms[i][j]; + cw->nbits = i; + cw->codeword = hc->firstcode[i] + j; + if (hc->type == HUFF_CODE_INT) { + if (fread(&cw->r.ival, 4, 1, infh) != 1) + goto error_out; + SWAP_BE_32(&cw->r.ival); + hash_table_enter_bkey(hc->codewords, + (char const *)&cw->r.ival, + sizeof(cw->r.ival), + (void *)cw); + } + else { + size_t len; + cw->r.sval = fread_line(infh, &len); + cw->r.sval[len-1] = '\0'; + hash_table_enter(hc->codewords, cw->r.sval, (void *)cw); + } + } + } + + return hc; +error_out: + huff_code_free(hc); + return NULL; +} + +int +huff_code_write(huff_code_t *hc, FILE *outfh) +{ + int i, j; + + /* Maximum codeword length */ + fputc(hc->maxbits, outfh); + /* Symbol type */ + fputc(hc->type, outfh); + /* Two extra bytes (for future use and alignment) */ + fputc(0, outfh); + fputc(0, outfh); + /* For each codeword length: */ + for (i = 1; i <= hc->maxbits; ++i) { + uint32 val; + + /* Starting code, number of codes. */ + val = hc->firstcode[i]; + /* Canonically big-endian (like the data itself) */ + SWAP_BE_32(&val); + fwrite(&val, 4, 1, outfh); + val = hc->numl[i]; + SWAP_BE_32(&val); + fwrite(&val, 4, 1, outfh); + + /* Symbols for each code (FIXME: Should compress these too) */ + for (j = 0; j < hc->numl[i]; ++j) { + if (hc->type == HUFF_CODE_INT) { + int32 val = hc->syms[i][j].r.ival; + SWAP_BE_32(&val); + fwrite(&val, 4, 1, outfh); + } + else { + /* Write them all separated by newlines, so that + * fgets() will read them for us. */ + fprintf(outfh, "%s\n", hc->syms[i][j].r.sval); + } + } + } + return 0; +} + +int +huff_code_dump_codebits(FILE *dumpfh, uint32 nbits, uint32 codeword) +{ + uint32 i; + + for (i = 0; i < nbits; ++i) + fputc((codeword & (1<<(nbits-i-1))) ? '1' : '0', dumpfh); + return 0; +} + +int +huff_code_dump(huff_code_t *hc, FILE *dumpfh) +{ + int i, j; + + /* Print out all codewords. */ + fprintf(dumpfh, "Maximum codeword length: %d\n", hc->maxbits); + fprintf(dumpfh, "Symbols are %s\n", (hc->type == HUFF_CODE_STR) ? "strings" : "ints"); + fprintf(dumpfh, "Codewords:\n"); + for (i = 1; i <= hc->maxbits; ++i) { + for (j = 0; j < hc->numl[i]; ++j) { + if (hc->type == HUFF_CODE_STR) + fprintf(dumpfh, "%-30s", hc->syms[i][j].r.sval); + else + fprintf(dumpfh, "%-30d", hc->syms[i][j].r.ival); + huff_code_dump_codebits(dumpfh, hc->syms[i][j].nbits, + hc->syms[i][j].codeword); + fprintf(dumpfh, "\n"); + } + } + return 0; +} + +huff_code_t * +huff_code_retain(huff_code_t *hc) +{ + ++hc->refcount; + return hc; +} + +int +huff_code_free(huff_code_t *hc) +{ + int i; + + if (hc == NULL) + return 0; + if (--hc->refcount > 0) + return hc->refcount; + for (i = 0; i <= hc->maxbits; ++i) { + int j; + for (j = 0; j < hc->numl[i]; ++j) { + if (hc->type == HUFF_CODE_STR) + ckd_free(hc->syms[i][j].r.sval); + } + ckd_free(hc->syms[i]); + } + ckd_free(hc->firstcode); + ckd_free(hc->numl); + ckd_free(hc->syms); + hash_table_free(hc->codewords); + ckd_free(hc); + return 0; +} + +FILE * +huff_code_attach(huff_code_t *hc, FILE *fh, char const *mode) +{ + FILE *oldfh = huff_code_detach(hc); + + hc->fh = fh; + if (mode[0] == 'w') + hc->be = bit_encode_attach(hc->fh); + return oldfh; +} + +FILE * +huff_code_detach(huff_code_t *hc) +{ + FILE *oldfh = hc->fh; + + if (hc->be) { + bit_encode_flush(hc->be); + bit_encode_free(hc->be); + hc->be = NULL; + } + hc->fh = NULL; + return oldfh; +} + +int +huff_code_encode_int(huff_code_t *hc, int32 sym, uint32 *outcw) +{ + huff_codeword_t *cw; + + if (hash_table_lookup_bkey(hc->codewords, + (char const *)&sym, + sizeof(sym), + (void **)&cw) < 0) + return 0; + if (hc->be) + bit_encode_write_cw(hc->be, cw->codeword, cw->nbits); + if (outcw) *outcw = cw->codeword; + return cw->nbits; +} + +int +huff_code_encode_str(huff_code_t *hc, char const *sym, uint32 *outcw) +{ + huff_codeword_t *cw; + + if (hash_table_lookup(hc->codewords, + sym, + (void **)&cw) < 0) + return 0; + if (hc->be) + bit_encode_write_cw(hc->be, cw->codeword, cw->nbits); + if (outcw) *outcw = cw->codeword; + return cw->nbits; +} + +static huff_codeword_t * +huff_code_decode_data(huff_code_t *hc, char const **inout_data, + size_t *inout_data_len, int *inout_offset) +{ + char const *data = *inout_data; + char const *end = data + *inout_data_len; + int offset = *inout_offset; + uint32 cw; + int cwlen; + int byte; + + if (data == end) + return NULL; + byte = *data++; + cw = !!(byte & (1 << (7-offset++))); + cwlen = 1; + /* printf("%.*x ", cwlen, cw); */ + while (cwlen <= hc->maxbits && cw < hc->firstcode[cwlen]) { + ++cwlen; + cw <<= 1; + if (offset > 7) { + if (data == end) + return NULL; + byte = *data++; + offset = 0; + } + cw |= !!(byte & (1 << (7-offset++))); + /* printf("%.*x ", cwlen, cw); */ + } + if (cwlen > hc->maxbits) /* FAIL: invalid data */ + return NULL; + + /* Put the last byte back if there are bits left over. */ + if (offset < 8) + --data; + else + offset = 0; + + /* printf("%.*x\n", cwlen, cw); */ + *inout_data_len = end - data; + *inout_data = data; + *inout_offset = offset; + return hc->syms[cwlen] + (cw - hc->firstcode[cwlen]); +} + +static huff_codeword_t * +huff_code_decode_fh(huff_code_t *hc) +{ + uint32 cw; + int cwlen; + int byte; + + if ((byte = fgetc(hc->fh)) == EOF) + return NULL; + cw = !!(byte & (1 << (7-hc->boff++))); + cwlen = 1; + /* printf("%.*x ", cwlen, cw); */ + while (cwlen <= hc->maxbits && cw < hc->firstcode[cwlen]) { + ++cwlen; + cw <<= 1; + if (hc->boff > 7) { + if ((byte = fgetc(hc->fh)) == EOF) + return NULL; + hc->boff = 0; + } + cw |= !!(byte & (1 << (7-hc->boff++))); + /* printf("%.*x ", cwlen, cw); */ + } + if (cwlen > hc->maxbits) /* FAIL: invalid data */ + return NULL; + + /* Put the last byte back if there are bits left over. */ + if (hc->boff < 8) + ungetc(byte, hc->fh); + else + hc->boff = 0; + + /* printf("%.*x\n", cwlen, cw); */ + return hc->syms[cwlen] + (cw - hc->firstcode[cwlen]); +} + +int +huff_code_decode_int(huff_code_t *hc, int *outval, + char const **inout_data, + size_t *inout_data_len, int *inout_offset) +{ + huff_codeword_t *cw; + + if (inout_data) + cw = huff_code_decode_data(hc, inout_data, inout_data_len, inout_offset); + else if (hc->fh) + cw = huff_code_decode_fh(hc); + else + return -1; + + if (cw == NULL) + return -1; + if (outval) + *outval = cw->r.ival; + + return 0; +} + +char const * +huff_code_decode_str(huff_code_t *hc, + char const **inout_data, + size_t *inout_data_len, int *inout_offset) +{ + huff_codeword_t *cw; + + if (inout_data) + cw = huff_code_decode_data(hc, inout_data, inout_data_len, inout_offset); + else if (hc->fh) + cw = huff_code_decode_fh(hc); + else + return NULL; + + if (cw == NULL) + return NULL; + + return cw->r.sval; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/listelem_alloc.c b/media/sphinxbase/src/libsphinxbase/util/listelem_alloc.c new file mode 100644 index 000000000..354c4767c --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/listelem_alloc.c @@ -0,0 +1,294 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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 <stdio.h> +#include <stdlib.h> + +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/listelem_alloc.h" +#include "sphinxbase/glist.h" + +/** + * Fast linked list allocator. + * + * We keep a separate linked list for each element-size. Element-size + * must be a multiple of pointer-size. + * + * Initially a block of empty elements is allocated, where the first + * machine word in each element points to the next available element. + * To allocate, we use this pointer to move the freelist to the next + * element, then return the current element. + * + * The last element in the list starts with a NULL pointer, which is + * used as a signal to allocate a new block of elements. + * + * In order to be able to actually release the memory allocated, we + * have to add a linked list of block pointers. This shouldn't create + * much overhead since we never access it except when freeing the + * allocator. + */ +struct listelem_alloc_s { + char **freelist; /**< ptr to first element in freelist */ + glist_t blocks; /**< Linked list of blocks allocated. */ + glist_t blocksize; /**< Number of elements in each block */ + size_t elemsize; /**< Number of (char *) in element */ + size_t blk_alloc; /**< Number of alloc operations before increasing blocksize */ + size_t n_blocks; + size_t n_alloc; + size_t n_freed; +}; + +#define MIN_ALLOC 50 /**< Minimum number of elements to allocate in one block */ +#define BLKID_SHIFT 16 /**< Bit position of block number in element ID */ +#define BLKID_MASK ((1<<BLKID_SHIFT)-1) + +/** + * Allocate a new block of elements. + */ +static void listelem_add_block(listelem_alloc_t *list, + char *caller_file, int caller_line); + +listelem_alloc_t * +listelem_alloc_init(size_t elemsize) +{ + listelem_alloc_t *list; + + if ((elemsize % sizeof(void *)) != 0) { + size_t rounded = (elemsize + sizeof(void *) - 1) & ~(sizeof(void *)-1); + E_WARN + ("List item size (%lu) not multiple of sizeof(void *), rounding to %lu\n", + (unsigned long)elemsize, + (unsigned long)rounded); + elemsize = rounded; + } + list = ckd_calloc(1, sizeof(*list)); + list->freelist = NULL; + list->blocks = NULL; + list->elemsize = elemsize; + /* Intent of this is to increase block size once we allocate + * 256KiB (i.e. 1<<18). If somehow the element size is big enough + * to overflow that, just fail, people should use malloc anyway. */ + list->blk_alloc = (1 << 18) / (MIN_ALLOC * elemsize); + if (list->blk_alloc <= 0) { + E_ERROR("Element size * block size exceeds 256k, use malloc instead.\n"); + ckd_free(list); + return NULL; + } + list->n_alloc = 0; + list->n_freed = 0; + + /* Allocate an initial block to minimize latency. */ + listelem_add_block(list, __FILE__, __LINE__); + return list; +} + +void +listelem_alloc_free(listelem_alloc_t *list) +{ + gnode_t *gn; + if (list == NULL) + return; + for (gn = list->blocks; gn; gn = gnode_next(gn)) + ckd_free(gnode_ptr(gn)); + glist_free(list->blocks); + glist_free(list->blocksize); + ckd_free(list); +} + +static void +listelem_add_block(listelem_alloc_t *list, char *caller_file, int caller_line) +{ + char **cpp, *cp; + size_t j; + int32 blocksize; + + blocksize = list->blocksize ? gnode_int32(list->blocksize) : MIN_ALLOC; + /* Check if block size should be increased (if many requests for this size) */ + if (list->blk_alloc == 0) { + /* See above. No sense in allocating blocks bigger than + * 256KiB (well, actually, there might be, but we'll worry + * about that later). */ + blocksize <<= 1; + if (blocksize * list->elemsize > (1 << 18)) + blocksize = (1 << 18) / list->elemsize; + list->blk_alloc = (1 << 18) / (blocksize * list->elemsize); + } + + /* Allocate block */ + cpp = list->freelist = + (char **) __ckd_calloc__(blocksize, list->elemsize, + caller_file, caller_line); + list->blocks = glist_add_ptr(list->blocks, cpp); + list->blocksize = glist_add_int32(list->blocksize, blocksize); + cp = (char *) cpp; + /* Link up the blocks via their first machine word. */ + for (j = blocksize - 1; j > 0; --j) { + cp += list->elemsize; + *cpp = cp; + cpp = (char **) cp; + } + /* Make sure the last element's forward pointer is NULL */ + *cpp = NULL; + --list->blk_alloc; + ++list->n_blocks; +} + + +void * +__listelem_malloc__(listelem_alloc_t *list, char *caller_file, int caller_line) +{ + char **ptr; + + /* Allocate a new block if list empty */ + if (list->freelist == NULL) + listelem_add_block(list, caller_file, caller_line); + + /* Unlink and return first element in freelist */ + ptr = list->freelist; + list->freelist = (char **) (*(list->freelist)); + (list->n_alloc)++; + + return (void *)ptr; +} + +void * +__listelem_malloc_id__(listelem_alloc_t *list, char *caller_file, + int caller_line, int32 *out_id) +{ + char **ptr; + + /* Allocate a new block if list empty */ + if (list->freelist == NULL) + listelem_add_block(list, caller_file, caller_line); + + /* Unlink and return first element in freelist */ + ptr = list->freelist; + list->freelist = (char **) (*(list->freelist)); + (list->n_alloc)++; + + if (out_id) { + int32 blksize, blkidx, ptridx; + gnode_t *gn, *gn2; + char **block; + + gn2 = list->blocksize; + block = NULL; + blkidx = 0; + for (gn = list->blocks; gn; gn = gnode_next(gn)) { + block = gnode_ptr(gn); + blksize = gnode_int32(gn2) * list->elemsize / sizeof(*block); + if (ptr >= block && ptr < block + blksize) + break; + gn2 = gnode_next(gn2); + ++blkidx; + } + if (gn == NULL) { + E_ERROR("Failed to find block index for pointer %p!\n", ptr); + } + ptridx = (ptr - block) / (list->elemsize / sizeof(*block)); + E_DEBUG(4,("ptr %p block %p blkidx %d ptridx %d\n", + ptr, block, list->n_blocks - blkidx - 1, ptridx)); + *out_id = ((list->n_blocks - blkidx - 1) << BLKID_SHIFT) | ptridx; + } + + return ptr; +} + +void * +listelem_get_item(listelem_alloc_t *list, int32 id) +{ + int32 blkidx, ptridx, i; + gnode_t *gn; + + blkidx = (id >> BLKID_SHIFT) & BLKID_MASK; + ptridx = id & BLKID_MASK; + + i = 0; + blkidx = list->n_blocks - blkidx; + for (gn = list->blocks; gn; gn = gnode_next(gn)) { + if (++i == blkidx) + break; + } + if (gn == NULL) { + E_ERROR("Failed to find block index %d\n", blkidx); + return NULL; + } + + return (void *)((char **)gnode_ptr(gn) + + ptridx * (list->elemsize / sizeof(void *))); +} + +void +__listelem_free__(listelem_alloc_t *list, void *elem, + char *caller_file, int caller_line) +{ + char **cpp; + + /* + * Insert freed item at head of list. + */ + cpp = (char **) elem; + *cpp = (char *) list->freelist; + list->freelist = cpp; + (list->n_freed)++; +} + + +void +listelem_stats(listelem_alloc_t *list) +{ + gnode_t *gn, *gn2; + char **cpp; + size_t n; + + E_INFO("Linklist stats:\n"); + for (n = 0, cpp = list->freelist; cpp; + cpp = (char **) (*cpp), n++); + E_INFO + ("elemsize %lu, #alloc %lu, #freed %lu, #freelist %lu\n", + (unsigned long)list->elemsize, + (unsigned long)list->n_alloc, + (unsigned long)list->n_freed, + (unsigned long)n); + E_INFO("Allocated blocks:\n"); + gn2 = list->blocksize; + for (gn = list->blocks; gn; gn = gnode_next(gn)) { + E_INFO("%p (%d * %d bytes)\n", gnode_ptr(gn), gnode_int32(gn2), list->elemsize); + gn2 = gnode_next(gn2); + } +} diff --git a/media/sphinxbase/src/libsphinxbase/util/logmath.c b/media/sphinxbase/src/libsphinxbase/util/logmath.c new file mode 100644 index 000000000..8702e0ed6 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/logmath.c @@ -0,0 +1,483 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2007 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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 <math.h> +#include <string.h> +#include <assert.h> + +#include "sphinxbase/logmath.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/mmio.h" +#include "sphinxbase/bio.h" +#include "sphinxbase/strfuncs.h" + +struct logmath_s { + logadd_t t; + int refcount; + mmio_file_t *filemap; + float64 base; + float64 log_of_base; + float64 log10_of_base; + float64 inv_log_of_base; + float64 inv_log10_of_base; + int32 zero; +}; + +logmath_t * +logmath_init(float64 base, int shift, int use_table) +{ + logmath_t *lmath; + uint32 maxyx, i; + float64 byx; + int width; + + /* Check that the base is correct. */ + if (base <= 1.0) { + E_ERROR("Base must be greater than 1.0\n"); + return NULL; + } + + /* Set up various necessary constants. */ + lmath = ckd_calloc(1, sizeof(*lmath)); + lmath->refcount = 1; + lmath->base = base; + lmath->log_of_base = log(base); + lmath->log10_of_base = log10(base); + lmath->inv_log_of_base = 1.0/lmath->log_of_base; + lmath->inv_log10_of_base = 1.0/lmath->log10_of_base; + lmath->t.shift = shift; + /* Shift this sufficiently that overflows can be avoided. */ + lmath->zero = MAX_NEG_INT32 >> (shift + 2); + + if (!use_table) + return lmath; + + /* Create a logadd table with the appropriate width */ + maxyx = (uint32) (log(2.0) / log(base) + 0.5) >> shift; + /* Poor man's log2 */ + if (maxyx < 256) width = 1; + else if (maxyx < 65536) width = 2; + else width = 4; + + lmath->t.width = width; + /* Figure out size of add table required. */ + byx = 1.0; /* Maximum possible base^{y-x} value - note that this implies that y-x == 0 */ + for (i = 0;; ++i) { + float64 lobyx = log(1.0 + byx) * lmath->inv_log_of_base; /* log_{base}(1 + base^{y-x}); */ + int32 k = (int32) (lobyx + 0.5 * (1<<shift)) >> shift; /* Round to shift */ + + /* base^{y-x} has reached the smallest representable value. */ + if (k <= 0) + break; + + /* This table is indexed by -(y-x), so we multiply byx by + * base^{-1} here which is equivalent to subtracting one from + * (y-x). */ + byx /= base; + } + i >>= shift; + + /* Never produce a table smaller than 256 entries. */ + if (i < 255) i = 255; + + lmath->t.table = ckd_calloc(i+1, width); + lmath->t.table_size = i + 1; + /* Create the add table (see above). */ + byx = 1.0; + for (i = 0;; ++i) { + float64 lobyx = log(1.0 + byx) * lmath->inv_log_of_base; + int32 k = (int32) (lobyx + 0.5 * (1<<shift)) >> shift; /* Round to shift */ + uint32 prev = 0; + + /* Check any previous value - if there is a shift, we want to + * only store the highest one. */ + switch (width) { + case 1: + prev = ((uint8 *)lmath->t.table)[i >> shift]; + break; + case 2: + prev = ((uint16 *)lmath->t.table)[i >> shift]; + break; + case 4: + prev = ((uint32 *)lmath->t.table)[i >> shift]; + break; + } + if (prev == 0) { + switch (width) { + case 1: + ((uint8 *)lmath->t.table)[i >> shift] = (uint8) k; + break; + case 2: + ((uint16 *)lmath->t.table)[i >> shift] = (uint16) k; + break; + case 4: + ((uint32 *)lmath->t.table)[i >> shift] = (uint32) k; + break; + } + } + if (k <= 0) + break; + + /* Decay base^{y-x} exponentially according to base. */ + byx /= base; + } + + return lmath; +} + +logmath_t * +logmath_read(const char *file_name) +{ + logmath_t *lmath; + char **argname, **argval; + int32 byteswap, i; + int chksum_present, do_mmap; + uint32 chksum; + long pos; + FILE *fp; + + E_INFO("Reading log table file '%s'\n", file_name); + if ((fp = fopen(file_name, "rb")) == NULL) { + E_ERROR_SYSTEM("Failed to open log table file '%s' for reading", file_name); + return NULL; + } + + /* Read header, including argument-value info and 32-bit byteorder magic */ + if (bio_readhdr(fp, &argname, &argval, &byteswap) < 0) { + E_ERROR("Failed to read the header from the file '%s'\n", file_name); + fclose(fp); + return NULL; + } + + lmath = ckd_calloc(1, sizeof(*lmath)); + /* Default values. */ + lmath->t.shift = 0; + lmath->t.width = 2; + lmath->base = 1.0001; + + /* Parse argument-value list */ + chksum_present = 0; + for (i = 0; argname[i]; i++) { + if (strcmp(argname[i], "version") == 0) { + } + else if (strcmp(argname[i], "chksum0") == 0) { + if (strcmp(argval[i], "yes") == 0) + chksum_present = 1; + } + else if (strcmp(argname[i], "width") == 0) { + lmath->t.width = atoi(argval[i]); + } + else if (strcmp(argname[i], "shift") == 0) { + lmath->t.shift = atoi(argval[i]); + } + else if (strcmp(argname[i], "logbase") == 0) { + lmath->base = atof_c(argval[i]); + } + } + bio_hdrarg_free(argname, argval); + chksum = 0; + + /* Set up various necessary constants. */ + lmath->log_of_base = log(lmath->base); + lmath->log10_of_base = log10(lmath->base); + lmath->inv_log_of_base = 1.0/lmath->log_of_base; + lmath->inv_log10_of_base = 1.0/lmath->log10_of_base; + /* Shift this sufficiently that overflows can be avoided. */ + lmath->zero = MAX_NEG_INT32 >> (lmath->t.shift + 2); + + /* #Values to follow */ + if (bio_fread(&lmath->t.table_size, sizeof(int32), 1, fp, byteswap, &chksum) != 1) { + E_ERROR("Failed to read values from the file '%s'", file_name); + goto error_out; + } + + /* Check alignment constraints for memory mapping */ + do_mmap = 1; + pos = ftell(fp); + if (pos & ((long)lmath->t.width - 1)) { + E_WARN("%s: Data start %ld is not aligned on %d-byte boundary, will not memory map\n", + file_name, pos, lmath->t.width); + do_mmap = 0; + } + /* Check byte order for memory mapping */ + if (byteswap) { + E_WARN("%s: Data is wrong-endian, will not memory map\n", file_name); + do_mmap = 0; + } + + if (do_mmap) { + lmath->filemap = mmio_file_read(file_name); + lmath->t.table = (char *)mmio_file_ptr(lmath->filemap) + pos; + } + else { + lmath->t.table = ckd_calloc(lmath->t.table_size, lmath->t.width); + if (bio_fread(lmath->t.table, lmath->t.width, lmath->t.table_size, + fp, byteswap, &chksum) != lmath->t.table_size) { + E_ERROR("Failed to read data (%d x %d bytes) from the file '%s' failed", + lmath->t.table_size, lmath->t.width, file_name); + goto error_out; + } + if (chksum_present) + bio_verify_chksum(fp, byteswap, chksum); + + if (fread(&i, 1, 1, fp) == 1) { + E_ERROR("%s: More data than expected\n", file_name); + goto error_out; + } + } + fclose(fp); + + return lmath; +error_out: + logmath_free(lmath); + return NULL; +} + +int32 +logmath_write(logmath_t *lmath, const char *file_name) +{ + FILE *fp; + long pos; + uint32 chksum; + + if (lmath->t.table == NULL) { + E_ERROR("No log table to write!\n"); + return -1; + } + + E_INFO("Writing log table file '%s'\n", file_name); + if ((fp = fopen(file_name, "wb")) == NULL) { + E_ERROR_SYSTEM("Failed to open logtable file '%s' for writing", file_name); + return -1; + } + + /* For whatever reason, we have to do this manually at the + * moment. */ + fprintf(fp, "s3\nversion 1.0\nchksum0 yes\n"); + fprintf(fp, "width %d\n", lmath->t.width); + fprintf(fp, "shift %d\n", lmath->t.shift); + fprintf(fp, "logbase %f\n", lmath->base); + /* Pad it out to ensure alignment. */ + pos = ftell(fp) + strlen("endhdr\n"); + if (pos & ((long)lmath->t.width - 1)) { + size_t align = lmath->t.width - (pos & ((long)lmath->t.width - 1)); + assert(lmath->t.width <= 8); + fwrite(" " /* 8 spaces */, 1, align, fp); + } + fprintf(fp, "endhdr\n"); + + /* Now write the binary data. */ + chksum = (uint32)BYTE_ORDER_MAGIC; + fwrite(&chksum, sizeof(uint32), 1, fp); + chksum = 0; + /* #Values to follow */ + if (bio_fwrite(&lmath->t.table_size, sizeof(uint32), + 1, fp, 0, &chksum) != 1) { + E_ERROR("Failed to write data to a file '%s'", file_name); + goto error_out; + } + + if (bio_fwrite(lmath->t.table, lmath->t.width, lmath->t.table_size, + fp, 0, &chksum) != lmath->t.table_size) { + E_ERROR("Failed to write data (%d x %d bytes) to the file '%s'", + lmath->t.table_size, lmath->t.width, file_name); + goto error_out; + } + if (bio_fwrite(&chksum, sizeof(uint32), 1, fp, 0, NULL) != 1) { + E_ERROR("Failed to write checksum to the file '%s'", file_name); + goto error_out; + } + + fclose(fp); + return 0; + +error_out: + fclose(fp); + return -1; +} + +logmath_t * +logmath_retain(logmath_t *lmath) +{ + ++lmath->refcount; + return lmath; +} + +int +logmath_free(logmath_t *lmath) +{ + if (lmath == NULL) + return 0; + if (--lmath->refcount > 0) + return lmath->refcount; + if (lmath->filemap) + mmio_file_unmap(lmath->filemap); + else + ckd_free(lmath->t.table); + ckd_free(lmath); + return 0; +} + +int32 +logmath_get_table_shape(logmath_t *lmath, uint32 *out_size, + uint32 *out_width, uint32 *out_shift) +{ + if (out_size) *out_size = lmath->t.table_size; + if (out_width) *out_width = lmath->t.width; + if (out_shift) *out_shift = lmath->t.shift; + + return lmath->t.table_size * lmath->t.width; +} + +float64 +logmath_get_base(logmath_t *lmath) +{ + return lmath->base; +} + +int +logmath_get_zero(logmath_t *lmath) +{ + return lmath->zero; +} + +int +logmath_get_width(logmath_t *lmath) +{ + return lmath->t.width; +} + +int +logmath_get_shift(logmath_t *lmath) +{ + return lmath->t.shift; +} + +int +logmath_add(logmath_t *lmath, int logb_x, int logb_y) +{ + logadd_t *t = LOGMATH_TABLE(lmath); + int d, r; + + /* handle 0 + x = x case. */ + if (logb_x <= lmath->zero) + return logb_y; + if (logb_y <= lmath->zero) + return logb_x; + + if (t->table == NULL) + return logmath_add_exact(lmath, logb_x, logb_y); + + /* d must be positive, obviously. */ + if (logb_x > logb_y) { + d = (logb_x - logb_y); + r = logb_x; + } + else { + d = (logb_y - logb_x); + r = logb_y; + } + + if (d < 0) { + /* Some kind of overflow has occurred, fail gracefully. */ + return r; + } + if ((size_t)d >= t->table_size) { + /* If this happens, it's not actually an error, because the + * last entry in the logadd table is guaranteed to be zero. + * Therefore we just return the larger of the two values. */ + return r; + } + + switch (t->width) { + case 1: + return r + (((uint8 *)t->table)[d]); + case 2: + return r + (((uint16 *)t->table)[d]); + case 4: + return r + (((uint32 *)t->table)[d]); + } + return r; +} + +int +logmath_add_exact(logmath_t *lmath, int logb_p, int logb_q) +{ + return logmath_log(lmath, + logmath_exp(lmath, logb_p) + + logmath_exp(lmath, logb_q)); +} + +int +logmath_log(logmath_t *lmath, float64 p) +{ + if (p <= 0) { + return lmath->zero; + } + return (int)(log(p) * lmath->inv_log_of_base) >> lmath->t.shift; +} + +float64 +logmath_exp(logmath_t *lmath, int logb_p) +{ + return pow(lmath->base, (float64)(logb_p << lmath->t.shift)); +} + +int +logmath_ln_to_log(logmath_t *lmath, float64 log_p) +{ + return (int)(log_p * lmath->inv_log_of_base) >> lmath->t.shift; +} + +float64 +logmath_log_to_ln(logmath_t *lmath, int logb_p) +{ + return (float64)(logb_p << lmath->t.shift) * lmath->log_of_base; +} + +int +logmath_log10_to_log(logmath_t *lmath, float64 log_p) +{ + return (int)(log_p * lmath->inv_log10_of_base) >> lmath->t.shift; +} + +float64 +logmath_log_to_log10(logmath_t *lmath, int logb_p) +{ + return (float64)(logb_p << lmath->t.shift) * lmath->log10_of_base; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/matrix.c b/media/sphinxbase/src/libsphinxbase/util/matrix.c new file mode 100644 index 000000000..27ba08f68 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/matrix.c @@ -0,0 +1,313 @@ +/* -*- c-basic-offset: 4 -*- */ +/* ==================================================================== + * Copyright (c) 1997-2006 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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 <string.h> +#include <stdlib.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sphinxbase/clapack_lite.h" +#include "sphinxbase/matrix.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" + +void +norm_3d(float32 ***arr, + uint32 d1, + uint32 d2, + uint32 d3) +{ + uint32 i, j, k; + float64 s; + + for (i = 0; i < d1; i++) { + for (j = 0; j < d2; j++) { + + /* compute sum (i, j) as over all k */ + for (k = 0, s = 0; k < d3; k++) { + s += arr[i][j][k]; + } + + /* do 1 floating point divide */ + s = 1.0 / s; + + /* divide all k by sum over k */ + for (k = 0; k < d3; k++) { + arr[i][j][k] *= s; + } + } + } +} + +void +accum_3d(float32 ***out, + float32 ***in, + uint32 d1, + uint32 d2, + uint32 d3) +{ + uint32 i, j, k; + + for (i = 0; i < d1; i++) { + for (j = 0; j < d2; j++) { + for (k = 0; k < d3; k++) { + out[i][j][k] += in[i][j][k]; + } + } + } +} + +void +floor_nz_3d(float32 ***m, + uint32 d1, + uint32 d2, + uint32 d3, + float32 floor) +{ + uint32 i, j, k; + + for (i = 0; i < d1; i++) { + for (j = 0; j < d2; j++) { + for (k = 0; k < d3; k++) { + if ((m[i][j][k] != 0) && (m[i][j][k] < floor)) + m[i][j][k] = floor; + } + } + } +} +void +floor_nz_1d(float32 *v, + uint32 d1, + float32 floor) +{ + uint32 i; + + for (i = 0; i < d1; i++) { + if ((v[i] != 0) && (v[i] < floor)) + v[i] = floor; + } +} + +void +band_nz_1d(float32 *v, + uint32 d1, + float32 band) +{ + uint32 i; + + for (i = 0; i < d1; i++) { + if (v[i] != 0) { + if ((v[i] > 0) && (v[i] < band)) { + v[i] = band; + } + else if ((v[i] < 0) && (v[i] > -band)) { + v[i] = -band; + } + } + } +} + +#ifndef WITH_LAPACK +float64 +determinant(float32 **a, int32 n) +{ + E_FATAL("No LAPACK library available, cannot compute determinant (FIXME)\n"); + return 0.0; +} +int32 +invert(float32 **ainv, float32 **a, int32 n) +{ + E_FATAL("No LAPACK library available, cannot compute matrix inverse (FIXME)\n"); + return 0; +} +int32 +solve(float32 **a, float32 *b, float32 *out_x, int32 n) +{ + E_FATAL("No LAPACK library available, cannot solve linear equations (FIXME)\n"); + return 0; +} + +void +matrixmultiply(float32 ** c, float32 ** a, float32 ** b, int32 n) +{ + int32 i, j, k; + + memset(c[0], 0, n*n*sizeof(float32)); + for (i = 0; i < n; ++i) { + for (j = 0; j < n; ++j) { + for (k = 0; k < n; ++k) { + c[i][k] += a[i][j] * b[j][k]; + } + } + } +} +#else /* WITH_LAPACK */ +/* Find determinant through LU decomposition. */ +float64 +determinant(float32 ** a, int32 n) +{ + float32 **tmp_a; + float64 det; + char uplo; + int32 info, i; + + /* a is assumed to be symmetric, so we don't need to switch the + * ordering of the data. But we do need to copy it since it is + * overwritten by LAPACK. */ + tmp_a = (float32 **)ckd_calloc_2d(n, n, sizeof(float32)); + memcpy(tmp_a[0], a[0], n*n*sizeof(float32)); + + uplo = 'L'; + spotrf_(&uplo, &n, tmp_a[0], &n, &info); + det = tmp_a[0][0]; + /* det = prod(diag(l))^2 */ + for (i = 1; i < n; ++i) + det *= tmp_a[i][i]; + ckd_free_2d((void **)tmp_a); + if (info > 0) + return -1.0; /* Generic "not positive-definite" answer */ + else + return det * det; +} + +int32 +solve(float32 **a, /*Input : an n*n matrix A */ + float32 *b, /*Input : a n dimesion vector b */ + float32 *out_x, /*Output : a n dimesion vector x */ + int32 n) +{ + char uplo; + float32 **tmp_a; + int32 info, nrhs; + + /* a is assumed to be symmetric, so we don't need to switch the + * ordering of the data. But we do need to copy it since it is + * overwritten by LAPACK. */ + tmp_a = (float32 **)ckd_calloc_2d(n, n, sizeof(float32)); + memcpy(tmp_a[0], a[0], n*n*sizeof(float32)); + memcpy(out_x, b, n*sizeof(float32)); + uplo = 'L'; + nrhs = 1; + sposv_(&uplo, &n, &nrhs, tmp_a[0], &n, out_x, &n, &info); + ckd_free_2d((void **)tmp_a); + + if (info != 0) + return -1; + else + return info; +} + +/* Find inverse by solving AX=I. */ +int32 +invert(float32 ** ainv, float32 ** a, int32 n) +{ + char uplo; + float32 **tmp_a; + int32 info, nrhs, i; + + /* Construct an identity matrix. */ + memset(ainv[0], 0, sizeof(float32) * n * n); + for (i = 0; i < n; i++) + ainv[i][i] = 1.0; + /* a is assumed to be symmetric, so we don't need to switch the + * ordering of the data. But we do need to copy it since it is + * overwritten by LAPACK. */ + tmp_a = (float32 **)ckd_calloc_2d(n, n, sizeof(float32)); + memcpy(tmp_a[0], a[0], n*n*sizeof(float32)); + uplo = 'L'; + nrhs = n; + sposv_(&uplo, &n, &nrhs, tmp_a[0], &n, ainv[0], &n, &info); + ckd_free_2d((void **)tmp_a); + + if (info != 0) + return -1; + else + return info; +} + +void +matrixmultiply(float32 ** c, float32 ** a, float32 ** b, int32 n) +{ + char side, uplo; + float32 alpha; + + side = 'L'; + uplo = 'L'; + alpha = 1.0; + ssymm_(&side, &uplo, &n, &n, &alpha, a[0], &n, b[0], &n, &alpha, c[0], &n); +} + +#endif /* WITH_LAPACK */ + +void +outerproduct(float32 ** a, float32 * x, float32 * y, int32 len) +{ + int32 i, j; + + for (i = 0; i < len; ++i) { + a[i][i] = x[i] * y[i]; + for (j = i + 1; j < len; ++j) { + a[i][j] = x[i] * y[j]; + a[j][i] = x[j] * y[i]; + } + } +} + +void +scalarmultiply(float32 ** a, float32 x, int32 n) +{ + int32 i, j; + + for (i = 0; i < n; ++i) { + a[i][i] *= x; + for (j = i+1; j < n; ++j) { + a[i][j] *= x; + a[j][i] *= x; + } + } +} + +void +matrixadd(float32 ** a, float32 ** b, int32 n) +{ + int32 i, j; + + for (i = 0; i < n; ++i) + for (j = 0; j < n; ++j) + a[i][j] += b[i][j]; +} diff --git a/media/sphinxbase/src/libsphinxbase/util/mmio.c b/media/sphinxbase/src/libsphinxbase/util/mmio.c new file mode 100644 index 000000000..0b2315b71 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/mmio.c @@ -0,0 +1,257 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 2005 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/********************************************************************* + * + * File: mmio.c + * + * Description: mmap() wrappers for Unix/Windows + * + * Author: David Huggins-Daines <dhuggins@cs.cmu.edu> + * + *********************************************************************/ + +#include <string.h> +#include <stdlib.h> + + +#ifdef GNUWINCE +# include <sys/wcebase.h> +# include <sys/wcetypes.h> +# include <sys/wcememory.h> +# include <sys/wcefile.h> +#elif defined(__SYMBIAN32__) /* SYMBIAN32 must be before WIN32 since Symbian SDK defines WIN32 as well */ +# include <unistd.h> +# include <fcntl.h> +# include <sys/stat.h> +# include <sys/mman.h> +#elif defined(_WIN32) +# include <windows.h> +#else +# include <unistd.h> +# include <fcntl.h> +# include <sys/stat.h> +# include <sys/file.h> +# include <sys/mman.h> +#endif + +#include "sphinxbase/prim_type.h" +#include "sphinxbase/err.h" +#include "sphinxbase/mmio.h" +#include "sphinxbase/ckd_alloc.h" + +#if defined(_WIN32_WCE) || defined(GNUWINCE) +struct mmio_file_s { + int dummy; +}; + +mmio_file_t * +mmio_file_read(const char *filename) +{ + HANDLE ffm, fd; + WCHAR *wfilename; + void *rv; + int len; + + len = mbstowcs(NULL, filename, 0) + 1; + wfilename = malloc(len * sizeof(WCHAR)); + mbstowcs(wfilename, filename, len); + + if ((ffm = + CreateFileForMappingW(wfilename, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + E_ERROR("Failed to create mapping for the file '%s': %08x\n", filename, + GetLastError()); + return NULL; + } + if ((fd = + CreateFileMappingW(ffm, NULL, PAGE_READONLY, 0, 0, NULL)) == NULL) { + E_ERROR("Failed to CreateFileMapping: %08x\n", GetLastError()); + CloseHandle(ffm); + return NULL; + } + rv = MapViewOfFile(fd, FILE_MAP_READ, 0, 0, 0); + free(wfilename); + CloseHandle(ffm); + CloseHandle(fd); + + return (mmio_file_t *) rv; +} + +void +mmio_file_unmap(mmio_file_t *mf) +{ + if (!UnmapViewOfFile((void *)mf)) { + E_ERROR("Failed to UnmapViewOfFile: %08x\n", GetLastError()); + } +} + +void * +mmio_file_ptr(mmio_file_t *mf) +{ + return (void *)mf; +} + +#elif defined(_WIN32) && !defined(_WIN32_WP) /* !WINCE */ +struct mmio_file_s { + int dummy; +}; + +mmio_file_t * +mmio_file_read(const char *filename) +{ + HANDLE ffm, fd; + void *rv; + + if ((ffm = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + E_ERROR("Failed to create file '%s': %08x\n", + filename, GetLastError()); + return NULL; + } + if ((fd = CreateFileMapping(ffm, NULL, + PAGE_READONLY, 0, 0, NULL)) == NULL) { + E_ERROR("Failed to CreateFileMapping: %08x\n", GetLastError()); + CloseHandle(ffm); + } + rv = MapViewOfFile(fd, FILE_MAP_READ, 0, 0, 0); + CloseHandle(ffm); + CloseHandle(fd); + + return (mmio_file_t *)rv; +} + +void +mmio_file_unmap(mmio_file_t *mf) +{ + if (!UnmapViewOfFile((void *)mf)) { + E_ERROR("Failed to UnmapViewOfFile: %08x\n", GetLastError()); + } +} + +void * +mmio_file_ptr(mmio_file_t *mf) +{ + return (void *)mf; +} + +#else /* !WIN32, !WINCE */ +#if defined(__ADSPBLACKFIN__) || defined(_WIN32_WP) + /* This is true for both uClinux and VisualDSP++, + but actually we need a better way to detect it. */ +struct mmio_file_s { + int dummy; +}; + +mmio_file_t * +mmio_file_read(const char *filename) +{ + E_ERROR("mmio is not implemented on this platform!"); + return NULL; +} + +void +mmio_file_unmap(mmio_file_t *mf) +{ + E_ERROR("mmio is not implemented on this platform!"); +} + +void * +mmio_file_ptr(mmio_file_t *mf) +{ + E_ERROR("mmio is not implemented on this platform!"); + return NULL; +} +#else /* !__ADSPBLACKFIN__ */ +struct mmio_file_s { + void *ptr; + size_t mapsize; +}; + +mmio_file_t * +mmio_file_read(const char *filename) +{ + mmio_file_t *mf; + struct stat buf; + void *ptr; + int fd; + size_t pagesize; + + if ((fd = open(filename, O_RDONLY)) == -1) { + E_ERROR_SYSTEM("Failed to open %s", filename); + return NULL; + } + if (fstat(fd, &buf) == -1) { + E_ERROR_SYSTEM("Failed to stat %s", filename); + close(fd); + return NULL; + } + ptr = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (ptr == (void *)-1) { + E_ERROR_SYSTEM("Failed to mmap %lld bytes", (unsigned long long)buf.st_size); + close(fd); + return NULL; + } + close(fd); + mf = ckd_calloc(1, sizeof(*mf)); + mf->ptr = ptr; + /* Align map size to next page. */ + pagesize = sysconf(_SC_PAGESIZE); + mf->mapsize = (buf.st_size + pagesize - 1) / pagesize * pagesize; + + return mf; +} + +void +mmio_file_unmap(mmio_file_t *mf) +{ + if (mf == NULL) + return; + if (munmap(mf->ptr, mf->mapsize) < 0) { + E_ERROR_SYSTEM("Failed to unmap %ld bytes at %p", mf->mapsize, mf->ptr); + } + ckd_free(mf); +} + +void * +mmio_file_ptr(mmio_file_t *mf) +{ + return mf->ptr; +} +#endif /* !__ADSPBLACKFIN__ */ +#endif /* !(WINCE || WIN32) */ diff --git a/media/sphinxbase/src/libsphinxbase/util/pio.c b/media/sphinxbase/src/libsphinxbase/util/pio.c new file mode 100644 index 000000000..4c520bebe --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/pio.c @@ -0,0 +1,655 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2004 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#if defined(_WIN32) && !defined(CYGWIN) +#include <direct.h> +#endif + +#include "sphinxbase/pio.h" +#include "sphinxbase/filename.h" +#include "sphinxbase/err.h" +#include "sphinxbase/strfuncs.h" +#include "sphinxbase/ckd_alloc.h" + +#ifndef EXEEXT +#define EXEEXT "" +#endif + +enum { + COMP_NONE, + COMP_COMPRESS, + COMP_GZIP, + COMP_BZIP2 +}; + +static void +guess_comptype(char const *file, int32 *ispipe, int32 *isgz) +{ + size_t k; + + k = strlen(file); + *ispipe = 0; + *isgz = COMP_NONE; + if ((k > 2) + && ((strcmp(file + k - 2, ".Z") == 0) + || (strcmp(file + k - 2, ".z") == 0))) { + *ispipe = 1; + *isgz = COMP_COMPRESS; + } + else if ((k > 3) && ((strcmp(file + k - 3, ".gz") == 0) + || (strcmp(file + k - 3, ".GZ") == 0))) { + *ispipe = 1; + *isgz = COMP_GZIP; + } + else if ((k > 4) && ((strcmp(file + k - 4, ".bz2") == 0) + || (strcmp(file + k - 4, ".BZ2") == 0))) { + *ispipe = 1; + *isgz = COMP_BZIP2; + } +} + +FILE * +fopen_comp(const char *file, const char *mode, int32 * ispipe) +{ + FILE *fp; + +#ifndef HAVE_POPEN + *ispipe = 0; /* No popen() on WinCE */ +#else /* HAVE_POPEN */ + int32 isgz; + guess_comptype(file, ispipe, &isgz); +#endif /* HAVE_POPEN */ + + if (*ispipe) { +#ifndef HAVE_POPEN + /* Shouldn't get here, anyway */ + E_FATAL("No popen() on WinCE\n"); +#else + if (strcmp(mode, "r") == 0) { + char *command; + switch (isgz) { + case COMP_GZIP: + command = string_join("gunzip" EXEEXT, " -c ", file, NULL); + break; + case COMP_COMPRESS: + command = string_join("zcat" EXEEXT, " ", file, NULL); + break; + case COMP_BZIP2: + command = string_join("bunzip2" EXEEXT, " -c ", file, NULL); + break; + default: + command = NULL; /* Make compiler happy. */ + E_FATAL("Unknown compression type %d\n", isgz); + } + if ((fp = popen(command, mode)) == NULL) { + E_ERROR_SYSTEM("Failed to open a pipe for a command '%s' mode '%s'", command, mode); + ckd_free(command); + return NULL; + } + ckd_free(command); + } + else if (strcmp(mode, "w") == 0) { + char *command; + switch (isgz) { + case COMP_GZIP: + command = string_join("gzip" EXEEXT, " > ", file, NULL); + break; + case COMP_COMPRESS: + command = string_join("compress" EXEEXT, " -c > ", file, NULL); + break; + case COMP_BZIP2: + command = string_join("bzip2" EXEEXT, " > ", file, NULL); + break; + default: + command = NULL; /* Make compiler happy. */ + E_FATAL("Unknown compression type %d\n", isgz); + } + if ((fp = popen(command, mode)) == NULL) { + E_ERROR_SYSTEM("Failed to open a pipe for a command '%s' mode '%s'", command, mode); + ckd_free(command); + return NULL; + } + ckd_free(command); + } + else { + E_ERROR("Compressed file operation for mode %s is not supported", mode); + return NULL; + } +#endif /* HAVE_POPEN */ + } + else { + fp = fopen(file, mode); + } + + return (fp); +} + + +void +fclose_comp(FILE * fp, int32 ispipe) +{ + if (ispipe) { +#ifdef HAVE_POPEN +#if defined(_WIN32) && (!defined(__SYMBIAN32__)) + _pclose(fp); +#else + pclose(fp); +#endif +#endif + } + else + fclose(fp); +} + + +FILE * +fopen_compchk(const char *file, int32 * ispipe) +{ +#ifndef HAVE_POPEN + *ispipe = 0; /* No popen() on WinCE */ + /* And therefore the rest of this function is useless. */ + return (fopen_comp(file, "r", ispipe)); +#else /* HAVE_POPEN */ + int32 isgz; + FILE *fh; + + /* First just try to fopen_comp() it */ + if ((fh = fopen_comp(file, "r", ispipe)) != NULL) + return fh; + else { + char *tmpfile; + size_t k; + + /* File doesn't exist; try other compressed/uncompressed form, as appropriate */ + guess_comptype(file, ispipe, &isgz); + k = strlen(file); + tmpfile = ckd_calloc(k+5, 1); + strcpy(tmpfile, file); + switch (isgz) { + case COMP_GZIP: + tmpfile[k - 3] = '\0'; + break; + case COMP_BZIP2: + tmpfile[k - 4] = '\0'; + break; + case COMP_COMPRESS: + tmpfile[k - 2] = '\0'; + break; + case COMP_NONE: + strcpy(tmpfile + k, ".gz"); + if ((fh = fopen_comp(tmpfile, "r", ispipe)) != NULL) { + E_WARN("Using %s instead of %s\n", tmpfile, file); + ckd_free(tmpfile); + return fh; + } + strcpy(tmpfile + k, ".bz2"); + if ((fh = fopen_comp(tmpfile, "r", ispipe)) != NULL) { + E_WARN("Using %s instead of %s\n", tmpfile, file); + ckd_free(tmpfile); + return fh; + } + strcpy(tmpfile + k, ".Z"); + if ((fh = fopen_comp(tmpfile, "r", ispipe)) != NULL) { + E_WARN("Using %s instead of %s\n", tmpfile, file); + ckd_free(tmpfile); + return fh; + } + ckd_free(tmpfile); + return NULL; + } + E_WARN("Using %s instead of %s\n", tmpfile, file); + fh = fopen_comp(tmpfile, "r", ispipe); + ckd_free(tmpfile); + return NULL; + } +#endif /* HAVE_POPEN */ +} + +lineiter_t * +lineiter_start(FILE *fh) +{ + lineiter_t *li; + + li = (lineiter_t *)ckd_calloc(1, sizeof(*li)); + li->buf = (char *)ckd_malloc(128); + li->buf[0] = '\0'; + li->bsiz = 128; + li->len = 0; + li->fh = fh; + + li = lineiter_next(li); + + /* Strip the UTF-8 BOM */ + + if (li && 0 == strncmp(li->buf, "\xef\xbb\xbf", 3)) { + memmove(li->buf, li->buf + 3, strlen(li->buf + 1)); + li->len -= 3; + } + + return li; +} + +lineiter_t * +lineiter_start_clean(FILE *fh) +{ + lineiter_t *li; + + li = lineiter_start(fh); + + if (li == NULL) + return li; + + li->clean = TRUE; + + if (li->buf && li->buf[0] == '#') { + li = lineiter_next(li); + } else { + string_trim(li->buf, STRING_BOTH); + } + + return li; +} + + +static lineiter_t * +lineiter_next_plain(lineiter_t *li) +{ + /* We are reading the next line */ + li->lineno++; + + /* Read a line and check for EOF. */ + if (fgets(li->buf, li->bsiz, li->fh) == NULL) { + lineiter_free(li); + return NULL; + } + /* If we managed to read the whole thing, then we are done + * (this will be by far the most common result). */ + li->len = (int32)strlen(li->buf); + if (li->len < li->bsiz - 1 || li->buf[li->len - 1] == '\n') + return li; + + /* Otherwise we have to reallocate and keep going. */ + while (1) { + li->bsiz *= 2; + li->buf = (char *)ckd_realloc(li->buf, li->bsiz); + /* If we get an EOF, we are obviously done. */ + if (fgets(li->buf + li->len, li->bsiz - li->len, li->fh) == NULL) { + li->len += strlen(li->buf + li->len); + return li; + } + li->len += strlen(li->buf + li->len); + /* If we managed to read the whole thing, then we are done. */ + if (li->len < li->bsiz - 1 || li->buf[li->len - 1] == '\n') + return li; + } + + /* Shouldn't get here. */ + return li; +} + + +lineiter_t * +lineiter_next(lineiter_t *li) +{ + if (!li->clean) + return lineiter_next_plain(li); + + for (li = lineiter_next_plain(li); li; li = lineiter_next_plain(li)) { + if (li->buf && li->buf[0] != '#') { + li->buf = string_trim(li->buf, STRING_BOTH); + break; + } + } + return li; +} + +int lineiter_lineno(lineiter_t *li) +{ + return li->lineno; +} + +void +lineiter_free(lineiter_t *li) +{ + if (li == NULL) + return; + ckd_free(li->buf); + ckd_free(li); +} + +char * +fread_line(FILE *stream, size_t *out_len) +{ + char *output, *outptr; + char buf[128]; + + output = outptr = NULL; + while (fgets(buf, sizeof(buf), stream)) { + size_t len = strlen(buf); + /* Append this data to the buffer. */ + if (output == NULL) { + output = (char *)ckd_malloc(len + 1); + outptr = output; + } + else { + size_t cur = outptr - output; + output = (char *)ckd_realloc(output, cur + len + 1); + outptr = output + cur; + } + memcpy(outptr, buf, len + 1); + outptr += len; + /* Stop on a short read or end of line. */ + if (len < sizeof(buf)-1 || buf[len-1] == '\n') + break; + } + if (out_len) *out_len = outptr - output; + return output; +} + +#define FREAD_RETRY_COUNT 60 + +int32 +fread_retry(void *pointer, int32 size, int32 num_items, FILE * stream) +{ + char *data; + size_t n_items_read; + size_t n_items_rem; + uint32 n_retry_rem; + int32 loc; + + n_retry_rem = FREAD_RETRY_COUNT; + + data = (char *)pointer; + loc = 0; + n_items_rem = num_items; + + do { + n_items_read = fread(&data[loc], size, n_items_rem, stream); + + n_items_rem -= n_items_read; + + if (n_items_rem > 0) { + /* an incomplete read occurred */ + + if (n_retry_rem == 0) + return -1; + + if (n_retry_rem == FREAD_RETRY_COUNT) { + E_ERROR_SYSTEM("fread() failed; retrying...\n"); + } + + --n_retry_rem; + + loc += n_items_read * size; +#if !defined(_WIN32) && defined(HAVE_UNISTD_H) + sleep(1); +#endif + } + } while (n_items_rem > 0); + + return num_items; +} + + +#ifdef _WIN32_WCE /* No stat() on WinCE */ +int32 +stat_retry(const char *file, struct stat * statbuf) +{ + WIN32_FIND_DATAW file_data; + HANDLE *h; + wchar_t *wfile; + size_t len; + + len = mbstowcs(NULL, file, 0) + 1; + wfile = ckd_calloc(len, sizeof(*wfile)); + mbstowcs(wfile, file, len); + if ((h = FindFirstFileW(wfile, &file_data)) == INVALID_HANDLE_VALUE) { + ckd_free(wfile); + return -1; + } + ckd_free(wfile); + memset(statbuf, 0, sizeof(*statbuf)); + statbuf->st_mtime = file_data.ftLastWriteTime.dwLowDateTime; + statbuf->st_size = file_data.nFileSizeLow; + FindClose(h); + + return 0; +} + + +int32 +stat_mtime(const char *file) +{ + struct stat statbuf; + + if (stat_retry(file, &statbuf) != 0) + return -1; + + return ((int32) statbuf.st_mtime); +} +#else +#define STAT_RETRY_COUNT 10 +int32 +stat_retry(const char *file, struct stat * statbuf) +{ + int32 i; + + for (i = 0; i < STAT_RETRY_COUNT; i++) { +#ifndef HAVE_SYS_STAT_H + FILE *fp; + + if ((fp = (FILE *)fopen(file, "r")) != 0) { + fseek(fp, 0, SEEK_END); + statbuf->st_size = ftell(fp); + fclose(fp); + return 0; + } +#else /* HAVE_SYS_STAT_H */ + if (stat(file, statbuf) == 0) + return 0; +#endif + if (i == 0) { + E_ERROR_SYSTEM("Failed to stat file '%s'; retrying...", file); + } +#ifdef HAVE_UNISTD_H + sleep(1); +#endif + } + + return -1; +} + +int32 +stat_mtime(const char *file) +{ + struct stat statbuf; + +#ifdef HAVE_SYS_STAT_H + if (stat(file, &statbuf) != 0) + return -1; +#else /* HAVE_SYS_STAT_H */ + if (stat_retry(file, &statbuf) != 0) + return -1; +#endif /* HAVE_SYS_STAT_H */ + + return ((int32) statbuf.st_mtime); +} +#endif /* !_WIN32_WCE */ + +struct bit_encode_s { + FILE *fh; + unsigned char buf, bbits; + int16 refcount; +}; + +bit_encode_t * +bit_encode_attach(FILE *outfh) +{ + bit_encode_t *be; + + be = (bit_encode_t *)ckd_calloc(1, sizeof(*be)); + be->refcount = 1; + be->fh = outfh; + return be; +} + +bit_encode_t * +bit_encode_retain(bit_encode_t *be) +{ + ++be->refcount; + return be; +} + +int +bit_encode_free(bit_encode_t *be) +{ + if (be == NULL) + return 0; + if (--be->refcount > 0) + return be->refcount; + ckd_free(be); + + return 0; +} + +int +bit_encode_write(bit_encode_t *be, unsigned char const *bits, int nbits) +{ + int tbits; + + tbits = nbits + be->bbits; + if (tbits < 8) { + /* Append to buffer. */ + be->buf |= ((bits[0] >> (8 - nbits)) << (8 - tbits)); + } + else { + int i = 0; + while (tbits >= 8) { + /* Shift bits out of the buffer and splice with high-order bits */ + fputc(be->buf | ((bits[i]) >> be->bbits), be->fh); + /* Put low-order bits back into buffer */ + be->buf = (bits[i] << (8 - be->bbits)) & 0xff; + tbits -= 8; + ++i; + } + } + /* tbits contains remaining number of bits. */ + be->bbits = tbits; + + return nbits; +} + +int +bit_encode_write_cw(bit_encode_t *be, uint32 codeword, int nbits) +{ + unsigned char bits[4]; + codeword <<= (32 - nbits); + bits[0] = (codeword >> 24) & 0xff; + bits[1] = (codeword >> 16) & 0xff; + bits[2] = (codeword >> 8) & 0xff; + bits[3] = codeword & 0xff; + return bit_encode_write(be, bits, nbits); +} + +int +bit_encode_flush(bit_encode_t *be) +{ + if (be->bbits) { + fputc(be->buf, be->fh); + be->bbits = 0; + } + return 0; +} + +int +build_directory(const char *path) +{ + int rv; + + /* Utterly failed... */ + if (strlen(path) == 0) + return -1; + +#if defined(_WIN32) && !defined(CYGWIN) + else if ((rv = _mkdir(path)) == 0) + return 0; +#elif defined(HAVE_SYS_STAT_H) /* Unix, Cygwin, doesn't work on MINGW */ + else if ((rv = mkdir(path, 0777)) == 0) + return 0; +#endif + + /* Or, it already exists... */ + else if (errno == EEXIST) + return 0; + else if (errno != ENOENT) { + E_ERROR_SYSTEM("Failed to create %s", path); + return -1; + } + else { + char *dirname = ckd_salloc(path); + path2dirname(path, dirname); + build_directory(dirname); + ckd_free(dirname); + +#if defined(_WIN32) && !defined(CYGWIN) + return _mkdir(path); +#elif defined(HAVE_SYS_STAT_H) /* Unix, Cygwin, doesn't work on MINGW */ + return mkdir(path, 0777); +#endif + } +} diff --git a/media/sphinxbase/src/libsphinxbase/util/profile.c b/media/sphinxbase/src/libsphinxbase/util/profile.c new file mode 100644 index 000000000..c8d84ca98 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/profile.c @@ -0,0 +1,345 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2001 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * profile.c -- For timing and event counting. + * + * ********************************************** + * CMU ARPA Speech Project + * + * Copyright (c) 1999 Carnegie Mellon University. + * ALL RIGHTS RESERVED. + * ********************************************** + * + * HISTORY + * $Log: profile.c,v $ + * Revision 1.7 2005/06/22 03:10:59 arthchan2003 + * 1, Fixed doxygen documentation, 2, Added keyword. + * + * Revision 1.3 2005/03/30 01:22:48 archan + * Fixed mistakes in last updates. Add + * + * + * 11-Mar-1999 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Added ptmr_init(). + * + * 19-Jun-97 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University + * Created. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(_WIN32) && !defined(__SYMBIAN32__) +# include <windows.h> +# ifndef _WIN32_WCE +# include <time.h> +# endif +#elif defined(HAVE_UNISTD_H) /* I know this, this is Unix... */ +# include <unistd.h> +# include <sys/time.h> +# include <sys/resource.h> +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include "sphinxbase/profile.h" +#include "sphinxbase/err.h" +#include "sphinxbase/ckd_alloc.h" + +#if defined(_WIN32_WCE) || defined(_WIN32_WP) +DWORD unlink(const char *filename) +{ + WCHAR *wfilename; + DWORD rv; + size_t len; + + len = mbstowcs(NULL, filename, 0); + wfilename = ckd_calloc(len+1, sizeof(*wfilename)); + mbstowcs(wfilename, filename, len); + rv = DeleteFileW(wfilename); + ckd_free(wfilename); + + return rv; +} +#endif + +pctr_t * +pctr_new(char *nm) +{ + pctr_t *pc; + + pc = ckd_calloc(1, sizeof(pctr_t)); + pc->name = ckd_salloc(nm); + pc->count = 0; + + return pc; +} + +void +pctr_reset(pctr_t * ctr) +{ + ctr->count = 0; +} + + +void +pctr_increment(pctr_t * ctr, int32 inc) +{ + ctr->count += inc; + /* E_INFO("Name %s, Count %d, inc %d\n",ctr->name, ctr->count, inc); */ +} + +void +pctr_print(FILE * fp, pctr_t * ctr) +{ + fprintf(fp, "CTR:"); + fprintf(fp, "[%d %s]", ctr->count, ctr->name); +} + +void +pctr_free(pctr_t * pc) +{ + if (pc) { + if (pc->name) + ckd_free(pc->name); + } + ckd_free(pc); +} + + +#if defined(_WIN32) && !defined(GNUWINCE) && !defined(__SYMBIAN32__) + +#define TM_LOWSCALE 1e-7 +#define TM_HIGHSCALE (4294967296.0 * TM_LOWSCALE); + +static float64 +make_sec(FILETIME * tm) +{ + float64 dt; + + dt = tm->dwLowDateTime * TM_LOWSCALE; + dt += tm->dwHighDateTime * TM_HIGHSCALE; + + return (dt); +} + +#else /* NOT WINDOWS */ + +static float64 +make_sec(struct timeval *s) +{ + return (s->tv_sec + s->tv_usec * 0.000001); +} + +#endif + + +void +ptmr_start(ptmr_t * tm) +{ +#if (! defined(_WIN32)) || defined(GNUWINCE) || defined(__SYMBIAN32__) + struct timeval e_start; /* Elapsed time */ + +#if (! defined(_HPUX_SOURCE)) && (! defined(__SYMBIAN32__)) + struct rusage start; /* CPU time */ + + /* Unix but not HPUX */ + getrusage(RUSAGE_SELF, &start); + tm->start_cpu = make_sec(&start.ru_utime) + make_sec(&start.ru_stime); +#endif + /* Unix + HP */ + gettimeofday(&e_start, 0); + tm->start_elapsed = make_sec(&e_start); +#elif defined(_WIN32_WP) + tm->start_cpu = GetTickCount64() / 1000; + tm->start_elapsed = GetTickCount64() / 1000; +#elif defined(_WIN32_WCE) + /* No GetProcessTimes() on WinCE. (Note CPU time will be bogus) */ + tm->start_cpu = GetTickCount() / 1000; + tm->start_elapsed = GetTickCount() / 1000; +#else + HANDLE pid; + FILETIME t_create, t_exit, kst, ust; + + /* PC */ + pid = GetCurrentProcess(); + GetProcessTimes(pid, &t_create, &t_exit, &kst, &ust); + tm->start_cpu = make_sec(&ust) + make_sec(&kst); + + tm->start_elapsed = (float64) clock() / CLOCKS_PER_SEC; +#endif +} + + +void +ptmr_stop(ptmr_t * tm) +{ + float64 dt_cpu, dt_elapsed; + +#if (! defined(_WIN32)) || defined(GNUWINCE) || defined(__SYMBIAN32__) + struct timeval e_stop; /* Elapsed time */ + +#if (! defined(_HPUX_SOURCE)) && (! defined(__SYMBIAN32__)) + struct rusage stop; /* CPU time */ + + /* Unix but not HPUX */ + getrusage(RUSAGE_SELF, &stop); + dt_cpu = + make_sec(&stop.ru_utime) + make_sec(&stop.ru_stime) - + tm->start_cpu; +#else + dt_cpu = 0.0; +#endif + /* Unix + HP */ + gettimeofday(&e_stop, 0); + dt_elapsed = (make_sec(&e_stop) - tm->start_elapsed); +#elif defined(_WIN32_WP) + dt_cpu = GetTickCount64() / 1000 - tm->start_cpu; + dt_elapsed = GetTickCount64() / 1000 - tm->start_elapsed; +#elif defined(_WIN32_WCE) + /* No GetProcessTimes() on WinCE. (Note CPU time will be bogus) */ + dt_cpu = GetTickCount() / 1000 - tm->start_cpu; + dt_elapsed = GetTickCount() / 1000 - tm->start_elapsed; +#else + HANDLE pid; + FILETIME t_create, t_exit, kst, ust; + + /* PC */ + pid = GetCurrentProcess(); + GetProcessTimes(pid, &t_create, &t_exit, &kst, &ust); + dt_cpu = make_sec(&ust) + make_sec(&kst) - tm->start_cpu; + dt_elapsed = ((float64) clock() / CLOCKS_PER_SEC) - tm->start_elapsed; +#endif + + tm->t_cpu += dt_cpu; + tm->t_elapsed += dt_elapsed; + + tm->t_tot_cpu += dt_cpu; + tm->t_tot_elapsed += dt_elapsed; +} + + +void +ptmr_reset(ptmr_t * tm) +{ + tm->t_cpu = 0.0; + tm->t_elapsed = 0.0; +} + + +void +ptmr_init(ptmr_t * tm) +{ + tm->t_cpu = 0.0; + tm->t_elapsed = 0.0; + tm->t_tot_cpu = 0.0; + tm->t_tot_elapsed = 0.0; +} + + +void +ptmr_reset_all(ptmr_t * tm) +{ + for (; tm->name; tm++) + ptmr_reset(tm); +} + + +void +ptmr_print_all(FILE * fp, ptmr_t * tm, float64 norm) +{ + if (norm != 0.0) { + norm = 1.0 / norm; + for (; tm->name; tm++) + fprintf(fp, " %6.2fx %s", tm->t_cpu * norm, tm->name); + } +} + + +int32 +host_endian(void) +{ + FILE *fp; + int32 BYTE_ORDER_MAGIC; + char *file; + char buf[8]; + int32 k, endian; + + file = "/tmp/__EnDiAn_TeSt__"; + + if ((fp = fopen(file, "wb")) == NULL) { + E_ERROR("Failed to open file '%s' for writing", file); + return -1; + } + + BYTE_ORDER_MAGIC = (int32) 0x11223344; + + k = (int32) BYTE_ORDER_MAGIC; + if (fwrite(&k, sizeof(int32), 1, fp) != 1) { + E_ERROR("Failed to write to file '%s'\n", file); + fclose(fp); + unlink(file); + return -1; + } + + fclose(fp); + if ((fp = fopen(file, "rb")) == NULL) { + E_ERROR_SYSTEM("Failed to open file '%s' for reading", file); + unlink(file); + return -1; + } + if (fread(buf, 1, sizeof(int32), fp) != sizeof(int32)) { + E_ERROR("Failed to read from file '%s'\n", file); + fclose(fp); + unlink(file); + return -1; + } + fclose(fp); + unlink(file); + + /* If buf[0] == lsB of BYTE_ORDER_MAGIC, we are little-endian */ + endian = (buf[0] == (BYTE_ORDER_MAGIC & 0x000000ff)) ? 1 : 0; + + return (endian); +} diff --git a/media/sphinxbase/src/libsphinxbase/util/sbthread.c b/media/sphinxbase/src/libsphinxbase/util/sbthread.c new file mode 100644 index 000000000..28bf77356 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/sbthread.c @@ -0,0 +1,741 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 2008 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ + +/** + * @file sbthread.c + * @brief Simple portable thread functions + * @author David Huggins-Daines <dhuggins@cs.cmu.edu> + */ + +#include <string.h> + +#include "sphinxbase/sbthread.h" +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/err.h" + +/* + * Platform-specific parts: threads, mutexes, and signals. + */ +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(__SYMBIAN32__) +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif /* not _WIN32_WINNT */ +#include <windows.h> + +struct sbthread_s { + cmd_ln_t *config; + sbmsgq_t *msgq; + sbthread_main func; + void *arg; + HANDLE th; + DWORD tid; +}; + +struct sbmsgq_s { + /* Ringbuffer for passing messages. */ + char *data; + size_t depth; + size_t out; + size_t nbytes; + + /* Current message is stored here. */ + char *msg; + size_t msglen; + CRITICAL_SECTION mtx; + HANDLE evt; +}; + +struct sbevent_s { + HANDLE evt; +}; + +struct sbmtx_s { + CRITICAL_SECTION mtx; +}; + +DWORD WINAPI +sbthread_internal_main(LPVOID arg) +{ + sbthread_t *th = (sbthread_t *)arg; + int rv; + + rv = (*th->func)(th); + return (DWORD)rv; +} + +sbthread_t * +sbthread_start(cmd_ln_t *config, sbthread_main func, void *arg) +{ + sbthread_t *th; + + th = ckd_calloc(1, sizeof(*th)); + th->config = config; + th->func = func; + th->arg = arg; + th->msgq = sbmsgq_init(256); + th->th = CreateThread(NULL, 0, sbthread_internal_main, th, 0, &th->tid); + if (th->th == NULL) { + sbthread_free(th); + return NULL; + } + return th; +} + +int +sbthread_wait(sbthread_t *th) +{ + DWORD rv, exit; + + /* It has already been joined. */ + if (th->th == NULL) + return -1; + + rv = WaitForSingleObject(th->th, INFINITE); + if (rv == WAIT_FAILED) { + E_ERROR("Failed to join thread: WAIT_FAILED\n"); + return -1; + } + GetExitCodeThread(th->th, &exit); + CloseHandle(th->th); + th->th = NULL; + return (int)exit; +} + +static DWORD +cond_timed_wait(HANDLE cond, int sec, int nsec) +{ + DWORD rv; + if (sec == -1) { + rv = WaitForSingleObject(cond, INFINITE); + } + else { + DWORD ms; + + ms = sec * 1000 + nsec / (1000*1000); + rv = WaitForSingleObject(cond, ms); + } + return rv; +} + +/* Updated to use Unicode */ +sbevent_t * +sbevent_init(void) +{ + sbevent_t *evt; + + evt = ckd_calloc(1, sizeof(*evt)); + evt->evt = CreateEventW(NULL, FALSE, FALSE, NULL); + if (evt->evt == NULL) { + ckd_free(evt); + return NULL; + } + return evt; +} + +void +sbevent_free(sbevent_t *evt) +{ + CloseHandle(evt->evt); + ckd_free(evt); +} + +int +sbevent_signal(sbevent_t *evt) +{ + return SetEvent(evt->evt) ? 0 : -1; +} + +int +sbevent_wait(sbevent_t *evt, int sec, int nsec) +{ + DWORD rv; + + rv = cond_timed_wait(evt->evt, sec, nsec); + return rv; +} + +sbmtx_t * +sbmtx_init(void) +{ + sbmtx_t *mtx; + + mtx = ckd_calloc(1, sizeof(*mtx)); + InitializeCriticalSection(&mtx->mtx); + return mtx; +} + +int +sbmtx_trylock(sbmtx_t *mtx) +{ + return TryEnterCriticalSection(&mtx->mtx) ? 0 : -1; +} + +int +sbmtx_lock(sbmtx_t *mtx) +{ + EnterCriticalSection(&mtx->mtx); + return 0; +} + +int +sbmtx_unlock(sbmtx_t *mtx) +{ + LeaveCriticalSection(&mtx->mtx); + return 0; +} + +void +sbmtx_free(sbmtx_t *mtx) +{ + DeleteCriticalSection(&mtx->mtx); + ckd_free(mtx); +} + +sbmsgq_t * +sbmsgq_init(size_t depth) +{ + sbmsgq_t *msgq; + + msgq = ckd_calloc(1, sizeof(*msgq)); + msgq->depth = depth; + msgq->evt = CreateEventW(NULL, FALSE, FALSE, NULL); + if (msgq->evt == NULL) { + ckd_free(msgq); + return NULL; + } + InitializeCriticalSection(&msgq->mtx); + msgq->data = ckd_calloc(depth, 1); + msgq->msg = ckd_calloc(depth, 1); + return msgq; +} + +void +sbmsgq_free(sbmsgq_t *msgq) +{ + CloseHandle(msgq->evt); + ckd_free(msgq->data); + ckd_free(msgq->msg); + ckd_free(msgq); +} + +int +sbmsgq_send(sbmsgq_t *q, size_t len, void const *data) +{ + char const *cdata = (char const *)data; + size_t in; + + /* Don't allow things bigger than depth to be sent! */ + if (len + sizeof(len) > q->depth) + return -1; + + if (q->nbytes + len + sizeof(len) > q->depth) + WaitForSingleObject(q->evt, INFINITE); + + /* Lock things while we manipulate the buffer (FIXME: this + actually should have been atomic with the wait above ...) */ + EnterCriticalSection(&q->mtx); + in = (q->out + q->nbytes) % q->depth; + /* First write the size of the message. */ + if (in + sizeof(len) > q->depth) { + /* Handle the annoying case where the size field gets wrapped around. */ + size_t len1 = q->depth - in; + memcpy(q->data + in, &len, len1); + memcpy(q->data, ((char *)&len) + len1, sizeof(len) - len1); + q->nbytes += sizeof(len); + in = sizeof(len) - len1; + } + else { + memcpy(q->data + in, &len, sizeof(len)); + q->nbytes += sizeof(len); + in += sizeof(len); + } + + /* Now write the message body. */ + if (in + len > q->depth) { + /* Handle wraparound. */ + size_t len1 = q->depth - in; + memcpy(q->data + in, cdata, len1); + q->nbytes += len1; + cdata += len1; + len -= len1; + in = 0; + } + memcpy(q->data + in, cdata, len); + q->nbytes += len; + + /* Signal the condition variable. */ + SetEvent(q->evt); + /* Unlock. */ + LeaveCriticalSection(&q->mtx); + + return 0; +} + +void * +sbmsgq_wait(sbmsgq_t *q, size_t *out_len, int sec, int nsec) +{ + char *outptr; + size_t len; + + /* Wait for data to be available. */ + if (q->nbytes == 0) { + if (cond_timed_wait(q->evt, sec, nsec) == WAIT_FAILED) + /* Timed out or something... */ + return NULL; + } + /* Lock to manipulate the queue (FIXME) */ + EnterCriticalSection(&q->mtx); + /* Get the message size. */ + if (q->out + sizeof(q->msglen) > q->depth) { + /* Handle annoying wraparound case. */ + size_t len1 = q->depth - q->out; + memcpy(&q->msglen, q->data + q->out, len1); + memcpy(((char *)&q->msglen) + len1, q->data, + sizeof(q->msglen) - len1); + q->out = sizeof(q->msglen) - len1; + } + else { + memcpy(&q->msglen, q->data + q->out, sizeof(q->msglen)); + q->out += sizeof(q->msglen); + } + q->nbytes -= sizeof(q->msglen); + /* Get the message body. */ + outptr = q->msg; + len = q->msglen; + if (q->out + q->msglen > q->depth) { + /* Handle wraparound. */ + size_t len1 = q->depth - q->out; + memcpy(outptr, q->data + q->out, len1); + outptr += len1; + len -= len1; + q->nbytes -= len1; + q->out = 0; + } + memcpy(outptr, q->data + q->out, len); + q->nbytes -= len; + q->out += len; + + /* Signal the condition variable. */ + SetEvent(q->evt); + /* Unlock. */ + LeaveCriticalSection(&q->mtx); + if (out_len) + *out_len = q->msglen; + return q->msg; +} + +#else /* POSIX */ +#include <pthread.h> +#include <sys/time.h> + +struct sbthread_s { + cmd_ln_t *config; + sbmsgq_t *msgq; + sbthread_main func; + void *arg; + pthread_t th; +}; + +struct sbmsgq_s { + /* Ringbuffer for passing messages. */ + char *data; + size_t depth; + size_t out; + size_t nbytes; + + /* Current message is stored here. */ + char *msg; + size_t msglen; + pthread_mutex_t mtx; + pthread_cond_t cond; +}; + +struct sbevent_s { + pthread_mutex_t mtx; + pthread_cond_t cond; + int signalled; +}; + +struct sbmtx_s { + pthread_mutex_t mtx; +}; + +static void * +sbthread_internal_main(void *arg) +{ + sbthread_t *th = (sbthread_t *)arg; + int rv; + + rv = (*th->func)(th); + return (void *)(long)rv; +} + +sbthread_t * +sbthread_start(cmd_ln_t *config, sbthread_main func, void *arg) +{ + sbthread_t *th; + int rv; + + th = ckd_calloc(1, sizeof(*th)); + th->config = config; + th->func = func; + th->arg = arg; + th->msgq = sbmsgq_init(1024); + if ((rv = pthread_create(&th->th, NULL, &sbthread_internal_main, th)) != 0) { + E_ERROR("Failed to create thread: %d\n", rv); + sbthread_free(th); + return NULL; + } + return th; +} + +int +sbthread_wait(sbthread_t *th) +{ + void *exit; + int rv; + + /* It has already been joined. */ + if (th->th == (pthread_t)-1) + return -1; + + rv = pthread_join(th->th, &exit); + if (rv != 0) { + E_ERROR("Failed to join thread: %d\n", rv); + return -1; + } + th->th = (pthread_t)-1; + return (int)(long)exit; +} + +sbmsgq_t * +sbmsgq_init(size_t depth) +{ + sbmsgq_t *msgq; + + msgq = ckd_calloc(1, sizeof(*msgq)); + msgq->depth = depth; + if (pthread_cond_init(&msgq->cond, NULL) != 0) { + ckd_free(msgq); + return NULL; + } + if (pthread_mutex_init(&msgq->mtx, NULL) != 0) { + pthread_cond_destroy(&msgq->cond); + ckd_free(msgq); + return NULL; + } + msgq->data = ckd_calloc(depth, 1); + msgq->msg = ckd_calloc(depth, 1); + return msgq; +} + +void +sbmsgq_free(sbmsgq_t *msgq) +{ + pthread_mutex_destroy(&msgq->mtx); + pthread_cond_destroy(&msgq->cond); + ckd_free(msgq->data); + ckd_free(msgq->msg); + ckd_free(msgq); +} + +int +sbmsgq_send(sbmsgq_t *q, size_t len, void const *data) +{ + size_t in; + + /* Don't allow things bigger than depth to be sent! */ + if (len + sizeof(len) > q->depth) + return -1; + + /* Lock the condition variable while we manipulate the buffer. */ + pthread_mutex_lock(&q->mtx); + if (q->nbytes + len + sizeof(len) > q->depth) { + /* Unlock and wait for space to be available. */ + if (pthread_cond_wait(&q->cond, &q->mtx) != 0) { + /* Timed out, don't send anything. */ + pthread_mutex_unlock(&q->mtx); + return -1; + } + /* Condition is now locked again. */ + } + in = (q->out + q->nbytes) % q->depth; + + /* First write the size of the message. */ + if (in + sizeof(len) > q->depth) { + /* Handle the annoying case where the size field gets wrapped around. */ + size_t len1 = q->depth - in; + memcpy(q->data + in, &len, len1); + memcpy(q->data, ((char *)&len) + len1, sizeof(len) - len1); + q->nbytes += sizeof(len); + in = sizeof(len) - len1; + } + else { + memcpy(q->data + in, &len, sizeof(len)); + q->nbytes += sizeof(len); + in += sizeof(len); + } + + /* Now write the message body. */ + if (in + len > q->depth) { + /* Handle wraparound. */ + size_t len1 = q->depth - in; + memcpy(q->data + in, data, len1); + q->nbytes += len1; + data = (char const *)data + len1; + len -= len1; + in = 0; + } + memcpy(q->data + in, data, len); + q->nbytes += len; + + /* Signal the condition variable. */ + pthread_cond_signal(&q->cond); + /* Unlock it, we have nothing else to do. */ + pthread_mutex_unlock(&q->mtx); + return 0; +} + +static int +cond_timed_wait(pthread_cond_t *cond, pthread_mutex_t *mtx, int sec, int nsec) +{ + int rv; + if (sec == -1) { + rv = pthread_cond_wait(cond, mtx); + } + else { + struct timeval now; + struct timespec end; + + gettimeofday(&now, NULL); + end.tv_sec = now.tv_sec + sec; + end.tv_nsec = now.tv_usec * 1000 + nsec; + if (end.tv_nsec > (1000*1000*1000)) { + sec += end.tv_nsec / (1000*1000*1000); + end.tv_nsec = end.tv_nsec % (1000*1000*1000); + } + rv = pthread_cond_timedwait(cond, mtx, &end); + } + return rv; +} + +void * +sbmsgq_wait(sbmsgq_t *q, size_t *out_len, int sec, int nsec) +{ + char *outptr; + size_t len; + + /* Lock the condition variable while we manipulate nmsg. */ + pthread_mutex_lock(&q->mtx); + if (q->nbytes == 0) { + /* Unlock the condition variable and wait for a signal. */ + if (cond_timed_wait(&q->cond, &q->mtx, sec, nsec) != 0) { + /* Timed out or something... */ + pthread_mutex_unlock(&q->mtx); + return NULL; + } + /* Condition variable is now locked again. */ + } + /* Get the message size. */ + if (q->out + sizeof(q->msglen) > q->depth) { + /* Handle annoying wraparound case. */ + size_t len1 = q->depth - q->out; + memcpy(&q->msglen, q->data + q->out, len1); + memcpy(((char *)&q->msglen) + len1, q->data, + sizeof(q->msglen) - len1); + q->out = sizeof(q->msglen) - len1; + } + else { + memcpy(&q->msglen, q->data + q->out, sizeof(q->msglen)); + q->out += sizeof(q->msglen); + } + q->nbytes -= sizeof(q->msglen); + /* Get the message body. */ + outptr = q->msg; + len = q->msglen; + if (q->out + q->msglen > q->depth) { + /* Handle wraparound. */ + size_t len1 = q->depth - q->out; + memcpy(outptr, q->data + q->out, len1); + outptr += len1; + len -= len1; + q->nbytes -= len1; + q->out = 0; + } + memcpy(outptr, q->data + q->out, len); + q->nbytes -= len; + q->out += len; + + /* Signal the condition variable. */ + pthread_cond_signal(&q->cond); + /* Unlock the condition variable, we are done. */ + pthread_mutex_unlock(&q->mtx); + if (out_len) + *out_len = q->msglen; + return q->msg; +} + +sbevent_t * +sbevent_init(void) +{ + sbevent_t *evt; + int rv; + + evt = ckd_calloc(1, sizeof(*evt)); + if ((rv = pthread_mutex_init(&evt->mtx, NULL)) != 0) { + E_ERROR("Failed to initialize mutex: %d\n", rv); + ckd_free(evt); + return NULL; + } + if ((rv = pthread_cond_init(&evt->cond, NULL)) != 0) { + E_ERROR_SYSTEM("Failed to initialize mutex: %d\n", rv); + pthread_mutex_destroy(&evt->mtx); + ckd_free(evt); + return NULL; + } + return evt; +} + +void +sbevent_free(sbevent_t *evt) +{ + pthread_mutex_destroy(&evt->mtx); + pthread_cond_destroy(&evt->cond); + ckd_free(evt); +} + +int +sbevent_signal(sbevent_t *evt) +{ + int rv; + + pthread_mutex_lock(&evt->mtx); + evt->signalled = TRUE; + rv = pthread_cond_signal(&evt->cond); + pthread_mutex_unlock(&evt->mtx); + return rv; +} + +int +sbevent_wait(sbevent_t *evt, int sec, int nsec) +{ + int rv = 0; + + /* Lock the mutex before we check its signalled state. */ + pthread_mutex_lock(&evt->mtx); + /* If it's not signalled, then wait until it is. */ + if (!evt->signalled) + rv = cond_timed_wait(&evt->cond, &evt->mtx, sec, nsec); + /* Set its state to unsignalled if we were successful. */ + if (rv == 0) + evt->signalled = FALSE; + /* And unlock its mutex. */ + pthread_mutex_unlock(&evt->mtx); + + return rv; +} + +sbmtx_t * +sbmtx_init(void) +{ + sbmtx_t *mtx; + + mtx = ckd_calloc(1, sizeof(*mtx)); + if (pthread_mutex_init(&mtx->mtx, NULL) != 0) { + ckd_free(mtx); + return NULL; + } + return mtx; +} + +int +sbmtx_trylock(sbmtx_t *mtx) +{ + return pthread_mutex_trylock(&mtx->mtx); +} + +int +sbmtx_lock(sbmtx_t *mtx) +{ + return pthread_mutex_lock(&mtx->mtx); +} + +int +sbmtx_unlock(sbmtx_t *mtx) +{ + return pthread_mutex_unlock(&mtx->mtx); +} + +void +sbmtx_free(sbmtx_t *mtx) +{ + pthread_mutex_destroy(&mtx->mtx); + ckd_free(mtx); +} +#endif /* not WIN32 */ + +cmd_ln_t * +sbthread_config(sbthread_t *th) +{ + return th->config; +} + +void * +sbthread_arg(sbthread_t *th) +{ + return th->arg; +} + +sbmsgq_t * +sbthread_msgq(sbthread_t *th) +{ + return th->msgq; +} + +int +sbthread_send(sbthread_t *th, size_t len, void const *data) +{ + return sbmsgq_send(th->msgq, len, data); +} + +void +sbthread_free(sbthread_t *th) +{ + sbthread_wait(th); + sbmsgq_free(th->msgq); + ckd_free(th); +} diff --git a/media/sphinxbase/src/libsphinxbase/util/slamch.c b/media/sphinxbase/src/libsphinxbase/util/slamch.c new file mode 100644 index 000000000..229458470 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/slamch.c @@ -0,0 +1,1029 @@ +/* src/slamch.f -- translated by f2c (version 20050501). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "sphinxbase/f2c.h" + +#ifdef _MSC_VER +#pragma warning (disable: 4244) +#endif + +/* Table of constant values */ + +static integer c__1 = 1; +static real c_b32 = 0.f; + +doublereal +slamch_(char *cmach, ftnlen cmach_len) +{ + /* Initialized data */ + + static logical first = TRUE_; + + /* System generated locals */ + integer i__1; + real ret_val; + + /* Builtin functions */ + double pow_ri(real *, integer *); + + /* Local variables */ + static real t; + static integer it; + static real rnd, eps, base; + static integer beta; + static real emin, prec, emax; + static integer imin, imax; + static logical lrnd; + static real rmin, rmax, rmach; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + static real small, sfmin; + extern /* Subroutine */ int slamc2_(integer *, integer *, logical *, real + *, integer *, real *, integer *, + real *); + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SLAMCH determines single precision machine parameters. */ + +/* Arguments */ +/* ========= */ + +/* CMACH (input) CHARACTER*1 */ +/* Specifies the value to be returned by SLAMCH: */ +/* = 'E' or 'e', SLAMCH := eps */ +/* = 'S' or 's , SLAMCH := sfmin */ +/* = 'B' or 'b', SLAMCH := base */ +/* = 'P' or 'p', SLAMCH := eps*base */ +/* = 'N' or 'n', SLAMCH := t */ +/* = 'R' or 'r', SLAMCH := rnd */ +/* = 'M' or 'm', SLAMCH := emin */ +/* = 'U' or 'u', SLAMCH := rmin */ +/* = 'L' or 'l', SLAMCH := emax */ +/* = 'O' or 'o', SLAMCH := rmax */ + +/* where */ + +/* eps = relative machine precision */ +/* sfmin = safe minimum, such that 1/sfmin does not overflow */ +/* base = base of the machine */ +/* prec = eps*base */ +/* t = number of (base) digits in the mantissa */ +/* rnd = 1.0 when rounding occurs in addition, 0.0 otherwise */ +/* emin = minimum exponent before (gradual) underflow */ +/* rmin = underflow threshold - base**(emin-1) */ +/* emax = largest exponent before overflow */ +/* rmax = overflow threshold - (base**emax)*(1-eps) */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Save statement .. */ +/* .. */ +/* .. Data statements .. */ +/* .. */ +/* .. Executable Statements .. */ + + if (first) { + first = FALSE_; + slamc2_(&beta, &it, &lrnd, &eps, &imin, &rmin, &imax, &rmax); + base = (real) beta; + t = (real) it; + if (lrnd) { + rnd = 1.f; + i__1 = 1 - it; + eps = pow_ri(&base, &i__1) / 2; + } + else { + rnd = 0.f; + i__1 = 1 - it; + eps = pow_ri(&base, &i__1); + } + prec = eps * base; + emin = (real) imin; + emax = (real) imax; + sfmin = rmin; + small = 1.f / rmax; + if (small >= sfmin) { + +/* Use SMALL plus a bit, to avoid the possibility of rounding */ +/* causing overflow when computing 1/sfmin. */ + + sfmin = small * (eps + 1.f); + } + } + + if (lsame_(cmach, "E", (ftnlen) 1, (ftnlen) 1)) { + rmach = eps; + } + else if (lsame_(cmach, "S", (ftnlen) 1, (ftnlen) 1)) { + rmach = sfmin; + } + else if (lsame_(cmach, "B", (ftnlen) 1, (ftnlen) 1)) { + rmach = base; + } + else if (lsame_(cmach, "P", (ftnlen) 1, (ftnlen) 1)) { + rmach = prec; + } + else if (lsame_(cmach, "N", (ftnlen) 1, (ftnlen) 1)) { + rmach = t; + } + else if (lsame_(cmach, "R", (ftnlen) 1, (ftnlen) 1)) { + rmach = rnd; + } + else if (lsame_(cmach, "M", (ftnlen) 1, (ftnlen) 1)) { + rmach = emin; + } + else if (lsame_(cmach, "U", (ftnlen) 1, (ftnlen) 1)) { + rmach = rmin; + } + else if (lsame_(cmach, "L", (ftnlen) 1, (ftnlen) 1)) { + rmach = emax; + } + else if (lsame_(cmach, "O", (ftnlen) 1, (ftnlen) 1)) { + rmach = rmax; + } + + ret_val = rmach; + return ret_val; + +/* End of SLAMCH */ + +} /* slamch_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int +slamc1_(integer * beta, integer * t, logical * rnd, logical * ieee1) +{ + /* Initialized data */ + + static logical first = TRUE_; + + /* System generated locals */ + real r__1, r__2; + + /* Local variables */ + static real a, b, c__, f, t1, t2; + static integer lt; + static real one, qtr; + static logical lrnd; + static integer lbeta; + static real savec; + static logical lieee1; + extern doublereal slamc3_(real *, real *); + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SLAMC1 determines the machine parameters given by BETA, T, RND, and */ +/* IEEE1. */ + +/* Arguments */ +/* ========= */ + +/* BETA (output) INTEGER */ +/* The base of the machine. */ + +/* T (output) INTEGER */ +/* The number of ( BETA ) digits in the mantissa. */ + +/* RND (output) LOGICAL */ +/* Specifies whether proper rounding ( RND = .TRUE. ) or */ +/* chopping ( RND = .FALSE. ) occurs in addition. This may not */ +/* be a reliable guide to the way in which the machine performs */ +/* its arithmetic. */ + +/* IEEE1 (output) LOGICAL */ +/* Specifies whether rounding appears to be done in the IEEE */ +/* 'round to nearest' style. */ + +/* Further Details */ +/* =============== */ + +/* The routine is based on the routine ENVRON by Malcolm and */ +/* incorporates suggestions by Gentleman and Marovich. See */ + +/* Malcolm M. A. (1972) Algorithms to reveal properties of */ +/* floating-point arithmetic. Comms. of the ACM, 15, 949-951. */ + +/* Gentleman W. M. and Marovich S. B. (1974) More on algorithms */ +/* that reveal properties of floating point arithmetic units. */ +/* Comms. of the ACM, 17, 276-277. */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. Save statement .. */ +/* .. */ +/* .. Data statements .. */ +/* .. */ +/* .. Executable Statements .. */ + + if (first) { + first = FALSE_; + one = 1.f; + +/* LBETA, LIEEE1, LT and LRND are the local values of BETA, */ +/* IEEE1, T and RND. */ + +/* Throughout this routine we use the function SLAMC3 to ensure */ +/* that relevant values are stored and not held in registers, or */ +/* are not affected by optimizers. */ + +/* Compute a = 2.0**m with the smallest positive integer m such */ +/* that */ + +/* fl( a + 1.0 ) = a. */ + + a = 1.f; + c__ = 1.f; + +/* + WHILE( C.EQ.ONE )LOOP */ + L10: + if (c__ == one) { + a *= 2; + c__ = slamc3_(&a, &one); + r__1 = -a; + c__ = slamc3_(&c__, &r__1); + goto L10; + } +/* + END WHILE */ + +/* Now compute b = 2.0**m with the smallest positive integer m */ +/* such that */ + +/* fl( a + b ) .gt. a. */ + + b = 1.f; + c__ = slamc3_(&a, &b); + +/* + WHILE( C.EQ.A )LOOP */ + L20: + if (c__ == a) { + b *= 2; + c__ = slamc3_(&a, &b); + goto L20; + } +/* + END WHILE */ + +/* Now compute the base. a and c are neighbouring floating point */ +/* numbers in the interval ( beta**t, beta**( t + 1 ) ) and so */ +/* their difference is beta. Adding 0.25 to c is to ensure that it */ +/* is truncated to beta and not ( beta - 1 ). */ + + qtr = one / 4; + savec = c__; + r__1 = -a; + c__ = slamc3_(&c__, &r__1); + lbeta = c__ + qtr; + +/* Now determine whether rounding or chopping occurs, by adding a */ +/* bit less than beta/2 and a bit more than beta/2 to a. */ + + b = (real) lbeta; + r__1 = b / 2; + r__2 = -b / 100; + f = slamc3_(&r__1, &r__2); + c__ = slamc3_(&f, &a); + if (c__ == a) { + lrnd = TRUE_; + } + else { + lrnd = FALSE_; + } + r__1 = b / 2; + r__2 = b / 100; + f = slamc3_(&r__1, &r__2); + c__ = slamc3_(&f, &a); + if (lrnd && c__ == a) { + lrnd = FALSE_; + } + +/* Try and decide whether rounding is done in the IEEE 'round to */ +/* nearest' style. B/2 is half a unit in the last place of the two */ +/* numbers A and SAVEC. Furthermore, A is even, i.e. has last bit */ +/* zero, and SAVEC is odd. Thus adding B/2 to A should not change */ +/* A, but adding B/2 to SAVEC should change SAVEC. */ + + r__1 = b / 2; + t1 = slamc3_(&r__1, &a); + r__1 = b / 2; + t2 = slamc3_(&r__1, &savec); + lieee1 = t1 == a && t2 > savec && lrnd; + +/* Now find the mantissa, t. It should be the integer part of */ +/* log to the base beta of a, however it is safer to determine t */ +/* by powering. So we find t as the smallest positive integer for */ +/* which */ + +/* fl( beta**t + 1.0 ) = 1.0. */ + + lt = 0; + a = 1.f; + c__ = 1.f; + +/* + WHILE( C.EQ.ONE )LOOP */ + L30: + if (c__ == one) { + ++lt; + a *= lbeta; + c__ = slamc3_(&a, &one); + r__1 = -a; + c__ = slamc3_(&c__, &r__1); + goto L30; + } +/* + END WHILE */ + + } + + *beta = lbeta; + *t = lt; + *rnd = lrnd; + *ieee1 = lieee1; + return 0; + +/* End of SLAMC1 */ + +} /* slamc1_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int +slamc2_(integer * beta, integer * t, logical * rnd, real * + eps, integer * emin, real * rmin, integer * emax, real * rmax) +{ + /* Initialized data */ + + static logical first = TRUE_; + static logical iwarn = FALSE_; + + /* Format strings */ + static char fmt_9999[] = + "(//\002 WARNING. The value EMIN may be incorre" + "ct:-\002,\002 EMIN = \002,i8,/\002 If, after inspection, the va" + "lue EMIN looks\002,\002 acceptable please comment out \002,/\002" + " the IF block as marked within the code of routine\002,\002 SLAM" + "C2,\002,/\002 otherwise supply EMIN explicitly.\002,/)"; + + /* System generated locals */ + integer i__1; + real r__1, r__2, r__3, r__4, r__5; + + /* Builtin functions */ + double pow_ri(real *, integer *); + integer s_wsfe(cilist *), do_fio(integer *, char *, ftnlen), + e_wsfe(void); + + /* Local variables */ + static real a, b, c__; + static integer i__, lt; + static real one, two; + static logical ieee; + static real half; + static logical lrnd; + static real leps, zero; + static integer lbeta; + static real rbase; + static integer lemin, lemax, gnmin; + static real small; + static integer gpmin; + static real third, lrmin, lrmax, sixth; + static logical lieee1; + extern /* Subroutine */ int slamc1_(integer *, integer *, logical *, + logical *); + extern doublereal slamc3_(real *, real *); + extern /* Subroutine */ int slamc4_(integer *, real *, integer *), + slamc5_(integer *, integer *, integer *, logical *, integer *, + real *); + static integer ngnmin, ngpmin; + + /* Fortran I/O blocks */ + static cilist io___58 = { 0, 6, 0, fmt_9999, 0 }; + + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SLAMC2 determines the machine parameters specified in its argument */ +/* list. */ + +/* Arguments */ +/* ========= */ + +/* BETA (output) INTEGER */ +/* The base of the machine. */ + +/* T (output) INTEGER */ +/* The number of ( BETA ) digits in the mantissa. */ + +/* RND (output) LOGICAL */ +/* Specifies whether proper rounding ( RND = .TRUE. ) or */ +/* chopping ( RND = .FALSE. ) occurs in addition. This may not */ +/* be a reliable guide to the way in which the machine performs */ +/* its arithmetic. */ + +/* EPS (output) REAL */ +/* The smallest positive number such that */ + +/* fl( 1.0 - EPS ) .LT. 1.0, */ + +/* where fl denotes the computed value. */ + +/* EMIN (output) INTEGER */ +/* The minimum exponent before (gradual) underflow occurs. */ + +/* RMIN (output) REAL */ +/* The smallest normalized number for the machine, given by */ +/* BASE**( EMIN - 1 ), where BASE is the floating point value */ +/* of BETA. */ + +/* EMAX (output) INTEGER */ +/* The maximum exponent before overflow occurs. */ + +/* RMAX (output) REAL */ +/* The largest positive number for the machine, given by */ +/* BASE**EMAX * ( 1 - EPS ), where BASE is the floating point */ +/* value of BETA. */ + +/* Further Details */ +/* =============== */ + +/* The computation of EPS is based on a routine PARANOIA by */ +/* W. Kahan of the University of California at Berkeley. */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Save statement .. */ +/* .. */ +/* .. Data statements .. */ +/* .. */ +/* .. Executable Statements .. */ + + if (first) { + first = FALSE_; + zero = 0.f; + one = 1.f; + two = 2.f; + +/* LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of */ +/* BETA, T, RND, EPS, EMIN and RMIN. */ + +/* Throughout this routine we use the function SLAMC3 to ensure */ +/* that relevant values are stored and not held in registers, or */ +/* are not affected by optimizers. */ + +/* SLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1. */ + + slamc1_(&lbeta, <, &lrnd, &lieee1); + +/* Start to find EPS. */ + + b = (real) lbeta; + i__1 = -lt; + a = pow_ri(&b, &i__1); + leps = a; + +/* Try some tricks to see whether or not this is the correct EPS. */ + + b = two / 3; + half = one / 2; + r__1 = -half; + sixth = slamc3_(&b, &r__1); + third = slamc3_(&sixth, &sixth); + r__1 = -half; + b = slamc3_(&third, &r__1); + b = slamc3_(&b, &sixth); + b = dabs(b); + if (b < leps) { + b = leps; + } + + leps = 1.f; + +/* + WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP */ + L10: + if (leps > b && b > zero) { + leps = b; + r__1 = half * leps; +/* Computing 5th power */ + r__3 = two, r__4 = r__3, r__3 *= r__3; +/* Computing 2nd power */ + r__5 = leps; + r__2 = r__4 * (r__3 * r__3) * (r__5 * r__5); + c__ = slamc3_(&r__1, &r__2); + r__1 = -c__; + c__ = slamc3_(&half, &r__1); + b = slamc3_(&half, &c__); + r__1 = -b; + c__ = slamc3_(&half, &r__1); + b = slamc3_(&half, &c__); + goto L10; + } +/* + END WHILE */ + + if (a < leps) { + leps = a; + } + +/* Computation of EPS complete. */ + +/* Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3)). */ +/* Keep dividing A by BETA until (gradual) underflow occurs. This */ +/* is detected when we cannot recover the previous A. */ + + rbase = one / lbeta; + small = one; + for (i__ = 1; i__ <= 3; ++i__) { + r__1 = small * rbase; + small = slamc3_(&r__1, &zero); +/* L20: */ + } + a = slamc3_(&one, &small); + slamc4_(&ngpmin, &one, &lbeta); + r__1 = -one; + slamc4_(&ngnmin, &r__1, &lbeta); + slamc4_(&gpmin, &a, &lbeta); + r__1 = -a; + slamc4_(&gnmin, &r__1, &lbeta); + ieee = FALSE_; + + if (ngpmin == ngnmin && gpmin == gnmin) { + if (ngpmin == gpmin) { + lemin = ngpmin; +/* ( Non twos-complement machines, no gradual underflow; */ +/* e.g., VAX ) */ + } + else if (gpmin - ngpmin == 3) { + lemin = ngpmin - 1 + lt; + ieee = TRUE_; +/* ( Non twos-complement machines, with gradual underflow; */ +/* e.g., IEEE standard followers ) */ + } + else { + lemin = min(ngpmin, gpmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } + else if (ngpmin == gpmin && ngnmin == gnmin) { + if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1) { + lemin = max(ngpmin, ngnmin); +/* ( Twos-complement machines, no gradual underflow; */ +/* e.g., CYBER 205 ) */ + } + else { + lemin = min(ngpmin, ngnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } + else if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1 + && gpmin == gnmin) { + if (gpmin - min(ngpmin, ngnmin) == 3) { + lemin = max(ngpmin, ngnmin) - 1 + lt; +/* ( Twos-complement machines with gradual underflow; */ +/* no known machine ) */ + } + else { + lemin = min(ngpmin, ngnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } + + } + else { +/* Computing MIN */ + i__1 = min(ngpmin, ngnmin), i__1 = min(i__1, gpmin); + lemin = min(i__1, gnmin); +/* ( A guess; no known machine ) */ + iwarn = TRUE_; + } +/* ** */ +/* Comment out this if block if EMIN is ok */ + if (iwarn) { + first = TRUE_; + s_wsfe(&io___58); + do_fio(&c__1, (char *) &lemin, (ftnlen) sizeof(integer)); + e_wsfe(); + } +/* ** */ + +/* Assume IEEE arithmetic if we found denormalised numbers above, */ +/* or if arithmetic seems to round in the IEEE style, determined */ +/* in routine SLAMC1. A true IEEE machine should have both things */ +/* true; however, faulty machines may have one or the other. */ + + ieee = ieee || lieee1; + +/* Compute RMIN by successive division by BETA. We could compute */ +/* RMIN as BASE**( EMIN - 1 ), but some machines underflow during */ +/* this computation. */ + + lrmin = 1.f; + i__1 = 1 - lemin; + for (i__ = 1; i__ <= i__1; ++i__) { + r__1 = lrmin * rbase; + lrmin = slamc3_(&r__1, &zero); +/* L30: */ + } + +/* Finally, call SLAMC5 to compute EMAX and RMAX. */ + + slamc5_(&lbeta, <, &lemin, &ieee, &lemax, &lrmax); + } + + *beta = lbeta; + *t = lt; + *rnd = lrnd; + *eps = leps; + *emin = lemin; + *rmin = lrmin; + *emax = lemax; + *rmax = lrmax; + + return 0; + + +/* End of SLAMC2 */ + +} /* slamc2_ */ + + +/* *********************************************************************** */ + +doublereal +slamc3_(real * a, real * b) +{ + /* System generated locals */ + real ret_val; + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SLAMC3 is intended to force A and B to be stored prior to doing */ +/* the addition of A and B , for use in situations where optimizers */ +/* might hold one of these in a register. */ + +/* Arguments */ +/* ========= */ + +/* A, B (input) REAL */ +/* The values A and B. */ + +/* ===================================================================== */ + +/* .. Executable Statements .. */ + + ret_val = *a + *b; + + return ret_val; + +/* End of SLAMC3 */ + +} /* slamc3_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int +slamc4_(integer * emin, real * start, integer * base) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static real a; + static integer i__; + static real b1, b2, c1, c2, d1, d2, one, zero, rbase; + extern doublereal slamc3_(real *, real *); + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SLAMC4 is a service routine for SLAMC2. */ + +/* Arguments */ +/* ========= */ + +/* EMIN (output) EMIN */ +/* The minimum exponent before (gradual) underflow, computed by */ +/* setting A = START and dividing by BASE until the previous A */ +/* can not be recovered. */ + +/* START (input) REAL */ +/* The starting point for determining EMIN. */ + +/* BASE (input) INTEGER */ +/* The base of the machine. */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + + a = *start; + one = 1.f; + rbase = one / *base; + zero = 0.f; + *emin = 1; + r__1 = a * rbase; + b1 = slamc3_(&r__1, &zero); + c1 = a; + c2 = a; + d1 = a; + d2 = a; +/* + WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND. */ +/* $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP */ + L10: + if (c1 == a && c2 == a && d1 == a && d2 == a) { + --(*emin); + a = b1; + r__1 = a / *base; + b1 = slamc3_(&r__1, &zero); + r__1 = b1 * *base; + c1 = slamc3_(&r__1, &zero); + d1 = zero; + i__1 = *base; + for (i__ = 1; i__ <= i__1; ++i__) { + d1 += b1; +/* L20: */ + } + r__1 = a * rbase; + b2 = slamc3_(&r__1, &zero); + r__1 = b2 / rbase; + c2 = slamc3_(&r__1, &zero); + d2 = zero; + i__1 = *base; + for (i__ = 1; i__ <= i__1; ++i__) { + d2 += b2; +/* L30: */ + } + goto L10; + } +/* + END WHILE */ + + return 0; + +/* End of SLAMC4 */ + +} /* slamc4_ */ + + +/* *********************************************************************** */ + +/* Subroutine */ int +slamc5_(integer * beta, integer * p, integer * emin, + logical * ieee, integer * emax, real * rmax) +{ + /* System generated locals */ + integer i__1; + real r__1; + + /* Local variables */ + static integer i__; + static real y, z__; + static integer try__, lexp; + static real oldy; + static integer uexp, nbits; + extern doublereal slamc3_(real *, real *); + static real recbas; + static integer exbits, expsum; + + +/* -- LAPACK auxiliary routine (version 3.0) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., */ +/* Courant Institute, Argonne National Lab, and Rice University */ +/* October 31, 1992 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SLAMC5 attempts to compute RMAX, the largest machine floating-point */ +/* number, without overflow. It assumes that EMAX + abs(EMIN) sum */ +/* approximately to a power of 2. It will fail on machines where this */ +/* assumption does not hold, for example, the Cyber 205 (EMIN = -28625, */ +/* EMAX = 28718). It will also fail if the value supplied for EMIN is */ +/* too large (i.e. too close to zero), probably with overflow. */ + +/* Arguments */ +/* ========= */ + +/* BETA (input) INTEGER */ +/* The base of floating-point arithmetic. */ + +/* P (input) INTEGER */ +/* The number of base BETA digits in the mantissa of a */ +/* floating-point value. */ + +/* EMIN (input) INTEGER */ +/* The minimum exponent before (gradual) underflow. */ + +/* IEEE (input) LOGICAL */ +/* A logical flag specifying whether or not the arithmetic */ +/* system is thought to comply with the IEEE standard. */ + +/* EMAX (output) INTEGER */ +/* The largest exponent before overflow */ + +/* RMAX (output) REAL */ +/* The largest machine floating-point number. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Executable Statements .. */ + +/* First compute LEXP and UEXP, two powers of 2 that bound */ +/* abs(EMIN). We then assume that EMAX + abs(EMIN) will sum */ +/* approximately to the bound that is closest to abs(EMIN). */ +/* (EMAX is the exponent of the required number RMAX). */ + + lexp = 1; + exbits = 1; + L10: + try__ = lexp << 1; + if (try__ <= -(*emin)) { + lexp = try__; + ++exbits; + goto L10; + } + if (lexp == -(*emin)) { + uexp = lexp; + } + else { + uexp = try__; + ++exbits; + } + +/* Now -LEXP is less than or equal to EMIN, and -UEXP is greater */ +/* than or equal to EMIN. EXBITS is the number of bits needed to */ +/* store the exponent. */ + + if (uexp + *emin > -lexp - *emin) { + expsum = lexp << 1; + } + else { + expsum = uexp << 1; + } + +/* EXPSUM is the exponent range, approximately equal to */ +/* EMAX - EMIN + 1 . */ + + *emax = expsum + *emin - 1; + nbits = exbits + 1 + *p; + +/* NBITS is the total number of bits needed to store a */ +/* floating-point number. */ + + if (nbits % 2 == 1 && *beta == 2) { + +/* Either there are an odd number of bits used to store a */ +/* floating-point number, which is unlikely, or some bits are */ +/* not used in the representation of numbers, which is possible, */ +/* (e.g. Cray machines) or the mantissa has an implicit bit, */ +/* (e.g. IEEE machines, Dec Vax machines), which is perhaps the */ +/* most likely. We have to assume the last alternative. */ +/* If this is true, then we need to reduce EMAX by one because */ +/* there must be some way of representing zero in an implicit-bit */ +/* system. On machines like Cray, we are reducing EMAX by one */ +/* unnecessarily. */ + + --(*emax); + } + + if (*ieee) { + +/* Assume we are on an IEEE machine which reserves one exponent */ +/* for infinity and NaN. */ + + --(*emax); + } + +/* Now create RMAX, the largest machine number, which should */ +/* be equal to (1.0 - BETA**(-P)) * BETA**EMAX . */ + +/* First compute 1.0 - BETA**(-P), being careful that the */ +/* result is less than 1.0 . */ + + recbas = 1.f / *beta; + z__ = *beta - 1.f; + y = 0.f; + i__1 = *p; + for (i__ = 1; i__ <= i__1; ++i__) { + z__ *= recbas; + if (y < 1.f) { + oldy = y; + } + y = slamc3_(&y, &z__); +/* L20: */ + } + if (y >= 1.f) { + y = oldy; + } + +/* Now multiply by BETA**EMAX to get RMAX. */ + + i__1 = *emax; + for (i__ = 1; i__ <= i__1; ++i__) { + r__1 = y * *beta; + y = slamc3_(&r__1, &c_b32); +/* L30: */ + } + + *rmax = y; + return 0; + +/* End of SLAMC5 */ + +} /* slamc5_ */ diff --git a/media/sphinxbase/src/libsphinxbase/util/slapack_lite.c b/media/sphinxbase/src/libsphinxbase/util/slapack_lite.c new file mode 100644 index 000000000..4d4e1af31 --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/slapack_lite.c @@ -0,0 +1,1461 @@ +/* +NOTE: This is generated code. Look in README.python for information on + remaking this file. +*/ +#include "sphinxbase/f2c.h" + +#ifdef HAVE_CONFIG +#include "config.h" +#else +extern doublereal slamch_(char *); +#define EPSILON slamch_("Epsilon") +#define SAFEMINIMUM slamch_("Safe minimum") +#define PRECISION slamch_("Precision") +#define BASE slamch_("Base") +#endif + + +extern doublereal slapy2_(real *, real *); + + + +/* Table of constant values */ + +static integer c__0 = 0; +static real c_b163 = 0.f; +static real c_b164 = 1.f; +static integer c__1 = 1; +static real c_b181 = -1.f; +static integer c_n1 = -1; + +integer ieeeck_(integer *ispec, real *zero, real *one) +{ + /* System generated locals */ + integer ret_val; + + /* Local variables */ + static real nan1, nan2, nan3, nan4, nan5, nan6, neginf, posinf, negzro, + newzro; + + +/* + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1998 + + + Purpose + ======= + + IEEECK is called from the ILAENV to verify that Infinity and + possibly NaN arithmetic is safe (i.e. will not trap). + + Arguments + ========= + + ISPEC (input) INTEGER + Specifies whether to test just for inifinity arithmetic + or whether to test for infinity and NaN arithmetic. + = 0: Verify infinity arithmetic only. + = 1: Verify infinity and NaN arithmetic. + + ZERO (input) REAL + Must contain the value 0.0 + This is passed to prevent the compiler from optimizing + away this code. + + ONE (input) REAL + Must contain the value 1.0 + This is passed to prevent the compiler from optimizing + away this code. + + RETURN VALUE: INTEGER + = 0: Arithmetic failed to produce the correct answers + = 1: Arithmetic produced the correct answers +*/ + + ret_val = 1; + + posinf = *one / *zero; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + neginf = -(*one) / *zero; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + negzro = *one / (neginf + *one); + if (negzro != *zero) { + ret_val = 0; + return ret_val; + } + + neginf = *one / negzro; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + newzro = negzro + *zero; + if (newzro != *zero) { + ret_val = 0; + return ret_val; + } + + posinf = *one / newzro; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + neginf *= posinf; + if (neginf >= *zero) { + ret_val = 0; + return ret_val; + } + + posinf *= posinf; + if (posinf <= *one) { + ret_val = 0; + return ret_val; + } + + +/* Return if we were only asked to check infinity arithmetic */ + + if (*ispec == 0) { + return ret_val; + } + + nan1 = posinf + neginf; + + nan2 = posinf / neginf; + + nan3 = posinf / posinf; + + nan4 = posinf * *zero; + + nan5 = neginf * negzro; + + nan6 = nan5 * 0.f; + + if (nan1 == nan1) { + ret_val = 0; + return ret_val; + } + + if (nan2 == nan2) { + ret_val = 0; + return ret_val; + } + + if (nan3 == nan3) { + ret_val = 0; + return ret_val; + } + + if (nan4 == nan4) { + ret_val = 0; + return ret_val; + } + + if (nan5 == nan5) { + ret_val = 0; + return ret_val; + } + + if (nan6 == nan6) { + ret_val = 0; + return ret_val; + } + + return ret_val; +} /* ieeeck_ */ + +integer ilaenv_(integer *ispec, char *name__, char *opts, integer *n1, + integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen + opts_len) +{ + /* System generated locals */ + integer ret_val; + + /* Builtin functions */ + /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen); + integer s_cmp(char *, char *, ftnlen, ftnlen); + + /* Local variables */ + static integer i__; + static char c1[1], c2[2], c3[3], c4[2]; + static integer ic, nb, iz, nx; + static logical cname, sname; + static integer nbmin; + extern integer ieeeck_(integer *, real *, real *); + static char subnam[6]; + + +/* + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1999 + + + Purpose + ======= + + ILAENV is called from the LAPACK routines to choose problem-dependent + parameters for the local environment. See ISPEC for a description of + the parameters. + + This version provides a set of parameters which should give good, + but not optimal, performance on many of the currently available + computers. Users are encouraged to modify this subroutine to set + the tuning parameters for their particular machine using the option + and problem size information in the arguments. + + This routine will not function correctly if it is converted to all + lower case. Converting it to all upper case is allowed. + + Arguments + ========= + + ISPEC (input) INTEGER + Specifies the parameter to be returned as the value of + ILAENV. + = 1: the optimal blocksize; if this value is 1, an unblocked + algorithm will give the best performance. + = 2: the minimum block size for which the block routine + should be used; if the usable block size is less than + this value, an unblocked routine should be used. + = 3: the crossover point (in a block routine, for N less + than this value, an unblocked routine should be used) + = 4: the number of shifts, used in the nonsymmetric + eigenvalue routines + = 5: the minimum column dimension for blocking to be used; + rectangular blocks must have dimension at least k by m, + where k is given by ILAENV(2,...) and m by ILAENV(5,...) + = 6: the crossover point for the SVD (when reducing an m by n + matrix to bidiagonal form, if max(m,n)/min(m,n) exceeds + this value, a QR factorization is used first to reduce + the matrix to a triangular form.) + = 7: the number of processors + = 8: the crossover point for the multishift QR and QZ methods + for nonsymmetric eigenvalue problems. + = 9: maximum size of the subproblems at the bottom of the + computation tree in the divide-and-conquer algorithm + (used by xGELSD and xGESDD) + =10: ieee NaN arithmetic can be trusted not to trap + =11: infinity arithmetic can be trusted not to trap + + NAME (input) CHARACTER*(*) + The name of the calling subroutine, in either upper case or + lower case. + + OPTS (input) CHARACTER*(*) + The character options to the subroutine NAME, concatenated + into a single character string. For example, UPLO = 'U', + TRANS = 'T', and DIAG = 'N' for a triangular routine would + be specified as OPTS = 'UTN'. + + N1 (input) INTEGER + N2 (input) INTEGER + N3 (input) INTEGER + N4 (input) INTEGER + Problem dimensions for the subroutine NAME; these may not all + be required. + + (ILAENV) (output) INTEGER + >= 0: the value of the parameter specified by ISPEC + < 0: if ILAENV = -k, the k-th argument had an illegal value. + + Further Details + =============== + + The following conventions have been used when calling ILAENV from the + LAPACK routines: + 1) OPTS is a concatenation of all of the character options to + subroutine NAME, in the same order that they appear in the + argument list for NAME, even if they are not used in determining + the value of the parameter specified by ISPEC. + 2) The problem dimensions N1, N2, N3, N4 are specified in the order + that they appear in the argument list for NAME. N1 is used + first, N2 second, and so on, and unused problem dimensions are + passed a value of -1. + 3) The parameter value returned by ILAENV is checked for validity in + the calling subroutine. For example, ILAENV is used to retrieve + the optimal blocksize for STRTRI as follows: + + NB = ILAENV( 1, 'STRTRI', UPLO // DIAG, N, -1, -1, -1 ) + IF( NB.LE.1 ) NB = MAX( 1, N ) + + ===================================================================== +*/ + + + switch (*ispec) { + case 1: goto L100; + case 2: goto L100; + case 3: goto L100; + case 4: goto L400; + case 5: goto L500; + case 6: goto L600; + case 7: goto L700; + case 8: goto L800; + case 9: goto L900; + case 10: goto L1000; + case 11: goto L1100; + } + +/* Invalid value for ISPEC */ + + ret_val = -1; + return ret_val; + +L100: + +/* Convert NAME to upper case if the first character is lower case. */ + + ret_val = 1; + s_copy(subnam, name__, (ftnlen)6, name_len); + ic = *(unsigned char *)subnam; + iz = 'Z'; + if (iz == 90 || iz == 122) { + +/* ASCII character set */ + + if (ic >= 97 && ic <= 122) { + *(unsigned char *)subnam = (char) (ic - 32); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 97 && ic <= 122) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32); + } +/* L10: */ + } + } + + } else if (iz == 233 || iz == 169) { + +/* EBCDIC character set */ + + if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= 162 && + ic <= 169) { + *(unsigned char *)subnam = (char) (ic + 64); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 129 && ic <= 137 || ic >= 145 && ic <= 153 || ic >= + 162 && ic <= 169) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic + 64); + } +/* L20: */ + } + } + + } else if (iz == 218 || iz == 250) { + +/* Prime machines: ASCII+128 */ + + if (ic >= 225 && ic <= 250) { + *(unsigned char *)subnam = (char) (ic - 32); + for (i__ = 2; i__ <= 6; ++i__) { + ic = *(unsigned char *)&subnam[i__ - 1]; + if (ic >= 225 && ic <= 250) { + *(unsigned char *)&subnam[i__ - 1] = (char) (ic - 32); + } +/* L30: */ + } + } + } + + *(unsigned char *)c1 = *(unsigned char *)subnam; + sname = *(unsigned char *)c1 == 'S' || *(unsigned char *)c1 == 'D'; + cname = *(unsigned char *)c1 == 'C' || *(unsigned char *)c1 == 'Z'; + if (! (cname || sname)) { + return ret_val; + } + s_copy(c2, subnam + 1, (ftnlen)2, (ftnlen)2); + s_copy(c3, subnam + 3, (ftnlen)3, (ftnlen)3); + s_copy(c4, c3 + 1, (ftnlen)2, (ftnlen)2); + + switch (*ispec) { + case 1: goto L110; + case 2: goto L200; + case 3: goto L300; + } + +L110: + +/* + ISPEC = 1: block size + + In these examples, separate code is provided for setting NB for + real and complex. We assume that NB will take the same value in + single or double precision. +*/ + + nb = 1; + + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } else if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, + "RQF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen) + 3, (ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) + == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 32; + } else { + nb = 32; + } + } else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "PO", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nb = 32; + } else if (sname && s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } else if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nb = 32; + } else if (s_cmp(c3, "GST", (ftnlen)3, (ftnlen)3) == 0) { + nb = 64; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nb = 32; + } + } + } else if (s_cmp(c2, "GB", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + if (*n4 <= 64) { + nb = 1; + } else { + nb = 32; + } + } else { + if (*n4 <= 64) { + nb = 1; + } else { + nb = 32; + } + } + } + } else if (s_cmp(c2, "PB", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + if (*n2 <= 64) { + nb = 1; + } else { + nb = 32; + } + } else { + if (*n2 <= 64) { + nb = 1; + } else { + nb = 32; + } + } + } + } else if (s_cmp(c2, "TR", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (s_cmp(c2, "LA", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "UUM", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nb = 64; + } else { + nb = 64; + } + } + } else if (sname && s_cmp(c2, "ST", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "EBZ", (ftnlen)3, (ftnlen)3) == 0) { + nb = 1; + } + } + ret_val = nb; + return ret_val; + +L200: + +/* ISPEC = 2: minimum block size */ + + nbmin = 2; + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", ( + ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, ( + ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0) + { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } else if (s_cmp(c3, "TRI", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 2; + } else { + nbmin = 2; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRF", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nbmin = 8; + } else { + nbmin = 8; + } + } else if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nbmin = 2; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nbmin = 2; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } else if (*(unsigned char *)c3 == 'M') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nbmin = 2; + } + } + } + ret_val = nbmin; + return ret_val; + +L300: + +/* ISPEC = 3: crossover point */ + + nx = 0; + if (s_cmp(c2, "GE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "QRF", (ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "RQF", ( + ftnlen)3, (ftnlen)3) == 0 || s_cmp(c3, "LQF", (ftnlen)3, ( + ftnlen)3) == 0 || s_cmp(c3, "QLF", (ftnlen)3, (ftnlen)3) == 0) + { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } else if (s_cmp(c3, "HRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } else if (s_cmp(c3, "BRD", (ftnlen)3, (ftnlen)3) == 0) { + if (sname) { + nx = 128; + } else { + nx = 128; + } + } + } else if (s_cmp(c2, "SY", (ftnlen)2, (ftnlen)2) == 0) { + if (sname && s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nx = 32; + } + } else if (cname && s_cmp(c2, "HE", (ftnlen)2, (ftnlen)2) == 0) { + if (s_cmp(c3, "TRD", (ftnlen)3, (ftnlen)3) == 0) { + nx = 32; + } + } else if (sname && s_cmp(c2, "OR", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nx = 128; + } + } + } else if (cname && s_cmp(c2, "UN", (ftnlen)2, (ftnlen)2) == 0) { + if (*(unsigned char *)c3 == 'G') { + if (s_cmp(c4, "QR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "RQ", + (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "LQ", (ftnlen)2, ( + ftnlen)2) == 0 || s_cmp(c4, "QL", (ftnlen)2, (ftnlen)2) == + 0 || s_cmp(c4, "HR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp( + c4, "TR", (ftnlen)2, (ftnlen)2) == 0 || s_cmp(c4, "BR", ( + ftnlen)2, (ftnlen)2) == 0) { + nx = 128; + } + } + } + ret_val = nx; + return ret_val; + +L400: + +/* ISPEC = 4: number of shifts (used by xHSEQR) */ + + ret_val = 6; + return ret_val; + +L500: + +/* ISPEC = 5: minimum column dimension (not used) */ + + ret_val = 2; + return ret_val; + +L600: + +/* ISPEC = 6: crossover point for SVD (used by xGELSS and xGESVD) */ + + ret_val = (integer) ((real) min(*n1,*n2) * 1.6f); + return ret_val; + +L700: + +/* ISPEC = 7: number of processors (not used) */ + + ret_val = 1; + return ret_val; + +L800: + +/* ISPEC = 8: crossover point for multishift (used by xHSEQR) */ + + ret_val = 50; + return ret_val; + +L900: + +/* + ISPEC = 9: maximum size of the subproblems at the bottom of the + computation tree in the divide-and-conquer algorithm + (used by xGELSD and xGESDD) +*/ + + ret_val = 25; + return ret_val; + +L1000: + +/* + ISPEC = 10: ieee NaN arithmetic can be trusted not to trap + + ILAENV = 0 +*/ + ret_val = 1; + if (ret_val == 1) { + ret_val = ieeeck_(&c__0, &c_b163, &c_b164); + } + return ret_val; + +L1100: + +/* + ISPEC = 11: infinity arithmetic can be trusted not to trap + + ILAENV = 0 +*/ + ret_val = 1; + if (ret_val == 1) { + ret_val = ieeeck_(&c__1, &c_b163, &c_b164); + } + return ret_val; + +/* End of ILAENV */ + +} /* ilaenv_ */ + +/* Subroutine */ int sposv_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + extern /* Subroutine */ int xerbla_(char *, integer *), spotrf_( + char *, integer *, real *, integer *, integer *), spotrs_( + char *, integer *, integer *, real *, integer *, real *, integer * + , integer *); + + +/* + -- LAPACK driver routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 + + + Purpose + ======= + + SPOSV computes the solution to a real system of linear equations + A * X = B, + where A is an N-by-N symmetric positive definite matrix and X and B + are N-by-NRHS matrices. + + The Cholesky decomposition is used to factor A as + A = U**T* U, if UPLO = 'U', or + A = L * L**T, if UPLO = 'L', + where U is an upper triangular matrix and L is a lower triangular + matrix. The factored form of A is then used to solve the system of + equations A * X = B. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The number of linear equations, i.e., the order of the + matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U**T*U or A = L*L**T. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + B (input/output) REAL array, dimension (LDB,NRHS) + On entry, the N-by-NRHS right hand side matrix B. + On exit, if INFO = 0, the N-by-NRHS solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i of A is not + positive definite, so the factorization could not be + completed, and the solution has not been computed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOSV ", &i__1); + return 0; + } + +/* Compute the Cholesky factorization A = U'*U or A = L*L'. */ + + spotrf_(uplo, n, &a[a_offset], lda, info); + if (*info == 0) { + +/* Solve the system A*X = B, overwriting B with X. */ + + spotrs_(uplo, n, nrhs, &a[a_offset], lda, &b[b_offset], ldb, info); + + } + return 0; + +/* End of SPOSV */ + +} /* sposv_ */ + +/* Subroutine */ int spotf2_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3; + real r__1; + + /* Builtin functions */ + double sqrt(doublereal); + + /* Local variables */ + static integer j; + static real ajj; + extern doublereal sdot_(integer *, real *, integer *, real *, integer *); + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sscal_(integer *, real *, real *, integer *), + sgemv_(char *, integer *, integer *, real *, real *, integer *, + real *, integer *, real *, real *, integer *); + static logical upper; + extern /* Subroutine */ int xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 + + + Purpose + ======= + + SPOTF2 computes the Cholesky factorization of a real symmetric + positive definite matrix A. + + The factorization has the form + A = U' * U , if UPLO = 'U', or + A = L * L', if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the unblocked version of the algorithm, calling Level 2 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + Specifies whether the upper or lower triangular part of the + symmetric matrix A is stored. + = 'U': Upper triangular + = 'L': Lower triangular + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + n by n upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading n by n lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U'*U or A = L*L'. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -k, the k-th argument had an illegal value + > 0: if INFO = k, the leading minor of order k is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTF2", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute U(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - sdot_(&i__2, &a[j * a_dim1 + 1], &c__1, + &a[j * a_dim1 + 1], &c__1); + if (ajj <= 0.f) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of row J. */ + + if (j < *n) { + i__2 = j - 1; + i__3 = *n - j; + sgemv_("Transpose", &i__2, &i__3, &c_b181, &a[(j + 1) * + a_dim1 + 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b164, + &a[j + (j + 1) * a_dim1], lda); + i__2 = *n - j; + r__1 = 1.f / ajj; + sscal_(&i__2, &r__1, &a[j + (j + 1) * a_dim1], lda); + } +/* L10: */ + } + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + +/* Compute L(J,J) and test for non-positive-definiteness. */ + + i__2 = j - 1; + ajj = a[j + j * a_dim1] - sdot_(&i__2, &a[j + a_dim1], lda, &a[j + + a_dim1], lda); + if (ajj <= 0.f) { + a[j + j * a_dim1] = ajj; + goto L30; + } + ajj = sqrt(ajj); + a[j + j * a_dim1] = ajj; + +/* Compute elements J+1:N of column J. */ + + if (j < *n) { + i__2 = *n - j; + i__3 = j - 1; + sgemv_("No transpose", &i__2, &i__3, &c_b181, &a[j + 1 + + a_dim1], lda, &a[j + a_dim1], lda, &c_b164, &a[j + 1 + + j * a_dim1], &c__1); + i__2 = *n - j; + r__1 = 1.f / ajj; + sscal_(&i__2, &r__1, &a[j + 1 + j * a_dim1], &c__1); + } +/* L20: */ + } + } + goto L40; + +L30: + *info = j; + +L40: + return 0; + +/* End of SPOTF2 */ + +} /* spotf2_ */ + +/* Subroutine */ int spotrf_(char *uplo, integer *n, real *a, integer *lda, + integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + static integer j, jb, nb; + extern logical lsame_(char *, char *); + extern /* Subroutine */ int sgemm_(char *, char *, integer *, integer *, + integer *, real *, real *, integer *, real *, integer *, real *, + real *, integer *); + static logical upper; + extern /* Subroutine */ int strsm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), ssyrk_(char *, char *, integer + *, integer *, real *, real *, integer *, real *, real *, integer * + ), spotf2_(char *, integer *, real *, integer *, + integer *), xerbla_(char *, integer *); + extern integer ilaenv_(integer *, char *, char *, integer *, integer *, + integer *, integer *, ftnlen, ftnlen); + + +/* + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 + + + Purpose + ======= + + SPOTRF computes the Cholesky factorization of a real symmetric + positive definite matrix A. + + The factorization has the form + A = U**T * U, if UPLO = 'U', or + A = L * L**T, if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + + This is the block version of the algorithm, calling Level 3 BLAS. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + A (input/output) REAL array, dimension (LDA,N) + On entry, the symmetric matrix A. If UPLO = 'U', the leading + N-by-N upper triangular part of A contains the upper + triangular part of the matrix A, and the strictly lower + triangular part of A is not referenced. If UPLO = 'L', the + leading N-by-N lower triangular part of A contains the lower + triangular part of the matrix A, and the strictly upper + triangular part of A is not referenced. + + On exit, if INFO = 0, the factor U or L from the Cholesky + factorization A = U**T*U or A = L*L**T. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i is not + positive definite, and the factorization could not be + completed. + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*lda < max(1,*n)) { + *info = -4; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTRF", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0) { + return 0; + } + +/* Determine the block size for this environment. */ + + nb = ilaenv_(&c__1, "SPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, ( + ftnlen)1); + if (nb <= 1 || nb >= *n) { + +/* Use unblocked code. */ + + spotf2_(uplo, n, &a[a_offset], lda, info); + } else { + +/* Use blocked code. */ + + if (upper) { + +/* Compute the Cholesky factorization A = U'*U. */ + + i__1 = *n; + i__2 = nb; + for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + ssyrk_("Upper", "Transpose", &jb, &i__3, &c_b181, &a[j * + a_dim1 + 1], lda, &c_b164, &a[j + j * a_dim1], lda); + spotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block row. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + sgemm_("Transpose", "No transpose", &jb, &i__3, &i__4, & + c_b181, &a[j * a_dim1 + 1], lda, &a[(j + jb) * + a_dim1 + 1], lda, &c_b164, &a[j + (j + jb) * + a_dim1], lda); + i__3 = *n - j - jb + 1; + strsm_("Left", "Upper", "Transpose", "Non-unit", &jb, & + i__3, &c_b164, &a[j + j * a_dim1], lda, &a[j + (j + + jb) * a_dim1], lda); + } +/* L10: */ + } + + } else { + +/* Compute the Cholesky factorization A = L*L'. */ + + i__2 = *n; + i__1 = nb; + for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) { + +/* + Update and factorize the current diagonal block and test + for non-positive-definiteness. + + Computing MIN +*/ + i__3 = nb, i__4 = *n - j + 1; + jb = min(i__3,i__4); + i__3 = j - 1; + ssyrk_("Lower", "No transpose", &jb, &i__3, &c_b181, &a[j + + a_dim1], lda, &c_b164, &a[j + j * a_dim1], lda); + spotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info); + if (*info != 0) { + goto L30; + } + if (j + jb <= *n) { + +/* Compute the current block column. */ + + i__3 = *n - j - jb + 1; + i__4 = j - 1; + sgemm_("No transpose", "Transpose", &i__3, &jb, &i__4, & + c_b181, &a[j + jb + a_dim1], lda, &a[j + a_dim1], + lda, &c_b164, &a[j + jb + j * a_dim1], lda); + i__3 = *n - j - jb + 1; + strsm_("Right", "Lower", "Transpose", "Non-unit", &i__3, & + jb, &c_b164, &a[j + j * a_dim1], lda, &a[j + jb + + j * a_dim1], lda); + } +/* L20: */ + } + } + } + goto L40; + +L30: + *info = *info + j - 1; + +L40: + return 0; + +/* End of SPOTRF */ + +} /* spotrf_ */ + +/* Subroutine */ int spotrs_(char *uplo, integer *n, integer *nrhs, real *a, + integer *lda, real *b, integer *ldb, integer *info) +{ + /* System generated locals */ + integer a_dim1, a_offset, b_dim1, b_offset, i__1; + + /* Local variables */ + extern logical lsame_(char *, char *); + static logical upper; + extern /* Subroutine */ int strsm_(char *, char *, char *, char *, + integer *, integer *, real *, real *, integer *, real *, integer * + ), xerbla_(char *, integer *); + + +/* + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 + + + Purpose + ======= + + SPOTRS solves a system of linear equations A*X = B with a symmetric + positive definite matrix A using the Cholesky factorization + A = U**T*U or A = L*L**T computed by SPOTRF. + + Arguments + ========= + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + NRHS (input) INTEGER + The number of right hand sides, i.e., the number of columns + of the matrix B. NRHS >= 0. + + A (input) REAL array, dimension (LDA,N) + The triangular factor U or L from the Cholesky factorization + A = U**T*U or A = L*L**T, as computed by SPOTRF. + + LDA (input) INTEGER + The leading dimension of the array A. LDA >= max(1,N). + + B (input/output) REAL array, dimension (LDB,NRHS) + On entry, the right hand side matrix B. + On exit, the solution matrix X. + + LDB (input) INTEGER + The leading dimension of the array B. LDB >= max(1,N). + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + + ===================================================================== + + + Test the input parameters. +*/ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + b_dim1 = *ldb; + b_offset = 1 + b_dim1; + b -= b_offset; + + /* Function Body */ + *info = 0; + upper = lsame_(uplo, "U"); + if (! upper && ! lsame_(uplo, "L")) { + *info = -1; + } else if (*n < 0) { + *info = -2; + } else if (*nrhs < 0) { + *info = -3; + } else if (*lda < max(1,*n)) { + *info = -5; + } else if (*ldb < max(1,*n)) { + *info = -7; + } + if (*info != 0) { + i__1 = -(*info); + xerbla_("SPOTRS", &i__1); + return 0; + } + +/* Quick return if possible */ + + if (*n == 0 || *nrhs == 0) { + return 0; + } + + if (upper) { + +/* + Solve A*X = B where A = U'*U. + + Solve U'*X = B, overwriting B with X. +*/ + + strsm_("Left", "Upper", "Transpose", "Non-unit", n, nrhs, &c_b164, &a[ + a_offset], lda, &b[b_offset], ldb); + +/* Solve U*X = B, overwriting B with X. */ + + strsm_("Left", "Upper", "No transpose", "Non-unit", n, nrhs, &c_b164, + &a[a_offset], lda, &b[b_offset], ldb); + } else { + +/* + Solve A*X = B where A = L*L'. + + Solve L*X = B, overwriting B with X. +*/ + + strsm_("Left", "Lower", "No transpose", "Non-unit", n, nrhs, &c_b164, + &a[a_offset], lda, &b[b_offset], ldb); + +/* Solve L'*X = B, overwriting B with X. */ + + strsm_("Left", "Lower", "Transpose", "Non-unit", n, nrhs, &c_b164, &a[ + a_offset], lda, &b[b_offset], ldb); + } + + return 0; + +/* End of SPOTRS */ + +} /* spotrs_ */ + diff --git a/media/sphinxbase/src/libsphinxbase/util/strfuncs.c b/media/sphinxbase/src/libsphinxbase/util/strfuncs.c new file mode 100644 index 000000000..4d2d72ffc --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/strfuncs.c @@ -0,0 +1,194 @@ +/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* ==================================================================== + * Copyright (c) 1999-2006 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ +/* + * strfuncs.c -- String functions + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdarg.h> + +#include "sphinxbase/ckd_alloc.h" +#include "sphinxbase/strfuncs.h" + +/* Defined in dtoa.c */ +double sb_strtod(const char *s00, char **se); + +double +atof_c(char const *str) +{ + return sb_strtod(str, NULL); +} + +/* Locale-independent isspace to avoid different incompatibilities */ +static int +isspace_c(char ch) +{ + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + return 1; + return 0; +} + +char * +string_join(const char *base, ...) +{ + va_list args; + size_t len; + const char *c; + char *out; + + va_start(args, base); + len = strlen(base); + while ((c = va_arg(args, const char *)) != NULL) { + len += strlen(c); + } + len++; + va_end(args); + + out = ckd_calloc(len, 1); + va_start(args, base); + strcpy(out, base); + while ((c = va_arg(args, const char *)) != NULL) { + strcat(out, c); + } + va_end(args); + + return out; +} + +char * +string_trim(char *string, enum string_edge_e which) +{ + size_t len; + + len = strlen(string); + if (which == STRING_START || which == STRING_BOTH) { + size_t sub = strspn(string, " \t\n\r\f"); + if (sub > 0) { + memmove(string, string + sub, len + 1 - sub); + len -= sub; + } + } + if (which == STRING_END || which == STRING_BOTH) { + long sub = len; + while (--sub >= 0) + if (strchr(" \t\n\r\f", string[sub]) == NULL) + break; + if (sub == -1) + string[0] = '\0'; + else + string[sub+1] = '\0'; + } + return string; +} + +int32 +str2words(char *line, char **ptr, int32 max_ptr) +{ + int32 i, n; + + n = 0; /* #words found so far */ + i = 0; /* For scanning through the input string */ + while (1) { + /* Skip whitespace before next word */ + while (line[i] && isspace_c(line[i])) + ++i; + if (!line[i]) + break; + + if (ptr != NULL && n >= max_ptr) { + /* + * Pointer array size insufficient. Restore NULL chars inserted so far + * to space chars. Not a perfect restoration, but better than nothing. + */ + for (; i >= 0; --i) + if (line[i] == '\0') + line[i] = ' '; + + return -1; + } + + /* Scan to end of word */ + if (ptr != NULL) + ptr[n] = line + i; + ++n; + while (line[i] && !isspace_c(line[i])) + ++i; + if (!line[i]) + break; + if (ptr != NULL) + line[i] = '\0'; + ++i; + } + + return n; +} + + +int32 +nextword(char *line, const char *delim, char **word, char *delimfound) +{ + const char *d; + char *w; + + /* Skip past any preceding delimiters */ + for (w = line; *w; w++) { + for (d = delim; *d && (*d != *w); d++); + if (!*d) + break; + } + if (!*w) + return -1; + + *word = w; /* Beginning of word */ + + /* Skip until first delimiter char */ + for (w++; *w; w++) { + for (d = delim; *d && (*d != *w); d++); + if (*d) + break; + } + + /* Replace delimiter with NULL char, but return the original first */ + *delimfound = *w; + *w = '\0'; + + return (w - *word); +} diff --git a/media/sphinxbase/src/libsphinxbase/util/utf8.c b/media/sphinxbase/src/libsphinxbase/util/utf8.c new file mode 100644 index 000000000..bd763da3f --- /dev/null +++ b/media/sphinxbase/src/libsphinxbase/util/utf8.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> */ +/* See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. */ + +/* Slightly modified to use Sphinx types and remove explicit inline. */ + +#include "sphinxbase/prim_type.h" + +#define UTF8_ACCEPT 0 +#define UTF8_REJECT 1 + +static const uint8 utf8d[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00..1f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20..3f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40..5f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60..7f */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, /* 80..9f */ + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* a0..bf */ + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* c0..df */ + 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, /* e0..ef */ + 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, /* f0..ff */ + 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, /* s0..s0 */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, /* s1..s2 */ + 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, /* s3..s4 */ + 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, /* s5..s6 */ + 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* s7..s8 */ +}; + +uint32 +utf8_decode(uint32 *state, uint32 *codep, uint32 byte) { + uint32 type = utf8d[byte]; + + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); + + *state = utf8d[256 + *state*16 + type]; + return *state; +} + +/* CMU code starts here. */ +/* ==================================================================== + * Copyright (c) 2009 Carnegie Mellon University. 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 work was supported in part by funding from the Defense Advanced + * Research Projects Agency and the National Science Foundation of the + * United States of America, and the CMU Sphinx Speech Consortium. + * + * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND + * ANY EXPRESSED 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 CARNEGIE MELLON UNIVERSITY + * NOR ITS EMPLOYEES 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. + * + * ==================================================================== + * + */ |