qse/ase/awk/misc.c

906 lines
18 KiB
C
Raw Normal View History

2006-04-04 16:03:14 +00:00
/*
2007-03-06 14:58:00 +00:00
* $Id: misc.c,v 1.53 2007-03-06 14:51:52 bacon Exp $
2007-02-03 10:47:41 +00:00
*
* {License}
2006-04-04 16:03:14 +00:00
*/
2006-10-24 04:10:12 +00:00
#include <ase/awk/awk_i.h>
2006-04-04 16:03:14 +00:00
2006-11-28 04:30:57 +00:00
void* ase_awk_malloc (ase_awk_t* awk, ase_size_t size)
{
return ASE_AWK_MALLOC (awk, size);
}
void ase_awk_free (ase_awk_t* awk, void* ptr)
{
2006-11-28 11:28:38 +00:00
ASE_AWK_FREE (awk, ptr);
2006-11-28 04:30:57 +00:00
}
2006-10-24 04:10:12 +00:00
ase_long_t ase_awk_strxtolong (
ase_awk_t* awk, const ase_char_t* str, ase_size_t len,
int base, const ase_char_t** endptr)
2006-04-04 16:03:14 +00:00
{
2006-10-24 04:10:12 +00:00
ase_long_t n = 0;
const ase_char_t* p;
const ase_char_t* end;
ase_size_t rem;
2006-04-04 16:45:21 +00:00
int digit, negative = 0;
2006-04-04 16:03:14 +00:00
2007-03-06 14:58:00 +00:00
ASE_ASSERT (base < 37);
2006-04-04 16:03:14 +00:00
2006-10-05 14:20:57 +00:00
p = str;
2006-10-06 03:37:40 +00:00
end = str + len;
2006-10-05 14:20:57 +00:00
2006-10-06 03:37:40 +00:00
/* strip off leading spaces */
2006-10-24 04:10:12 +00:00
/*while (ASE_AWK_ISSPACE(awk,*p)) p++;*/
2006-04-04 16:03:14 +00:00
2006-10-06 03:37:40 +00:00
/* check for a sign */
2006-10-24 04:10:12 +00:00
/*while (*p != ASE_T('\0')) */
2006-10-05 14:20:57 +00:00
while (p < end)
2006-04-04 16:03:14 +00:00
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('-'))
2006-04-04 16:03:14 +00:00
{
2006-04-04 16:45:21 +00:00
negative = ~negative;
2006-04-04 16:03:14 +00:00
p++;
}
2006-10-24 04:10:12 +00:00
else if (*p == ASE_T('+')) p++;
2006-04-04 16:03:14 +00:00
else break;
}
2006-10-06 03:37:40 +00:00
/* check for a binary/octal/hexadecimal notation */
2006-10-05 14:20:57 +00:00
rem = end - p;
2006-04-04 16:03:14 +00:00
if (base == 0)
{
2006-10-24 04:10:12 +00:00
if (rem >= 1 && *p == ASE_T('0'))
2006-04-04 16:03:14 +00:00
{
p++;
2006-10-05 14:20:57 +00:00
if (rem == 1) base = 8;
2006-10-24 04:10:12 +00:00
else if (*p == ASE_T('x') || *p == ASE_T('X'))
2006-04-04 16:03:14 +00:00
{
p++; base = 16;
}
2006-10-24 04:10:12 +00:00
else if (*p == ASE_T('b') || *p == ASE_T('B'))
2006-04-04 16:22:01 +00:00
{
p++; base = 2;
}
2006-04-04 16:03:14 +00:00
else base = 8;
}
else base = 10;
}
2006-10-05 14:20:57 +00:00
else if (rem >= 2 && base == 16)
2006-04-04 16:03:14 +00:00
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('0') &&
(*(p+1) == ASE_T('x') || *(p+1) == ASE_T('X'))) p += 2;
2006-04-04 16:22:01 +00:00
}
2006-10-05 14:20:57 +00:00
else if (rem >= 2 && base == 2)
2006-04-04 16:22:01 +00:00
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('0') &&
(*(p+1) == ASE_T('b') || *(p+1) == ASE_T('B'))) p += 2;
2006-04-04 16:03:14 +00:00
}
2006-10-06 03:37:40 +00:00
/* process the digits */
2006-10-24 04:10:12 +00:00
/*while (*p != ASE_T('\0'))*/
2006-10-05 14:20:57 +00:00
while (p < end)
2006-04-04 16:03:14 +00:00
{
2006-10-24 04:10:12 +00:00
if (*p >= ASE_T('0') && *p <= ASE_T('9'))
digit = *p - ASE_T('0');
else if (*p >= ASE_T('A') && *p <= ASE_T('Z'))
digit = *p - ASE_T('A') + 10;
else if (*p >= ASE_T('a') && *p <= ASE_T('z'))
digit = *p - ASE_T('a') + 10;
2006-04-04 16:03:14 +00:00
else break;
if (digit >= base) break;
n = n * base + digit;
p++;
}
2006-10-24 04:10:12 +00:00
if (endptr != ASE_NULL) *endptr = p;
2006-04-04 16:45:21 +00:00
return (negative)? -n: n;
2006-04-04 16:03:14 +00:00
}
2006-04-04 16:45:21 +00:00
/*
2006-10-24 04:10:12 +00:00
* ase_awk_strtoreal is almost a replica of strtod.
2006-04-04 16:45:21 +00:00
*
* strtod.c --
*
* Source code for the "strtod" library procedure.
*
* Copyright (c) 1988-1993 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
2006-10-22 12:39:30 +00:00
* express or implied warranty.
2006-04-04 16:45:21 +00:00
*/
2006-10-22 12:39:30 +00:00
#define MAX_EXPONENT 511
2006-04-04 16:45:21 +00:00
2006-10-24 04:10:12 +00:00
ase_real_t ase_awk_strtoreal (ase_awk_t* awk, const ase_char_t* str)
2006-04-04 16:03:14 +00:00
{
2006-04-04 16:45:21 +00:00
/*
* Table giving binary powers of 10. Entry is 10^2^i.
2006-10-22 12:39:30 +00:00
* Used to convert decimal exponents into floating-point numbers.
2006-04-04 16:45:21 +00:00
*/
2006-10-24 04:10:12 +00:00
static ase_real_t powers_of_10[] =
2006-10-05 14:20:57 +00:00
{
2006-04-04 16:45:21 +00:00
10., 100., 1.0e4, 1.0e8, 1.0e16,
1.0e32, 1.0e64, 1.0e128, 1.0e256
};
2006-10-24 04:10:12 +00:00
ase_real_t fraction, dbl_exp, * d;
const ase_char_t* p;
ase_cint_t c;
2006-10-22 12:39:30 +00:00
int exp = 0; /* Esseonent read from "EX" field */
2006-04-04 16:45:21 +00:00
/*
2006-10-22 11:34:53 +00:00
* Esseonent that derives from the fractional part. Under normal
2006-04-04 16:45:21 +00:00
* circumstatnces, it is the negative of the number of digits in F.
* However, if I is very long, the last digits of I get dropped
2006-10-22 12:39:30 +00:00
* (otherwise a long I with a large negative exponent could cause an
* unnecessary overflow on I alone). In this case, frac_exp is
2006-04-04 16:45:21 +00:00
* incremented one for each dropped digit.
*/
2006-10-22 12:39:30 +00:00
int frac_exp;
2006-10-05 14:20:57 +00:00
int mant_size; /* Number of digits in mantissa. */
int dec_pt; /* Number of mantissa digits BEFORE decimal point */
2006-10-24 04:10:12 +00:00
const ase_char_t *pexp; /* Temporarily holds location of exponent in string */
2006-10-22 12:39:30 +00:00
int negative = 0, exp_negative = 0;
2006-04-04 16:45:21 +00:00
p = str;
2006-10-06 03:37:40 +00:00
/* strip off leading blanks */
2006-10-24 04:10:12 +00:00
/*while (ASE_AWK_ISSPACE(awk,*p)) p++;*/
2006-04-04 16:45:21 +00:00
2006-10-06 03:37:40 +00:00
/* check for a sign */
2006-10-24 04:10:12 +00:00
while (*p != ASE_T('\0'))
2006-04-04 16:45:21 +00:00
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('-'))
2006-04-04 16:45:21 +00:00
{
2006-10-06 03:37:40 +00:00
negative = ~negative;
2006-04-04 16:45:21 +00:00
p++;
}
2006-10-24 04:10:12 +00:00
else if (*p == ASE_T('+')) p++;
2006-04-04 16:45:21 +00:00
else break;
}
2006-04-10 14:53:48 +00:00
/* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point. */
2006-10-05 14:20:57 +00:00
dec_pt = -1;
for (mant_size = 0; ; mant_size++)
{
2006-04-04 16:45:21 +00:00
c = *p;
2006-10-24 04:10:12 +00:00
if (!ASE_AWK_ISDIGIT (awk, c))
2006-10-05 14:20:57 +00:00
{
2006-10-24 04:10:12 +00:00
if ((c != ASE_T('.')) || (dec_pt >= 0)) break;
2006-10-05 14:20:57 +00:00
dec_pt = mant_size;
2006-04-04 16:45:21 +00:00
}
p++;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
2006-10-22 12:39:30 +00:00
pexp = p;
2006-10-05 14:20:57 +00:00
p -= mant_size;
if (dec_pt < 0)
2006-04-04 16:45:21 +00:00
{
2006-10-05 14:20:57 +00:00
dec_pt = mant_size;
2006-04-04 16:45:21 +00:00
}
else
{
2006-10-05 14:20:57 +00:00
mant_size--; /* One of the digits was the point */
2006-04-04 16:45:21 +00:00
}
2006-04-26 15:53:17 +00:00
2006-10-05 14:20:57 +00:00
if (mant_size > 18)
2006-04-04 16:45:21 +00:00
{
2006-10-22 12:39:30 +00:00
frac_exp = dec_pt - 18;
2006-10-05 14:20:57 +00:00
mant_size = 18;
2006-04-04 16:45:21 +00:00
}
else
{
2006-10-22 12:39:30 +00:00
frac_exp = dec_pt - mant_size;
2006-04-04 16:45:21 +00:00
}
2006-10-05 14:20:57 +00:00
if (mant_size == 0)
2006-04-04 16:45:21 +00:00
{
fraction = 0.0;
2006-04-26 15:53:17 +00:00
/*p = str;*/
2006-10-22 12:39:30 +00:00
p = pexp;
2006-04-04 16:45:21 +00:00
goto done;
}
else
{
int frac1, frac2;
frac1 = 0;
2006-10-05 14:20:57 +00:00
for ( ; mant_size > 9; mant_size--)
2006-04-04 16:45:21 +00:00
{
c = *p;
p++;
2006-10-24 04:10:12 +00:00
if (c == ASE_T('.'))
2006-04-04 16:45:21 +00:00
{
c = *p;
p++;
}
2006-10-24 04:10:12 +00:00
frac1 = 10 * frac1 + (c - ASE_T('0'));
2006-04-04 16:45:21 +00:00
}
frac2 = 0;
2006-10-05 14:20:57 +00:00
for (; mant_size > 0; mant_size--) {
2006-04-04 16:45:21 +00:00
c = *p;
p++;
2006-10-24 04:10:12 +00:00
if (c == ASE_T('.'))
2006-04-04 16:45:21 +00:00
{
c = *p;
p++;
}
2006-10-24 04:10:12 +00:00
frac2 = 10*frac2 + (c - ASE_T('0'));
2006-04-04 16:45:21 +00:00
}
fraction = (1.0e9 * frac1) + frac2;
}
2006-10-22 12:39:30 +00:00
/* Skim off the exponent */
p = pexp;
2006-10-24 04:10:12 +00:00
if ((*p == ASE_T('E')) || (*p == ASE_T('e')))
2006-04-04 16:45:21 +00:00
{
p++;
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('-'))
2006-04-04 16:45:21 +00:00
{
2006-10-22 12:39:30 +00:00
exp_negative = 1;
2006-10-06 03:37:40 +00:00
p++;
}
else
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('+')) p++;
2006-10-22 12:39:30 +00:00
exp_negative = 0;
2006-10-06 03:37:40 +00:00
}
2006-10-24 04:10:12 +00:00
if (!ASE_AWK_ISDIGIT (awk, *p))
2006-10-06 03:37:40 +00:00
{
2006-10-22 12:39:30 +00:00
/* p = pexp; */
2006-10-06 14:35:17 +00:00
/* goto done; */
2006-10-22 12:39:30 +00:00
goto no_exp;
2006-10-06 03:37:40 +00:00
}
2006-10-24 04:10:12 +00:00
while (ASE_AWK_ISDIGIT (awk, *p))
2006-10-06 03:37:40 +00:00
{
2006-10-24 04:10:12 +00:00
exp = exp * 10 + (*p - ASE_T('0'));
2006-10-06 03:37:40 +00:00
p++;
}
}
2006-10-22 12:39:30 +00:00
no_exp:
if (exp_negative) exp = frac_exp - exp;
else exp = frac_exp + exp;
2006-10-06 03:37:40 +00:00
/*
2006-10-22 12:39:30 +00:00
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
2006-10-06 03:37:40 +00:00
* fraction.
*/
2006-10-22 12:39:30 +00:00
if (exp < 0)
2006-10-06 03:37:40 +00:00
{
2006-10-22 12:39:30 +00:00
exp_negative = 1;
exp = -exp;
2006-10-06 03:37:40 +00:00
}
2006-10-22 12:39:30 +00:00
else exp_negative = 0;
2006-10-06 03:37:40 +00:00
2006-10-22 12:39:30 +00:00
if (exp > MAX_EXPONENT) exp = MAX_EXPONENT;
2006-10-06 03:37:40 +00:00
2006-10-22 12:39:30 +00:00
dbl_exp = 1.0;
2006-10-06 03:37:40 +00:00
2006-10-22 12:39:30 +00:00
for (d = powers_of_10; exp != 0; exp >>= 1, d++)
2006-10-06 03:37:40 +00:00
{
2006-10-22 12:39:30 +00:00
if (exp & 01) dbl_exp *= *d;
2006-10-06 03:37:40 +00:00
}
2006-10-22 12:39:30 +00:00
if (exp_negative) fraction /= dbl_exp;
else fraction *= dbl_exp;
2006-10-06 03:37:40 +00:00
done:
return (negative)? -fraction: fraction;
}
2006-10-24 04:10:12 +00:00
ase_real_t ase_awk_strxtoreal (
ase_awk_t* awk, const ase_char_t* str, ase_size_t len,
const ase_char_t** endptr)
2006-10-06 03:37:40 +00:00
{
/*
* Table giving binary powers of 10. Entry is 10^2^i.
2006-10-22 12:39:30 +00:00
* Used to convert decimal exponents into floating-point numbers.
2006-10-06 03:37:40 +00:00
*/
2006-10-24 04:10:12 +00:00
static ase_real_t powers_of_10[] =
2006-10-06 03:37:40 +00:00
{
10., 100., 1.0e4, 1.0e8, 1.0e16,
1.0e32, 1.0e64, 1.0e128, 1.0e256
};
2006-10-24 04:10:12 +00:00
ase_real_t fraction, dbl_exp, * d;
const ase_char_t* p, * end;
ase_cint_t c;
2006-10-22 12:39:30 +00:00
int exp = 0; /* Esseonent read from "EX" field */
2006-10-06 03:37:40 +00:00
/*
2006-10-22 11:34:53 +00:00
* Esseonent that derives from the fractional part. Under normal
2006-10-06 03:37:40 +00:00
* circumstatnces, it is the negative of the number of digits in F.
* However, if I is very long, the last digits of I get dropped
2006-10-22 12:39:30 +00:00
* (otherwise a long I with a large negative exponent could cause an
* unnecessary overflow on I alone). In this case, frac_exp is
2006-10-06 03:37:40 +00:00
* incremented one for each dropped digit.
*/
2006-10-22 12:39:30 +00:00
int frac_exp;
2006-10-06 03:37:40 +00:00
int mant_size; /* Number of digits in mantissa. */
int dec_pt; /* Number of mantissa digits BEFORE decimal point */
2006-10-24 04:10:12 +00:00
const ase_char_t *pexp; /* Temporarily holds location of exponent in string */
2006-10-22 12:39:30 +00:00
int negative = 0, exp_negative = 0;
2006-10-06 03:37:40 +00:00
p = str;
end = str + len;
/* Strip off leading blanks and check for a sign */
2006-10-24 04:10:12 +00:00
/*while (ASE_AWK_ISSPACE(awk,*p)) p++;*/
2006-10-06 03:37:40 +00:00
2006-10-24 04:10:12 +00:00
/*while (*p != ASE_T('\0')) */
2006-10-06 03:37:40 +00:00
while (p < end)
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('-'))
2006-10-06 03:37:40 +00:00
{
negative = ~negative;
p++;
}
2006-10-24 04:10:12 +00:00
else if (*p == ASE_T('+')) p++;
2006-10-06 03:37:40 +00:00
else break;
}
/* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point. */
dec_pt = -1;
/*for (mant_size = 0; ; mant_size++) */
for (mant_size = 0; p < end; mant_size++)
{
c = *p;
2006-10-24 04:10:12 +00:00
if (!ASE_AWK_ISDIGIT (awk, c))
2006-10-06 03:37:40 +00:00
{
2006-10-24 04:10:12 +00:00
if (c != ASE_T('.') || dec_pt >= 0) break;
2006-10-06 03:37:40 +00:00
dec_pt = mant_size;
}
p++;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
2006-10-22 12:39:30 +00:00
pexp = p;
2006-10-06 03:37:40 +00:00
p -= mant_size;
if (dec_pt < 0)
{
dec_pt = mant_size;
}
else
{
mant_size--; /* One of the digits was the point */
}
2006-10-24 04:10:12 +00:00
if (mant_size > 18) /* TODO: is 18 correct for ase_real_t??? */
2006-10-06 03:37:40 +00:00
{
2006-10-22 12:39:30 +00:00
frac_exp = dec_pt - 18;
2006-10-06 03:37:40 +00:00
mant_size = 18;
}
else
{
2006-10-22 12:39:30 +00:00
frac_exp = dec_pt - mant_size;
2006-10-06 03:37:40 +00:00
}
if (mant_size == 0)
{
fraction = 0.0;
/*p = str;*/
2006-10-22 12:39:30 +00:00
p = pexp;
2006-10-06 03:37:40 +00:00
goto done;
}
else
{
int frac1, frac2;
2006-10-06 14:35:17 +00:00
2006-10-06 03:37:40 +00:00
frac1 = 0;
for ( ; mant_size > 9; mant_size--)
{
c = *p;
p++;
2006-10-24 04:10:12 +00:00
if (c == ASE_T('.'))
2006-10-06 03:37:40 +00:00
{
c = *p;
p++;
}
2006-10-24 04:10:12 +00:00
frac1 = 10 * frac1 + (c - ASE_T('0'));
2006-10-06 03:37:40 +00:00
}
2006-10-06 14:35:17 +00:00
2006-10-06 03:37:40 +00:00
frac2 = 0;
for (; mant_size > 0; mant_size--) {
2006-10-06 14:35:17 +00:00
c = *p++;
2006-10-24 04:10:12 +00:00
if (c == ASE_T('.'))
2006-10-06 03:37:40 +00:00
{
c = *p;
p++;
}
2006-10-24 04:10:12 +00:00
frac2 = 10 * frac2 + (c - ASE_T('0'));
2006-10-06 03:37:40 +00:00
}
fraction = (1.0e9 * frac1) + frac2;
}
2006-10-22 12:39:30 +00:00
/* Skim off the exponent */
p = pexp;
2006-10-24 04:10:12 +00:00
if (p < end && (*p == ASE_T('E') || *p == ASE_T('e')))
2006-10-06 03:37:40 +00:00
{
p++;
2006-10-06 14:35:17 +00:00
if (p < end)
2006-04-04 16:45:21 +00:00
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('-'))
2006-10-06 14:35:17 +00:00
{
2006-10-22 12:39:30 +00:00
exp_negative = 1;
2006-10-06 14:35:17 +00:00
p++;
}
else
{
2006-10-24 04:10:12 +00:00
if (*p == ASE_T('+')) p++;
2006-10-22 12:39:30 +00:00
exp_negative = 0;
2006-10-06 14:35:17 +00:00
}
2006-04-04 16:45:21 +00:00
}
2006-10-22 12:39:30 +00:00
else exp_negative = 0;
2006-10-06 14:35:17 +00:00
2006-10-24 04:10:12 +00:00
if (!(p < end && ASE_AWK_ISDIGIT (awk, *p)))
2006-04-04 16:45:21 +00:00
{
2006-10-22 12:39:30 +00:00
/*p = pexp;*/
2006-10-06 14:35:17 +00:00
/*goto done;*/
2006-10-22 12:39:30 +00:00
goto no_exp;
2006-04-04 16:45:21 +00:00
}
2006-10-06 14:35:17 +00:00
2006-10-24 04:10:12 +00:00
while (p < end && ASE_AWK_ISDIGIT (awk, *p))
2006-04-04 16:45:21 +00:00
{
2006-10-24 04:10:12 +00:00
exp = exp * 10 + (*p - ASE_T('0'));
2006-04-04 16:45:21 +00:00
p++;
}
}
2006-10-22 12:39:30 +00:00
no_exp:
if (exp_negative) exp = frac_exp - exp;
else exp = frac_exp + exp;
2006-04-04 16:45:21 +00:00
/*
2006-10-22 12:39:30 +00:00
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
2006-04-04 16:45:21 +00:00
* fraction.
*/
2006-10-22 12:39:30 +00:00
if (exp < 0)
2006-04-04 16:45:21 +00:00
{
2006-10-22 12:39:30 +00:00
exp_negative = 1;
exp = -exp;
2006-04-04 16:45:21 +00:00
}
2006-10-22 12:39:30 +00:00
else exp_negative = 0;
2006-04-04 16:45:21 +00:00
2006-10-22 12:39:30 +00:00
if (exp > MAX_EXPONENT) exp = MAX_EXPONENT;
2006-04-04 16:45:21 +00:00
2006-10-22 12:39:30 +00:00
dbl_exp = 1.0;
2006-04-04 16:45:21 +00:00
2006-10-22 12:39:30 +00:00
for (d = powers_of_10; exp != 0; exp >>= 1, d++)
2006-04-04 16:45:21 +00:00
{
2006-10-22 12:39:30 +00:00
if (exp & 01) dbl_exp *= *d;
2006-04-04 16:45:21 +00:00
}
2006-10-22 12:39:30 +00:00
if (exp_negative) fraction /= dbl_exp;
else fraction *= dbl_exp;
2006-04-04 16:45:21 +00:00
done:
2006-10-24 04:10:12 +00:00
if (endptr != ASE_NULL) *endptr = p;
2006-10-06 03:37:40 +00:00
return (negative)? -fraction: fraction;
2006-04-04 16:03:14 +00:00
}
2006-10-24 04:10:12 +00:00
ase_size_t ase_awk_longtostr (
ase_long_t value, int radix, const ase_char_t* prefix,
ase_char_t* buf, ase_size_t size)
2006-09-01 16:31:13 +00:00
{
2006-10-24 04:10:12 +00:00
ase_long_t t, rem;
ase_size_t len, ret, i;
ase_size_t prefix_len;
2006-09-01 16:31:13 +00:00
2007-02-23 08:17:51 +00:00
prefix_len = (prefix != ASE_NULL)? ase_strlen(prefix): 0;
2006-09-01 16:31:13 +00:00
t = value;
if (t == 0)
{
/* zero */
2006-11-27 04:33:22 +00:00
if (buf == ASE_NULL)
{
/* if buf is not given,
* return the number of bytes required */
return prefix_len + 1;
}
2006-09-01 16:31:13 +00:00
if (size < prefix_len+1)
{
/* buffer too small */
2006-10-24 04:10:12 +00:00
return (ase_size_t)-1;
2006-09-01 16:31:13 +00:00
}
for (i = 0; i < prefix_len; i++) buf[i] = prefix[i];
2006-10-24 04:10:12 +00:00
buf[prefix_len] = ASE_T('0');
if (size > prefix_len+1) buf[prefix_len+1] = ASE_T('\0');
2006-11-27 04:33:22 +00:00
return prefix_len+1;
2006-09-01 16:31:13 +00:00
}
/* non-zero values */
len = prefix_len;
if (t < 0) { t = -t; len++; }
while (t > 0) { len++; t /= radix; }
2006-10-24 04:10:12 +00:00
if (buf == ASE_NULL)
2006-09-01 16:31:13 +00:00
{
/* if buf is not given, return the number of bytes required */
return len;
}
2006-10-24 04:10:12 +00:00
if (size < len) return (ase_size_t)-1; /* buffer too small */
if (size > len) buf[len] = ASE_T('\0');
2006-09-01 16:31:13 +00:00
ret = len;
t = value;
if (t < 0) t = -t;
while (t > 0)
{
rem = t % radix;
if (rem >= 10)
2006-10-24 04:10:12 +00:00
buf[--len] = (ase_char_t)rem + ASE_T('a') - 10;
2006-09-01 16:31:13 +00:00
else
2006-10-24 04:10:12 +00:00
buf[--len] = (ase_char_t)rem + ASE_T('0');
2006-09-01 16:31:13 +00:00
t /= radix;
}
if (value < 0)
{
for (i = 1; i <= prefix_len; i++)
{
buf[i] = prefix[i-1];
len--;
}
2006-10-24 04:10:12 +00:00
buf[--len] = ASE_T('-');
2006-09-01 16:31:13 +00:00
}
else
{
for (i = 0; i < prefix_len; i++) buf[i] = prefix[i];
}
return ret;
}
2006-10-24 04:10:12 +00:00
ase_char_t* ase_awk_strtok (
ase_awk_run_t* run, const ase_char_t* s,
const ase_char_t* delim, ase_char_t** tok, ase_size_t* tok_len)
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
return ase_awk_strxntok (
2007-02-23 08:17:51 +00:00
run, s, ase_strlen(s),
delim, ase_strlen(delim), tok, tok_len);
2006-09-01 06:23:58 +00:00
}
2006-10-24 04:10:12 +00:00
ase_char_t* ase_awk_strxtok (
ase_awk_run_t* run, const ase_char_t* s, ase_size_t len,
const ase_char_t* delim, ase_char_t** tok, ase_size_t* tok_len)
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
return ase_awk_strxntok (
2006-09-08 15:26:49 +00:00
run, s, len,
2007-02-23 08:17:51 +00:00
delim, ase_strlen(delim), tok, tok_len);
2006-09-03 15:47:11 +00:00
}
2006-10-24 04:10:12 +00:00
ase_char_t* ase_awk_strntok (
ase_awk_run_t* run, const ase_char_t* s,
const ase_char_t* delim, ase_size_t delim_len,
ase_char_t** tok, ase_size_t* tok_len)
2006-09-03 15:47:11 +00:00
{
2006-10-24 04:10:12 +00:00
return ase_awk_strxntok (
2007-02-23 08:17:51 +00:00
run, s, ase_strlen(s),
2006-09-03 15:47:11 +00:00
delim, delim_len, tok, tok_len);
2006-09-01 06:23:58 +00:00
}
2006-10-24 04:10:12 +00:00
ase_char_t* ase_awk_strxntok (
ase_awk_run_t* run, const ase_char_t* s, ase_size_t len,
const ase_char_t* delim, ase_size_t delim_len,
ase_char_t** tok, ase_size_t* tok_len)
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
const ase_char_t* p = s, *d;
const ase_char_t* end = s + len;
const ase_char_t* sp = ASE_NULL, * ep = ASE_NULL;
const ase_char_t* delim_end = delim + delim_len;
ase_char_t c;
2006-09-01 06:23:58 +00:00
int delim_mode;
2006-09-03 15:47:11 +00:00
#define __DELIM_NULL 0
#define __DELIM_EMPTY 1
#define __DELIM_SPACES 2
#define __DELIM_NOSPACES 3
#define __DELIM_COMPOSITE 4
2006-10-24 04:10:12 +00:00
if (delim == ASE_NULL) delim_mode = __DELIM_NULL;
2006-09-01 06:23:58 +00:00
else
{
2006-09-03 15:47:11 +00:00
delim_mode = __DELIM_EMPTY;
2006-09-01 06:23:58 +00:00
2006-09-03 15:47:11 +00:00
for (d = delim; d < delim_end; d++)
{
2006-10-24 04:10:12 +00:00
if (ASE_AWK_ISSPACE(run->awk,*d))
2006-09-03 15:47:11 +00:00
{
if (delim_mode == __DELIM_EMPTY)
delim_mode = __DELIM_SPACES;
else if (delim_mode == __DELIM_NOSPACES)
{
delim_mode = __DELIM_COMPOSITE;
break;
}
}
else
{
if (delim_mode == __DELIM_EMPTY)
delim_mode = __DELIM_NOSPACES;
else if (delim_mode == __DELIM_SPACES)
{
delim_mode = __DELIM_COMPOSITE;
break;
}
}
}
2006-12-04 07:17:13 +00:00
/* TODO: verify the following statement... */
if (delim_mode == __DELIM_SPACES &&
delim_len == 1 &&
delim[0] != ASE_T(' ')) delim_mode = __DELIM_NOSPACES;
2006-09-03 15:47:11 +00:00
}
if (delim_mode == __DELIM_NULL)
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
/* when ASE_NULL is given as "delim", it trims off the
2006-09-03 15:47:11 +00:00
* leading and trailing spaces characters off the source
* string "s" eventually. */
2006-10-24 04:10:12 +00:00
while (p < end && ASE_AWK_ISSPACE(run->awk,*p)) p++;
2006-09-01 06:23:58 +00:00
while (p < end)
{
c = *p;
2006-10-24 04:10:12 +00:00
if (!ASE_AWK_ISSPACE(run->awk,c))
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
if (sp == ASE_NULL) sp = p;
2006-09-01 06:23:58 +00:00
ep = p;
}
p++;
}
}
2006-09-03 15:47:11 +00:00
else if (delim_mode == __DELIM_EMPTY)
2006-09-01 06:23:58 +00:00
{
2006-09-03 15:47:11 +00:00
/* each character in the source string "s" becomes a token. */
if (p < end)
{
c = *p;
sp = p;
ep = p++;
}
}
else if (delim_mode == __DELIM_SPACES)
{
/* each token is delimited by space characters. all leading
* and trailing spaces are removed. */
2006-10-24 04:10:12 +00:00
while (p < end && ASE_AWK_ISSPACE(run->awk,*p)) p++;
2006-09-01 06:23:58 +00:00
while (p < end)
{
c = *p;
2006-10-24 04:10:12 +00:00
if (ASE_AWK_ISSPACE(run->awk,c)) break;
if (sp == ASE_NULL) sp = p;
2006-09-01 06:23:58 +00:00
ep = p++;
}
2006-10-24 04:10:12 +00:00
while (p < end && ASE_AWK_ISSPACE(run->awk,*p)) p++;
2006-09-01 06:23:58 +00:00
}
2006-09-03 15:47:11 +00:00
else if (delim_mode == __DELIM_NOSPACES)
{
2006-09-05 04:11:11 +00:00
/* each token is delimited by one of charaters
* in the delimeter set "delim". */
2006-09-22 14:05:30 +00:00
if (run->global.ignorecase)
2006-09-03 15:47:11 +00:00
{
2006-09-09 04:52:40 +00:00
while (p < end)
2006-09-03 15:47:11 +00:00
{
2006-10-24 04:10:12 +00:00
c = ASE_AWK_TOUPPER(run->awk, *p);
2006-09-09 04:52:40 +00:00
for (d = delim; d < delim_end; d++)
{
2006-10-24 04:10:12 +00:00
if (c == ASE_AWK_TOUPPER(run->awk,*d)) goto exit_loop;
2006-09-09 04:52:40 +00:00
}
2006-10-24 04:10:12 +00:00
if (sp == ASE_NULL) sp = p;
2006-09-09 04:52:40 +00:00
ep = p++;
}
}
else
{
while (p < end)
{
c = *p;
for (d = delim; d < delim_end; d++)
{
if (c == *d) goto exit_loop;
}
2006-10-24 04:10:12 +00:00
if (sp == ASE_NULL) sp = p;
2006-09-09 04:52:40 +00:00
ep = p++;
2006-09-03 15:47:11 +00:00
}
}
}
else /* if (delim_mode == __DELIM_COMPOSITE) */
2006-09-01 06:23:58 +00:00
{
2006-09-05 04:11:11 +00:00
/* each token is delimited by one of non-space charaters
* in the delimeter set "delim". however, all space characters
* surrounding the token are removed */
2006-10-24 04:10:12 +00:00
while (p < end && ASE_AWK_ISSPACE(run->awk,*p)) p++;
2006-09-22 14:05:30 +00:00
if (run->global.ignorecase)
2006-09-01 06:23:58 +00:00
{
2006-09-09 04:52:40 +00:00
while (p < end)
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
c = ASE_AWK_TOUPPER(run->awk, *p);
if (ASE_AWK_ISSPACE(run->awk,c))
2006-09-09 04:52:40 +00:00
{
p++;
continue;
}
for (d = delim; d < delim_end; d++)
{
2006-10-24 04:10:12 +00:00
if (c == ASE_AWK_TOUPPER(run->awk,*d)) goto exit_loop;
2006-09-09 04:52:40 +00:00
}
2006-10-24 04:10:12 +00:00
if (sp == ASE_NULL) sp = p;
2006-09-09 04:52:40 +00:00
ep = p++;
2006-09-01 06:23:58 +00:00
}
2006-09-09 04:52:40 +00:00
}
else
{
while (p < end)
2006-09-01 06:23:58 +00:00
{
2006-09-09 04:52:40 +00:00
c = *p;
2006-10-24 04:10:12 +00:00
if (ASE_AWK_ISSPACE(run->awk,c))
2006-09-09 04:52:40 +00:00
{
p++;
continue;
}
for (d = delim; d < delim_end; d++)
{
if (c == *d) goto exit_loop;
}
2006-10-24 04:10:12 +00:00
if (sp == ASE_NULL) sp = p;
2006-09-09 04:52:40 +00:00
ep = p++;
2006-09-01 06:23:58 +00:00
}
}
}
exit_loop:
2006-10-24 04:10:12 +00:00
if (sp == ASE_NULL)
2006-09-01 06:23:58 +00:00
{
2006-10-24 04:10:12 +00:00
*tok = ASE_NULL;
*tok_len = (ase_size_t)0;
2006-09-01 06:23:58 +00:00
}
else
{
2006-10-24 04:10:12 +00:00
*tok = (ase_char_t*)sp;
2006-09-01 06:23:58 +00:00
*tok_len = ep - sp + 1;
}
2006-10-24 04:10:12 +00:00
/* if ASE_NULL is returned, this function should not be called anymore */
if (p >= end) return ASE_NULL;
2006-09-05 04:11:11 +00:00
if (delim_mode == __DELIM_EMPTY ||
2006-10-24 04:10:12 +00:00
delim_mode == __DELIM_SPACES) return (ase_char_t*)p;
return (ase_char_t*)++p;
2006-09-05 04:11:11 +00:00
}
2006-10-24 04:10:12 +00:00
ase_char_t* ase_awk_strxntokbyrex (
ase_awk_run_t* run, const ase_char_t* s, ase_size_t len,
void* rex, ase_char_t** tok, ase_size_t* tok_len, int* errnum)
2006-09-05 04:11:11 +00:00
{
int n;
2006-10-24 04:10:12 +00:00
ase_char_t* match_ptr;
ase_size_t match_len, i;
ase_size_t left = len;
const ase_char_t* ptr = s;
const ase_char_t* str_ptr = s;
ase_size_t str_len = len;
2006-09-05 04:11:11 +00:00
2006-09-08 14:51:15 +00:00
while (len > 0)
{
2006-10-24 04:10:12 +00:00
n = ase_awk_matchrex (
2006-09-10 15:50:34 +00:00
run->awk, rex,
2006-10-24 04:10:12 +00:00
((run->global.ignorecase)? ASE_AWK_REX_IGNORECASE: 0),
ptr, left, (const ase_char_t**)&match_ptr, &match_len,
2006-09-10 16:04:34 +00:00
errnum);
2006-10-24 04:10:12 +00:00
if (n == -1) return ASE_NULL;
2006-09-08 14:51:15 +00:00
if (n == 0)
{
/* no match has been found.
* return the entire string as a token */
2006-10-24 04:10:12 +00:00
*tok = (ase_char_t*)str_ptr;
2006-09-08 14:51:15 +00:00
*tok_len = str_len;
2006-10-24 04:10:12 +00:00
*errnum = ASE_AWK_ENOERR;
return ASE_NULL;
2006-09-08 14:51:15 +00:00
}
2006-09-05 15:18:36 +00:00
2007-03-06 14:58:00 +00:00
ASE_ASSERT (n == 1);
2006-09-05 15:18:36 +00:00
2006-09-08 14:51:15 +00:00
if (match_len == 0)
{
ptr++;
left--;
}
2006-10-24 04:10:12 +00:00
else if (run->awk->option & ASE_AWK_STRIPSPACES)
2006-09-08 14:51:15 +00:00
{
/* match at the beginning of the input string */
if (match_ptr == s)
{
for (i = 0; i < match_len; i++)
{
2006-10-24 04:10:12 +00:00
if (!ASE_AWK_ISSPACE(run->awk, match_ptr[i]))
2006-09-08 14:51:15 +00:00
goto exit_loop;
}
2006-09-05 15:18:36 +00:00
2006-09-08 14:51:15 +00:00
/* the match that are all spaces at the
* beginning of the input string is skipped */
ptr += match_len;
left -= match_len;
str_ptr = s + match_len;
str_len -= match_len;
}
else break;
}
else break;
}
2006-09-05 15:18:36 +00:00
2006-09-08 14:51:15 +00:00
exit_loop:
if (len == 0)
2006-09-05 15:18:36 +00:00
{
2006-10-24 04:10:12 +00:00
*tok = (ase_char_t*)str_ptr;
2006-09-08 14:51:15 +00:00
*tok_len = str_len;
2006-10-24 04:10:12 +00:00
*errnum = ASE_AWK_ENOERR;
return ASE_NULL;
2006-09-05 15:18:36 +00:00
}
2006-10-24 04:10:12 +00:00
*tok = (ase_char_t*)str_ptr;
2006-09-08 14:51:15 +00:00
*tok_len = match_ptr - str_ptr;
2006-09-05 04:11:11 +00:00
2006-09-05 15:18:36 +00:00
for (i = 0; i < match_len; i++)
{
2006-10-24 04:10:12 +00:00
if (!ASE_AWK_ISSPACE(run->awk, match_ptr[i]))
2006-09-05 15:18:36 +00:00
{
2006-10-24 04:10:12 +00:00
*errnum = ASE_AWK_ENOERR;
2006-09-05 15:18:36 +00:00
return match_ptr+match_len;
}
}
2006-10-24 04:10:12 +00:00
*errnum = ASE_AWK_ENOERR;
2006-09-08 14:51:15 +00:00
2006-10-24 04:10:12 +00:00
if (run->awk->option & ASE_AWK_STRIPSPACES)
2006-09-08 14:51:15 +00:00
{
return (match_ptr+match_len >= s+len)?
2006-10-24 04:10:12 +00:00
ASE_NULL: (match_ptr+match_len);
2006-09-08 14:51:15 +00:00
}
else
{
return (match_ptr+match_len > s+len)?
2006-10-24 04:10:12 +00:00
ASE_NULL: (match_ptr+match_len);
2006-09-08 14:51:15 +00:00
}
2006-09-01 06:23:58 +00:00
}