|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* builtin.c - Builtin functions and various utility procedures.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Copyright (C) 1986, 1988, 1989, 1991-2018 the Free Software Foundation, Inc.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* This file is part of GAWK, the GNU implementation of the
|
|
Packit |
575503 |
* AWK Programming Language.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* GAWK is free software; you can redistribute it and/or modify
|
|
Packit |
575503 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
575503 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
575503 |
* (at your option) any later version.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* GAWK is distributed in the hope that it will be useful,
|
|
Packit |
575503 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
575503 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
575503 |
* GNU General Public License for more details.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
575503 |
* along with this program; if not, write to the Free Software
|
|
Packit |
575503 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#include "awk.h"
|
|
Packit |
575503 |
#if defined(HAVE_FCNTL_H)
|
|
Packit |
575503 |
#include <fcntl.h>
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
#include <math.h>
|
|
Packit |
575503 |
#include "random.h"
|
|
Packit |
575503 |
#include "floatmagic.h"
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if defined(HAVE_POPEN_H)
|
|
Packit |
575503 |
#include "popen.h"
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#ifndef CHAR_BIT
|
|
Packit |
575503 |
# define CHAR_BIT 8
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* The extra casts work around common compiler bugs. */
|
|
Packit |
575503 |
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
|
Packit |
575503 |
/* Note: these assume that negative integers are represented internally
|
|
Packit |
575503 |
via 2's complement, which is not mandated by C. They also ignore the
|
|
Packit |
575503 |
fact that signed integer arithmetic overflow can trigger exceptions,
|
|
Packit |
575503 |
unlike unsigned which is guaranteed not to do so. */
|
|
Packit |
575503 |
#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
|
|
Packit |
575503 |
? ~ (uintmax_t) 0 << (sizeof (t) * CHAR_BIT - 1) \
|
|
Packit |
575503 |
: 0))
|
|
Packit |
575503 |
#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#ifndef INTMAX_MIN
|
|
Packit |
575503 |
# define INTMAX_MIN TYPE_MINIMUM (intmax_t)
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
#ifndef UINTMAX_MAX
|
|
Packit |
575503 |
# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t)
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#ifndef SIZE_MAX /* C99 constant, can't rely on it everywhere */
|
|
Packit |
575503 |
#define SIZE_MAX ((size_t) -1)
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#define DEFAULT_G_PRECISION 6
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static size_t mbc_byte_count(const char *ptr, size_t numchars);
|
|
Packit |
575503 |
static size_t mbc_char_count(const char *ptr, size_t numbytes);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* Can declare these, since we always use the random shipped with gawk */
|
|
Packit |
575503 |
extern char *initstate(unsigned long seed, char *state, long n);
|
|
Packit |
575503 |
extern char *setstate(char *state);
|
|
Packit |
575503 |
extern long random(void);
|
|
Packit |
575503 |
extern void srandom(unsigned long seed);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
extern NODE **args_array;
|
|
Packit |
575503 |
extern int max_args;
|
|
Packit |
575503 |
extern NODE **fields_arr;
|
|
Packit |
575503 |
extern bool output_is_tty;
|
|
Packit |
575503 |
extern FILE *output_fp;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#define POP_TWO_SCALARS(s1, s2) \
|
|
Packit |
575503 |
s2 = POP_SCALAR(); \
|
|
Packit |
575503 |
s1 = POP(); \
|
|
Packit |
575503 |
do { if (s1->type == Node_var_array) { \
|
|
Packit |
575503 |
DEREF(s2); \
|
|
Packit |
575503 |
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \
|
|
Packit |
575503 |
}} while (false)
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Since we supply the version of random(), we know what
|
|
Packit |
575503 |
* value to use here.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
#define GAWK_RANDOM_MAX 0x7fffffffL
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* efwrite --- like fwrite, but with error checking */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static void
|
|
Packit |
575503 |
efwrite(const void *ptr,
|
|
Packit |
575503 |
size_t size,
|
|
Packit |
575503 |
size_t count,
|
|
Packit |
575503 |
FILE *fp,
|
|
Packit |
575503 |
const char *from,
|
|
Packit |
575503 |
struct redirect *rp,
|
|
Packit |
575503 |
bool flush)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
errno = 0;
|
|
Packit |
575503 |
if (rp != NULL) {
|
|
Packit |
575503 |
if (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count)
|
|
Packit |
575503 |
goto wrerror;
|
|
Packit |
575503 |
} else if (fwrite(ptr, size, count, fp) != count)
|
|
Packit |
575503 |
goto wrerror;
|
|
Packit |
575503 |
if (flush
|
|
Packit |
575503 |
&& ((fp == stdout && output_is_tty)
|
|
Packit |
575503 |
|| (rp != NULL && (rp->flag & RED_NOBUF) != 0))) {
|
|
Packit |
575503 |
if (rp != NULL) {
|
|
Packit |
575503 |
rp->output.gawk_fflush(fp, rp->output.opaque);
|
|
Packit |
575503 |
if (rp->output.gawk_ferror(fp, rp->output.opaque))
|
|
Packit |
575503 |
goto wrerror;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
fflush(fp);
|
|
Packit |
575503 |
if (ferror(fp))
|
|
Packit |
575503 |
goto wrerror;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
wrerror:
|
|
Packit |
575503 |
#ifdef __MINGW32__
|
|
Packit |
575503 |
if (errno == 0 || errno == EINVAL)
|
|
Packit |
575503 |
w32_maybe_set_errno();
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
/* for stdout, die with a real SIGPIPE, like other awks */
|
|
Packit |
575503 |
if (fp == stdout && errno == EPIPE)
|
|
Packit |
575503 |
die_via_sigpipe();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* otherwise die verbosely */
|
|
Packit |
575503 |
if ((rp != NULL) ? is_non_fatal_redirect(rp->value, strlen(rp->value)) : is_non_fatal_std(fp))
|
|
Packit |
575503 |
update_ERRNO_int(errno);
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
fatal(_("%s to \"%s\" failed (%s)"), from,
|
|
Packit |
575503 |
rp != NULL
|
|
Packit |
575503 |
? rp->value
|
|
Packit |
575503 |
: fp == stdout
|
|
Packit |
575503 |
? _("standard output")
|
|
Packit |
575503 |
: _("standard error"),
|
|
Packit |
575503 |
errno ? strerror(errno) : _("reason unknown"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_exp --- exponential function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_exp(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double d, res;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("exp: received non-numeric argument"));
|
|
Packit |
575503 |
d = force_number(tmp)->numbr;
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
errno = 0;
|
|
Packit |
575503 |
res = exp(d);
|
|
Packit |
575503 |
if (errno == ERANGE)
|
|
Packit |
575503 |
warning(_("exp: argument %g is out of range"), d);
|
|
Packit |
575503 |
return make_number((AWKNUM) res);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* stdfile --- return fp for a standard file */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* This function allows `fflush("/dev/stdout")' to work.
|
|
Packit |
575503 |
* The other files will be available via getredirect().
|
|
Packit |
575503 |
* /dev/stdin is not included, since fflush is only for output.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static FILE *
|
|
Packit |
575503 |
stdfile(const char *name, size_t len)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
if (len == 11) {
|
|
Packit |
575503 |
if (strncmp(name, "/dev/stderr", 11) == 0)
|
|
Packit |
575503 |
return stderr;
|
|
Packit |
575503 |
else if (strncmp(name, "/dev/stdout", 11) == 0)
|
|
Packit |
575503 |
return stdout;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return NULL;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_fflush --- flush output, either named file or pipe or everything */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_fflush(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
struct redirect *rp;
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
FILE *fp;
|
|
Packit |
575503 |
int status = 0;
|
|
Packit |
575503 |
const char *file;
|
|
Packit |
575503 |
int len;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* November, 2012.
|
|
Packit |
575503 |
* It turns out that circa 2002, when BWK
|
|
Packit |
575503 |
* added fflush() and fflush("") to his awk, he made both of
|
|
Packit |
575503 |
* them flush everything.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* Now, with our inside agent getting ready to try to get fflush()
|
|
Packit |
575503 |
* standardized in POSIX, we are going to make our awk consistent
|
|
Packit |
575503 |
* with his. This should not really affect anyone, as flushing
|
|
Packit |
575503 |
* everything also flushes stdout.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* So. Once upon a time:
|
|
Packit |
575503 |
* fflush() --- flush stdout
|
|
Packit |
575503 |
* fflush("") --- flush everything
|
|
Packit |
575503 |
* Now, both calls flush everything.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* fflush() */
|
|
Packit |
575503 |
if (nargs == 0) {
|
|
Packit |
575503 |
status = flush_io(); // ERRNO updated
|
|
Packit |
575503 |
return make_number((AWKNUM) status);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_STRING();
|
|
Packit |
575503 |
file = tmp->stptr;
|
|
Packit |
575503 |
len = tmp->stlen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* fflush("") */
|
|
Packit |
575503 |
if (tmp->stlen == 0) {
|
|
Packit |
575503 |
status = flush_io(); // ERRNO updated
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) status);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* fflush("/some/path") */
|
|
Packit |
575503 |
rp = getredirect(tmp->stptr, tmp->stlen);
|
|
Packit |
575503 |
status = -1;
|
|
Packit |
575503 |
if (rp != NULL) {
|
|
Packit |
575503 |
if ((rp->flag & (RED_WRITE|RED_APPEND)) == 0) {
|
|
Packit |
575503 |
if ((rp->flag & RED_PIPE) != 0)
|
|
Packit |
575503 |
warning(_("fflush: cannot flush: pipe `%.*s' opened for reading, not writing"),
|
|
Packit |
575503 |
len, file);
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
warning(_("fflush: cannot flush: file `%.*s' opened for reading, not writing"),
|
|
Packit |
575503 |
len, file);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) status);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
fp = rp->output.fp;
|
|
Packit |
575503 |
if (fp != NULL) {
|
|
Packit |
575503 |
status = rp->output.gawk_fflush(fp, rp->output.opaque);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (status != 0) {
|
|
Packit |
575503 |
if (! is_non_fatal_redirect(tmp->stptr, tmp->stlen))
|
|
Packit |
575503 |
fatal(_("fflush: cannot flush file `%.*s': %s"),
|
|
Packit |
575503 |
len, file, strerror(errno));
|
|
Packit |
575503 |
update_ERRNO_int(errno);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else if ((rp->flag & RED_TWOWAY) != 0)
|
|
Packit |
575503 |
warning(_("fflush: cannot flush: two-way pipe `%.*s' has closed write end"),
|
|
Packit |
575503 |
len, file);
|
|
Packit |
575503 |
} else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) {
|
|
Packit |
575503 |
status = (non_fatal_flush_std_file(fp) == false);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
status = -1;
|
|
Packit |
575503 |
warning(_("fflush: `%.*s' is not an open file, pipe or co-process"), len, file);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) status);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* strncasecmpmbs --- like strncasecmp (multibyte string version) */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
int
|
|
Packit |
575503 |
strncasecmpmbs(const unsigned char *s1, const unsigned char *s2, size_t n)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
size_t i1, i2, mbclen1, mbclen2, gap;
|
|
Packit |
575503 |
wchar_t wc1, wc2;
|
|
Packit |
575503 |
mbstate_t mbs1, mbs2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& mbs1, 0, sizeof(mbs1));
|
|
Packit |
575503 |
memset(& mbs2, 0, sizeof(mbs2));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (i1 = i2 = 0 ; i1 < n && i2 < n ;i1 += mbclen1, i2 += mbclen2) {
|
|
Packit |
575503 |
if (is_valid_character(s1[i1])) {
|
|
Packit |
575503 |
mbclen1 = 1;
|
|
Packit |
575503 |
wc1 = btowc_cache(s1[i1]);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
mbclen1 = mbrtowc(& wc1, (const char *)s1 + i1,
|
|
Packit |
575503 |
n - i1, & mbs1);
|
|
Packit |
575503 |
if (mbclen1 == (size_t) -1 || mbclen1 == (size_t) -2 || mbclen1 == 0) {
|
|
Packit |
575503 |
/* We treat it as a singlebyte character. */
|
|
Packit |
575503 |
mbclen1 = 1;
|
|
Packit |
575503 |
wc1 = btowc_cache(s1[i1]);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (is_valid_character(s2[i2])) {
|
|
Packit |
575503 |
mbclen2 = 1;
|
|
Packit |
575503 |
wc2 = btowc_cache(s2[i2]);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
mbclen2 = mbrtowc(& wc2, (const char *)s2 + i2,
|
|
Packit |
575503 |
n - i2, & mbs2);
|
|
Packit |
575503 |
if (mbclen2 == (size_t) -1 || mbclen2 == (size_t) -2 || mbclen2 == 0) {
|
|
Packit |
575503 |
/* We treat it as a singlebyte character. */
|
|
Packit |
575503 |
mbclen2 = 1;
|
|
Packit |
575503 |
wc2 = btowc_cache(s2[i2]);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if ((gap = towlower(wc1) - towlower(wc2)) != 0)
|
|
Packit |
575503 |
/* s1 and s2 are not equivalent. */
|
|
Packit |
575503 |
return gap;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/* s1 and s2 are equivalent. */
|
|
Packit |
575503 |
return 0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* Inspect the buffer `src' and write the index of each byte to `dest'.
|
|
Packit |
575503 |
Caller must allocate `dest'.
|
|
Packit |
575503 |
e.g. str = <mb1(1)>, <mb1(2)>, a, b, <mb2(1)>, <mb2(2)>, <mb2(3)>, c
|
|
Packit |
575503 |
where mb(i) means the `i'-th byte of a multibyte character.
|
|
Packit |
575503 |
dest = 1, 2, 1, 1, 1, 2, 3. 1
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
static void
|
|
Packit |
575503 |
index_multibyte_buffer(char* src, char* dest, int len)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
int idx, prev_idx;
|
|
Packit |
575503 |
mbstate_t mbs, prevs;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& prevs, 0, sizeof(mbstate_t));
|
|
Packit |
575503 |
for (idx = prev_idx = 0 ; idx < len ; idx++) {
|
|
Packit |
575503 |
size_t mbclen;
|
|
Packit |
575503 |
mbs = prevs;
|
|
Packit |
575503 |
mbclen = mbrlen(src + prev_idx, idx - prev_idx + 1, & mbs);
|
|
Packit |
575503 |
if (mbclen == (size_t) -1 || mbclen == 1 || mbclen == 0) {
|
|
Packit |
575503 |
/* singlebyte character. */
|
|
Packit |
575503 |
mbclen = 1;
|
|
Packit |
575503 |
prev_idx = idx + 1;
|
|
Packit |
575503 |
} else if (mbclen == (size_t) -2) {
|
|
Packit |
575503 |
/* a part of a multibyte character. */
|
|
Packit |
575503 |
mbclen = idx - prev_idx + 1;
|
|
Packit |
575503 |
} else if (mbclen > 1) {
|
|
Packit |
575503 |
/* the end of a multibyte character. */
|
|
Packit |
575503 |
prev_idx = idx + 1;
|
|
Packit |
575503 |
prevs = mbs;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/* Can't reach. */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
dest[idx] = mbclen;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_index --- find index of a string */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_index(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *s1, *s2;
|
|
Packit |
575503 |
const char *p1, *p2;
|
|
Packit |
575503 |
size_t l1, l2;
|
|
Packit |
575503 |
long ret;
|
|
Packit |
575503 |
bool do_single_byte = false;
|
|
Packit |
575503 |
mbstate_t mbs1, mbs2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
memset(& mbs1, 0, sizeof(mbstate_t));
|
|
Packit |
575503 |
memset(& mbs2, 0, sizeof(mbstate_t));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
POP_TWO_SCALARS(s1, s2);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if ((fixtype(s1)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("index: received non-string first argument"));
|
|
Packit |
575503 |
if ((fixtype(s2)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("index: received non-string second argument"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
s1 = force_string(s1);
|
|
Packit |
575503 |
s2 = force_string(s2);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
p1 = s1->stptr;
|
|
Packit |
575503 |
p2 = s2->stptr;
|
|
Packit |
575503 |
l1 = s1->stlen;
|
|
Packit |
575503 |
l2 = s2->stlen;
|
|
Packit |
575503 |
ret = 0;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Icky special case, index(foo, "") should return 1,
|
|
Packit |
575503 |
* since both bwk awk and mawk do, and since match("foo", "")
|
|
Packit |
575503 |
* returns 1. This makes index("", "") work, too, fwiw.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (l2 == 0) {
|
|
Packit |
575503 |
ret = 1;
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
s1 = force_wstring(s1);
|
|
Packit |
575503 |
s2 = force_wstring(s2);
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* If we don't have valid wide character strings, use
|
|
Packit |
575503 |
* the real bytes.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
do_single_byte = ((s1->wstlen == 0 && s1->stlen > 0)
|
|
Packit |
575503 |
|| (s2->wstlen == 0 && s2->stlen > 0));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* IGNORECASE will already be false if posix */
|
|
Packit |
575503 |
if (IGNORECASE) {
|
|
Packit |
575503 |
while (l1 > 0) {
|
|
Packit |
575503 |
if (l2 > l1)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
if (! do_single_byte && gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
const wchar_t *pos;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
pos = wcasestrstr(s1->wstptr, s1->wstlen, s2->wstptr, s2->wstlen);
|
|
Packit |
575503 |
if (pos == NULL)
|
|
Packit |
575503 |
ret = 0;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
ret = pos - s1->wstptr + 1; /* 1-based */
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Could use tolower(*p1) == tolower(*p2) here.
|
|
Packit |
575503 |
* See discussion in eval.c as to why not.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (casetable[(unsigned char)*p1] == casetable[(unsigned char)*p2]
|
|
Packit |
575503 |
&& (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
|
|
Packit |
575503 |
ret = 1 + s1->stlen - l1;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
l1--;
|
|
Packit |
575503 |
p1++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
while (l1 > 0) {
|
|
Packit |
575503 |
if (l2 > l1)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
if (*p1 == *p2
|
|
Packit |
575503 |
&& (l2 == 1 || (l2 > 0 && memcmp(p1, p2, l2) == 0))) {
|
|
Packit |
575503 |
ret = 1 + s1->stlen - l1;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (! do_single_byte && gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
const wchar_t *pos;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
pos = wstrstr(s1->wstptr, s1->wstlen, s2->wstptr, s2->wstlen);
|
|
Packit |
575503 |
if (pos == NULL)
|
|
Packit |
575503 |
ret = 0;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
ret = pos - s1->wstptr + 1; /* 1-based */
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
l1--;
|
|
Packit |
575503 |
p1++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
out:
|
|
Packit |
575503 |
DEREF(s1);
|
|
Packit |
575503 |
DEREF(s2);
|
|
Packit |
575503 |
return make_number((AWKNUM) ret);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* double_to_int --- convert double to int, used several places */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
double
|
|
Packit |
575503 |
double_to_int(double d)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
if (d >= 0)
|
|
Packit |
575503 |
d = floor(d);
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
d = ceil(d);
|
|
Packit |
575503 |
return d;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_int --- convert double to int for awk */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_int(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double d;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("int: received non-numeric argument"));
|
|
Packit |
575503 |
d = force_number(tmp)->numbr;
|
|
Packit |
575503 |
d = double_to_int(d);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) d);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_isarray --- check if argument is array */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_isarray(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
int ret = 1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP();
|
|
Packit |
575503 |
if (tmp->type != Node_var_array) {
|
|
Packit |
575503 |
ret = 0;
|
|
Packit |
575503 |
// could be Node_var_new
|
|
Packit |
575503 |
if (tmp->type == Node_val)
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
return make_number((AWKNUM) ret);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_length --- length of a string, array or $0 */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_length(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
size_t len;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP();
|
|
Packit |
575503 |
if (tmp->type == Node_var_array) {
|
|
Packit |
575503 |
static bool warned = false;
|
|
Packit |
575503 |
unsigned long size;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_posix)
|
|
Packit |
575503 |
fatal(_("length: received array argument"));
|
|
Packit |
575503 |
if (do_lint && ! warned) {
|
|
Packit |
575503 |
warned = true;
|
|
Packit |
575503 |
lintwarn(_("`length(array)' is a gawk extension"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Support for deferred loading of array elements requires that
|
|
Packit |
575503 |
* we use the array length interface even though it isn't
|
|
Packit |
575503 |
* necessary for the built-in array types.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* 1/2015: The deferred arrays are gone, but this is probably
|
|
Packit |
575503 |
* still a good idea.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
size = assoc_length(tmp);
|
|
Packit |
575503 |
return make_number(size);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
assert(tmp->type == Node_val);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("length: received non-string argument"));
|
|
Packit |
575503 |
tmp = force_string(tmp);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
tmp = force_wstring(tmp);
|
|
Packit |
575503 |
len = tmp->wstlen;
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* If the bytes don't make a valid wide character
|
|
Packit |
575503 |
* string, fall back to the bytes themselves.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (len == 0 && tmp->stlen > 0)
|
|
Packit |
575503 |
len = tmp->stlen;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
len = tmp->stlen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) len);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_log --- the log function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_log(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double d, arg;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("log: received non-numeric argument"));
|
|
Packit |
575503 |
arg = force_number(tmp)->numbr;
|
|
Packit |
575503 |
if (arg < 0.0)
|
|
Packit |
575503 |
warning(_("log: received negative argument %g"), arg);
|
|
Packit |
575503 |
d = log(arg);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) d);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* mpz2mpfr --- convert an arbitrary-precision integer to a float
|
|
Packit |
575503 |
* without any loss of precision. The returned value is only
|
|
Packit |
575503 |
* good for temporary use.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static mpfr_ptr
|
|
Packit |
575503 |
mpz2mpfr(mpz_ptr zi)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
size_t prec;
|
|
Packit |
575503 |
static mpfr_t mpfrval;
|
|
Packit |
575503 |
static bool inited = false;
|
|
Packit |
575503 |
int tval;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* estimate minimum precision for exact conversion */
|
|
Packit |
575503 |
prec = mpz_sizeinbase(zi, 2); /* most significant 1 bit position starting at 1 */
|
|
Packit |
575503 |
prec -= (size_t) mpz_scan1(zi, 0); /* least significant 1 bit index starting at 0 */
|
|
Packit |
575503 |
if (prec < MPFR_PREC_MIN)
|
|
Packit |
575503 |
prec = MPFR_PREC_MIN;
|
|
Packit |
575503 |
else if (prec > MPFR_PREC_MAX)
|
|
Packit |
575503 |
prec = MPFR_PREC_MAX;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (! inited) {
|
|
Packit |
575503 |
mpfr_init2(mpfrval, prec);
|
|
Packit |
575503 |
inited = true;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
mpfr_set_prec(mpfrval, prec);
|
|
Packit |
575503 |
tval = mpfr_set_z(mpfrval, zi, ROUND_MODE);
|
|
Packit |
575503 |
IEEE_FMT(mpfrval, tval);
|
|
Packit |
575503 |
return mpfrval;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* format_tree() formats arguments of sprintf,
|
|
Packit |
575503 |
* and accordingly to a fmt_string providing a format like in
|
|
Packit |
575503 |
* printf family from C library. Returns a string node which value
|
|
Packit |
575503 |
* is a formatted string. Called by sprintf function.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* It is one of the uglier parts of gawk. Thanks to Michal Jaegermann
|
|
Packit |
575503 |
* for taming this beast and making it compatible with ANSI C.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
format_tree(
|
|
Packit |
575503 |
const char *fmt_string,
|
|
Packit |
575503 |
size_t n0,
|
|
Packit |
575503 |
NODE **the_args,
|
|
Packit |
575503 |
long num_args)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
|
|
Packit |
575503 |
/* difference of pointers should be of ptrdiff_t type, but let us be kind */
|
|
Packit |
575503 |
#define bchunk(s, l) if (l) { \
|
|
Packit |
575503 |
while ((l) > ofre) { \
|
|
Packit |
575503 |
size_t olen = obufout - obuf; \
|
|
Packit |
575503 |
erealloc(obuf, char *, osiz * 2, "format_tree"); \
|
|
Packit |
575503 |
ofre += osiz; \
|
|
Packit |
575503 |
osiz *= 2; \
|
|
Packit |
575503 |
obufout = obuf + olen; \
|
|
Packit |
575503 |
} \
|
|
Packit |
575503 |
memcpy(obufout, s, (size_t) (l)); \
|
|
Packit |
575503 |
obufout += (l); \
|
|
Packit |
575503 |
ofre -= (l); \
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* copy one byte from 's' to 'obufout' checking for space in the process */
|
|
Packit |
575503 |
#define bchunk_one(s) { \
|
|
Packit |
575503 |
if (ofre < 1) { \
|
|
Packit |
575503 |
size_t olen = obufout - obuf; \
|
|
Packit |
575503 |
erealloc(obuf, char *, osiz * 2, "format_tree"); \
|
|
Packit |
575503 |
ofre += osiz; \
|
|
Packit |
575503 |
osiz *= 2; \
|
|
Packit |
575503 |
obufout = obuf + olen; \
|
|
Packit |
575503 |
} \
|
|
Packit |
575503 |
*obufout++ = *s; \
|
|
Packit |
575503 |
--ofre; \
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* Is there space for something L big in the buffer? */
|
|
Packit |
575503 |
#define chksize(l) if ((l) >= ofre) { \
|
|
Packit |
575503 |
size_t olen = obufout - obuf; \
|
|
Packit |
575503 |
size_t delta = osiz+l-ofre; \
|
|
Packit |
575503 |
erealloc(obuf, char *, osiz + delta, "format_tree"); \
|
|
Packit |
575503 |
obufout = obuf + olen; \
|
|
Packit |
575503 |
ofre += delta; \
|
|
Packit |
575503 |
osiz += delta; \
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
size_t cur_arg = 0;
|
|
Packit |
575503 |
NODE *r = NULL;
|
|
Packit |
575503 |
int i, nc;
|
|
Packit |
575503 |
bool toofew = false;
|
|
Packit |
575503 |
char *obuf, *obufout;
|
|
Packit |
575503 |
size_t osiz, ofre, olen_final;
|
|
Packit |
575503 |
const char *chbuf;
|
|
Packit |
575503 |
const char *s0, *s1;
|
|
Packit |
575503 |
int cs1;
|
|
Packit |
575503 |
NODE *arg;
|
|
Packit |
575503 |
long fw, prec, argnum;
|
|
Packit |
575503 |
bool used_dollar;
|
|
Packit |
575503 |
bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
|
|
Packit |
575503 |
long *cur = NULL;
|
|
Packit |
575503 |
uintmax_t uval;
|
|
Packit |
575503 |
bool sgn;
|
|
Packit |
575503 |
int base;
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Although this is an array, the elements serve two different
|
|
Packit |
575503 |
* purposes. The first element is the general buffer meant
|
|
Packit |
575503 |
* to hold the entire result string. The second one is a
|
|
Packit |
575503 |
* temporary buffer for large floating point values. They
|
|
Packit |
575503 |
* could just as easily be separate variables, and the
|
|
Packit |
575503 |
* code might arguably be clearer.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
struct {
|
|
Packit |
575503 |
char *buf;
|
|
Packit |
575503 |
size_t bufsize;
|
|
Packit |
575503 |
char stackbuf[30];
|
|
Packit |
575503 |
} cpbufs[2];
|
|
Packit |
575503 |
#define cpbuf cpbufs[0].buf
|
|
Packit |
575503 |
char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
|
|
Packit |
575503 |
char *cp;
|
|
Packit |
575503 |
const char *fill;
|
|
Packit |
575503 |
AWKNUM tmpval = 0.0;
|
|
Packit |
575503 |
char signchar = '\0';
|
|
Packit |
575503 |
size_t len;
|
|
Packit |
575503 |
bool zero_flag = false;
|
|
Packit |
575503 |
bool quote_flag = false;
|
|
Packit |
575503 |
int ii, jj;
|
|
Packit |
575503 |
char *chp;
|
|
Packit |
575503 |
size_t copy_count, char_count;
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
mpz_ptr zi;
|
|
Packit |
575503 |
mpfr_ptr mf;
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
enum { MP_NONE = 0, MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static const char sp[] = " ";
|
|
Packit |
575503 |
static const char zero_string[] = "0";
|
|
Packit |
575503 |
static const char lchbuf[] = "0123456789abcdef";
|
|
Packit |
575503 |
static const char Uchbuf[] = "0123456789ABCDEF";
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#define INITIAL_OUT_SIZE 512
|
|
Packit |
575503 |
emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
|
|
Packit |
575503 |
obufout = obuf;
|
|
Packit |
575503 |
osiz = INITIAL_OUT_SIZE;
|
|
Packit |
575503 |
ofre = osiz - 1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
cur_arg = 1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
size_t k;
|
|
Packit |
575503 |
for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
|
|
Packit |
575503 |
cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
|
|
Packit |
575503 |
cpbufs[k].buf = cpbufs[k].stackbuf;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* The point of this goop is to grow the buffer
|
|
Packit |
575503 |
* holding the converted number, so that large
|
|
Packit |
575503 |
* values don't overflow a fixed length buffer.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
#define PREPEND(CH) do { \
|
|
Packit |
575503 |
if (cp == cpbufs[0].buf) { \
|
|
Packit |
575503 |
char *prev = cpbufs[0].buf; \
|
|
Packit |
575503 |
emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
|
|
Packit |
575503 |
"format_tree"); \
|
|
Packit |
575503 |
memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev, \
|
|
Packit |
575503 |
cpbufs[0].bufsize); \
|
|
Packit |
575503 |
cpbufs[0].bufsize *= 2; \
|
|
Packit |
575503 |
if (prev != cpbufs[0].stackbuf) \
|
|
Packit |
575503 |
efree(prev); \
|
|
Packit |
575503 |
cend = cpbufs[0].buf+cpbufs[0].bufsize; \
|
|
Packit |
575503 |
} \
|
|
Packit |
575503 |
*--cp = (CH); \
|
|
Packit |
575503 |
} while(0)
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Check first for use of `count$'.
|
|
Packit |
575503 |
* If plain argument retrieval was used earlier, choke.
|
|
Packit |
575503 |
* Otherwise, return the requested argument.
|
|
Packit |
575503 |
* If not `count$' now, but it was used earlier, choke.
|
|
Packit |
575503 |
* If this format is more than total number of args, choke.
|
|
Packit |
575503 |
* Otherwise, return the current argument.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
#define parse_next_arg() { \
|
|
Packit |
575503 |
if (argnum > 0) { \
|
|
Packit |
575503 |
if (cur_arg > 1) { \
|
|
Packit |
575503 |
msg(_("fatal: must use `count$' on all formats or none")); \
|
|
Packit |
575503 |
goto out; \
|
|
Packit |
575503 |
} \
|
|
Packit |
575503 |
arg = the_args[argnum]; \
|
|
Packit |
575503 |
} else if (used_dollar) { \
|
|
Packit |
575503 |
msg(_("fatal: must use `count$' on all formats or none")); \
|
|
Packit |
575503 |
arg = 0; /* shutup the compiler */ \
|
|
Packit |
575503 |
goto out; \
|
|
Packit |
575503 |
} else if (cur_arg >= num_args) { \
|
|
Packit |
575503 |
arg = 0; /* shutup the compiler */ \
|
|
Packit |
575503 |
toofew = true; \
|
|
Packit |
575503 |
break; \
|
|
Packit |
575503 |
} else { \
|
|
Packit |
575503 |
arg = the_args[cur_arg]; \
|
|
Packit |
575503 |
cur_arg++; \
|
|
Packit |
575503 |
} \
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
used_dollar = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
s0 = s1 = fmt_string;
|
|
Packit |
575503 |
while (n0-- > 0) {
|
|
Packit |
575503 |
if (*s1 != '%') {
|
|
Packit |
575503 |
s1++;
|
|
Packit |
575503 |
continue;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
need_format = true;
|
|
Packit |
575503 |
bchunk(s0, s1 - s0);
|
|
Packit |
575503 |
s0 = s1;
|
|
Packit |
575503 |
cur = &fw;
|
|
Packit |
575503 |
fw = 0;
|
|
Packit |
575503 |
prec = 0;
|
|
Packit |
575503 |
base = 0;
|
|
Packit |
575503 |
argnum = 0;
|
|
Packit |
575503 |
base = 0;
|
|
Packit |
575503 |
have_prec = false;
|
|
Packit |
575503 |
signchar = '\0';
|
|
Packit |
575503 |
zero_flag = false;
|
|
Packit |
575503 |
quote_flag = false;
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
mf = NULL;
|
|
Packit |
575503 |
zi = NULL;
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
fmt_type = MP_NONE;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
lj = alt = big_flag = bigbig_flag = small_flag = false;
|
|
Packit |
575503 |
fill = sp;
|
|
Packit |
575503 |
cp = cend;
|
|
Packit |
575503 |
chbuf = lchbuf;
|
|
Packit |
575503 |
s1++;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
retry:
|
|
Packit |
575503 |
if (n0-- == 0) /* ran out early! */
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
switch (cs1 = *s1++) {
|
|
Packit |
575503 |
case (-1): /* dummy case to allow for checking */
|
|
Packit |
575503 |
check_pos:
|
|
Packit |
575503 |
if (cur != &fw)
|
|
Packit |
575503 |
break; /* reject as a valid format */
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case '%':
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* 29 Oct. 2002:
|
|
Packit |
575503 |
* The C99 standard pages 274 and 279 seem to imply that
|
|
Packit |
575503 |
* since there's no arg converted, the field width doesn't
|
|
Packit |
575503 |
* apply. The code already was that way, but this
|
|
Packit |
575503 |
* comment documents it, at least in the code.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
const char *msg = NULL;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (fw && ! have_prec)
|
|
Packit |
575503 |
msg = _("field width is ignored for `%%' specifier");
|
|
Packit |
575503 |
else if (fw == 0 && have_prec)
|
|
Packit |
575503 |
msg = _("precision is ignored for `%%' specifier");
|
|
Packit |
575503 |
else if (fw && have_prec)
|
|
Packit |
575503 |
msg = _("field width and precision are ignored for `%%' specifier");
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (msg != NULL)
|
|
Packit |
575503 |
lintwarn("%s", msg);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
bchunk_one("%");
|
|
Packit |
575503 |
s0 = s1;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
case '0':
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Only turn on zero_flag if we haven't seen
|
|
Packit |
575503 |
* the field width or precision yet. Otherwise,
|
|
Packit |
575503 |
* screws up floating point formatting.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (cur == & fw)
|
|
Packit |
575503 |
zero_flag = true;
|
|
Packit |
575503 |
if (lj)
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
/* FALL through */
|
|
Packit |
575503 |
case '1':
|
|
Packit |
575503 |
case '2':
|
|
Packit |
575503 |
case '3':
|
|
Packit |
575503 |
case '4':
|
|
Packit |
575503 |
case '5':
|
|
Packit |
575503 |
case '6':
|
|
Packit |
575503 |
case '7':
|
|
Packit |
575503 |
case '8':
|
|
Packit |
575503 |
case '9':
|
|
Packit |
575503 |
if (cur == NULL)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
if (prec >= 0)
|
|
Packit |
575503 |
*cur = cs1 - '0';
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* with a negative precision *cur is already set
|
|
Packit |
575503 |
* to -1, so it will remain negative, but we have
|
|
Packit |
575503 |
* to "eat" precision digits in any case
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
|
|
Packit |
575503 |
--n0;
|
|
Packit |
575503 |
*cur = *cur * 10 + *s1++ - '0';
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (prec < 0) /* negative precision is discarded */
|
|
Packit |
575503 |
have_prec = false;
|
|
Packit |
575503 |
if (cur == &prec)
|
|
Packit |
575503 |
cur = NULL;
|
|
Packit |
575503 |
if (n0 == 0) /* badly formatted control string */
|
|
Packit |
575503 |
continue;
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case '$':
|
|
Packit |
575503 |
if (do_traditional) {
|
|
Packit |
575503 |
msg(_("fatal: `$' is not permitted in awk formats"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (cur == &fw) {
|
|
Packit |
575503 |
argnum = fw;
|
|
Packit |
575503 |
fw = 0;
|
|
Packit |
575503 |
used_dollar = true;
|
|
Packit |
575503 |
if (argnum <= 0) {
|
|
Packit |
575503 |
msg(_("fatal: arg count with `$' must be > 0"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (argnum >= num_args) {
|
|
Packit |
575503 |
msg(_("fatal: arg count %ld greater than total number of supplied arguments"), argnum);
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
msg(_("fatal: `$' not permitted after period in format"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case '*':
|
|
Packit |
575503 |
if (cur == NULL)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
if (! do_traditional && used_dollar && ! isdigit((unsigned char) *s1)) {
|
|
Packit |
575503 |
fatal(_("fatal: must use `count$' on all formats or none"));
|
|
Packit |
575503 |
break; /* silence warnings */
|
|
Packit |
575503 |
} else if (! do_traditional && isdigit((unsigned char) *s1)) {
|
|
Packit |
575503 |
int val = 0;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (; n0 > 0 && *s1 && isdigit((unsigned char) *s1); s1++, n0--) {
|
|
Packit |
575503 |
val *= 10;
|
|
Packit |
575503 |
val += *s1 - '0';
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (*s1 != '$') {
|
|
Packit |
575503 |
msg(_("fatal: no `$' supplied for positional field width or precision"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
s1++;
|
|
Packit |
575503 |
n0--;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (val >= num_args) {
|
|
Packit |
575503 |
toofew = true;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
arg = the_args[val];
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
parse_next_arg();
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
(void) force_number(arg);
|
|
Packit |
575503 |
*cur = get_number_si(arg);
|
|
Packit |
575503 |
if (*cur < 0 && cur == &fw) {
|
|
Packit |
575503 |
*cur = -*cur;
|
|
Packit |
575503 |
lj = true;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (cur == &prec) {
|
|
Packit |
575503 |
if (*cur >= 0)
|
|
Packit |
575503 |
have_prec = true;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
have_prec = false;
|
|
Packit |
575503 |
cur = NULL;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case ' ': /* print ' ' or '-' */
|
|
Packit |
575503 |
/* 'space' flag is ignored */
|
|
Packit |
575503 |
/* if '+' already present */
|
|
Packit |
575503 |
if (signchar != false)
|
|
Packit |
575503 |
goto check_pos;
|
|
Packit |
575503 |
/* FALL THROUGH */
|
|
Packit |
575503 |
case '+': /* print '+' or '-' */
|
|
Packit |
575503 |
signchar = cs1;
|
|
Packit |
575503 |
goto check_pos;
|
|
Packit |
575503 |
case '-':
|
|
Packit |
575503 |
if (prec < 0)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
if (cur == &prec) {
|
|
Packit |
575503 |
prec = -1;
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
fill = sp; /* if left justified then other */
|
|
Packit |
575503 |
lj = true; /* filling is ignored */
|
|
Packit |
575503 |
goto check_pos;
|
|
Packit |
575503 |
case '.':
|
|
Packit |
575503 |
if (cur != &fw)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
cur = ≺
|
|
Packit |
575503 |
have_prec = true;
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case '#':
|
|
Packit |
575503 |
alt = true;
|
|
Packit |
575503 |
goto check_pos;
|
|
Packit |
575503 |
case '\'':
|
|
Packit |
575503 |
#if defined(HAVE_LOCALE_H)
|
|
Packit |
575503 |
quote_flag = true;
|
|
Packit |
575503 |
goto check_pos;
|
|
Packit |
575503 |
#else
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
case 'l':
|
|
Packit |
575503 |
if (big_flag)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
static bool warned = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint && ! warned) {
|
|
Packit |
575503 |
lintwarn(_("`l' is meaningless in awk formats; ignored"));
|
|
Packit |
575503 |
warned = true;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (do_posix) {
|
|
Packit |
575503 |
msg(_("fatal: `l' is not permitted in POSIX awk formats"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
big_flag = true;
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case 'L':
|
|
Packit |
575503 |
if (bigbig_flag)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
static bool warned = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint && ! warned) {
|
|
Packit |
575503 |
lintwarn(_("`L' is meaningless in awk formats; ignored"));
|
|
Packit |
575503 |
warned = true;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (do_posix) {
|
|
Packit |
575503 |
msg(_("fatal: `L' is not permitted in POSIX awk formats"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
bigbig_flag = true;
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case 'h':
|
|
Packit |
575503 |
if (small_flag)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
static bool warned = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint && ! warned) {
|
|
Packit |
575503 |
lintwarn(_("`h' is meaningless in awk formats; ignored"));
|
|
Packit |
575503 |
warned = true;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (do_posix) {
|
|
Packit |
575503 |
msg(_("fatal: `h' is not permitted in POSIX awk formats"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
small_flag = true;
|
|
Packit |
575503 |
goto retry;
|
|
Packit |
575503 |
case 'c':
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
parse_next_arg();
|
|
Packit |
575503 |
/* user input that looks numeric is numeric */
|
|
Packit |
575503 |
fixtype(arg);
|
|
Packit |
575503 |
if ((arg->flags & NUMBER) != 0) {
|
|
Packit |
575503 |
uval = get_number_uj(arg);
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
char buf[100];
|
|
Packit |
575503 |
wchar_t wc;
|
|
Packit |
575503 |
mbstate_t mbs;
|
|
Packit |
575503 |
size_t count;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& mbs, 0, sizeof(mbs));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* handle systems with too small wchar_t */
|
|
Packit |
575503 |
if (sizeof(wchar_t) < 4 && uval > 0xffff) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("[s]printf: value %g is too big for %%c format"),
|
|
Packit |
575503 |
arg->numbr);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
goto out0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
wc = uval;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
count = wcrtomb(buf, wc, & mbs);
|
|
Packit |
575503 |
if (count == 0
|
|
Packit |
575503 |
|| count == (size_t) -1) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("[s]printf: value %g is not a valid wide character"),
|
|
Packit |
575503 |
arg->numbr);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
goto out0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memcpy(cpbuf, buf, count);
|
|
Packit |
575503 |
prec = count;
|
|
Packit |
575503 |
cp = cpbuf;
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
out0:
|
|
Packit |
575503 |
;
|
|
Packit |
575503 |
/* else,
|
|
Packit |
575503 |
fall through */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
cpbuf[0] = uval;
|
|
Packit |
575503 |
prec = 1;
|
|
Packit |
575503 |
cp = cpbuf;
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* As per POSIX, only output first character of a
|
|
Packit |
575503 |
* string value. Thus, we ignore any provided
|
|
Packit |
575503 |
* precision, forcing it to 1. (Didn't this
|
|
Packit |
575503 |
* used to work? 6/2003.)
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
cp = arg->stptr;
|
|
Packit |
575503 |
prec = 1;
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* First character can be multiple bytes if
|
|
Packit |
575503 |
* it's a multibyte character. Grr.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
mbstate_t state;
|
|
Packit |
575503 |
size_t count;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& state, 0, sizeof(state));
|
|
Packit |
575503 |
count = mbrlen(cp, arg->stlen, & state);
|
|
Packit |
575503 |
if (count != (size_t) -1 && count != (size_t) -2 && count > 0) {
|
|
Packit |
575503 |
prec = count;
|
|
Packit |
575503 |
/* may need to increase fw so that padding happens, see pr_tail code */
|
|
Packit |
575503 |
if (fw > 0)
|
|
Packit |
575503 |
fw += count - 1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
case 's':
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
parse_next_arg();
|
|
Packit |
575503 |
arg = force_string(arg);
|
|
Packit |
575503 |
if (fw == 0 && ! have_prec)
|
|
Packit |
575503 |
prec = arg->stlen;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
char_count = mbc_char_count(arg->stptr, arg->stlen);
|
|
Packit |
575503 |
if (! have_prec || prec > char_count)
|
|
Packit |
575503 |
prec = char_count;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
cp = arg->stptr;
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
case 'd':
|
|
Packit |
575503 |
case 'i':
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
parse_next_arg();
|
|
Packit |
575503 |
(void) force_number(arg);
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
if (is_mpg_float(arg))
|
|
Packit |
575503 |
goto mpf0;
|
|
Packit |
575503 |
else if (is_mpg_integer(arg))
|
|
Packit |
575503 |
goto mpz0;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
tmpval = arg->numbr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Check for Nan or Inf.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (isnan(tmpval) || isinf(tmpval))
|
|
Packit |
575503 |
goto out_of_range;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
tmpval = double_to_int(tmpval);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* ``The result of converting a zero value with a
|
|
Packit |
575503 |
* precision of zero is no characters.''
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (have_prec && prec == 0 && tmpval == 0)
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (tmpval < 0) {
|
|
Packit |
575503 |
tmpval = -tmpval;
|
|
Packit |
575503 |
sgn = true;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
if (tmpval == -0.0)
|
|
Packit |
575503 |
/* avoid printing -0 */
|
|
Packit |
575503 |
tmpval = 0.0;
|
|
Packit |
575503 |
sgn = false;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Use snprintf return value to tell if there
|
|
Packit |
575503 |
* is enough room in the buffer or not.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
while ((i = snprintf(cpbufs[1].buf,
|
|
Packit |
575503 |
cpbufs[1].bufsize, "%.0f",
|
|
Packit |
575503 |
tmpval)) >=
|
|
Packit |
575503 |
cpbufs[1].bufsize) {
|
|
Packit |
575503 |
if (cpbufs[1].buf == cpbufs[1].stackbuf)
|
|
Packit |
575503 |
cpbufs[1].buf = NULL;
|
|
Packit |
575503 |
if (i > 0) {
|
|
Packit |
575503 |
cpbufs[1].bufsize += ((i > cpbufs[1].bufsize) ?
|
|
Packit |
575503 |
i : cpbufs[1].bufsize);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
cpbufs[1].bufsize *= 2;
|
|
Packit |
575503 |
assert(cpbufs[1].bufsize > 0);
|
|
Packit |
575503 |
erealloc(cpbufs[1].buf, char *,
|
|
Packit |
575503 |
cpbufs[1].bufsize, "format_tree");
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (i < 1)
|
|
Packit |
575503 |
goto out_of_range;
|
|
Packit |
575503 |
#if defined(HAVE_LOCALE_H)
|
|
Packit |
575503 |
quote_flag = (quote_flag && loc.thousands_sep[0] != 0);
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
chp = &cpbufs[1].buf[i-1];
|
|
Packit |
575503 |
ii = jj = 0;
|
|
Packit |
575503 |
do {
|
|
Packit |
575503 |
PREPEND(*chp);
|
|
Packit |
575503 |
chp--; i--;
|
|
Packit |
575503 |
#if defined(HAVE_LOCALE_H)
|
|
Packit |
575503 |
if (quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
|
|
Packit |
575503 |
if (i) { /* only add if more digits coming */
|
|
Packit |
575503 |
int k;
|
|
Packit |
575503 |
const char *ts = loc.thousands_sep;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (k = strlen(ts) - 1; k >= 0; k--) {
|
|
Packit |
575503 |
PREPEND(ts[k]);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (loc.grouping[ii+1] == 0)
|
|
Packit |
575503 |
jj = 0; /* keep using current val in loc.grouping[ii] */
|
|
Packit |
575503 |
else if (loc.grouping[ii+1] == CHAR_MAX)
|
|
Packit |
575503 |
quote_flag = false;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
ii++;
|
|
Packit |
575503 |
jj = 0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
} while (i > 0);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* add more output digits to match the precision */
|
|
Packit |
575503 |
if (have_prec) {
|
|
Packit |
575503 |
while (cend - cp < prec)
|
|
Packit |
575503 |
PREPEND('0');
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (sgn)
|
|
Packit |
575503 |
PREPEND('-');
|
|
Packit |
575503 |
else if (signchar)
|
|
Packit |
575503 |
PREPEND(signchar);
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* When to fill with zeroes is of course not simple.
|
|
Packit |
575503 |
* First: No zero fill if left-justifying.
|
|
Packit |
575503 |
* Next: There seem to be two cases:
|
|
Packit |
575503 |
* A '0' without a precision, e.g. %06d
|
|
Packit |
575503 |
* A precision with no field width, e.g. %.10d
|
|
Packit |
575503 |
* Any other case, we don't want to fill with zeroes.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (! lj
|
|
Packit |
575503 |
&& ((zero_flag && ! have_prec)
|
|
Packit |
575503 |
|| (fw == 0 && have_prec)))
|
|
Packit |
575503 |
fill = zero_string;
|
|
Packit |
575503 |
if (prec > fw)
|
|
Packit |
575503 |
fw = prec;
|
|
Packit |
575503 |
prec = cend - cp;
|
|
Packit |
575503 |
if (fw > prec && ! lj && fill != sp
|
|
Packit |
575503 |
&& (*cp == '-' || signchar)) {
|
|
Packit |
575503 |
bchunk_one(cp);
|
|
Packit |
575503 |
cp++;
|
|
Packit |
575503 |
prec--;
|
|
Packit |
575503 |
fw--;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
case 'X':
|
|
Packit |
575503 |
chbuf = Uchbuf; /* FALL THROUGH */
|
|
Packit |
575503 |
case 'x':
|
|
Packit |
575503 |
base += 6; /* FALL THROUGH */
|
|
Packit |
575503 |
case 'u':
|
|
Packit |
575503 |
base += 2; /* FALL THROUGH */
|
|
Packit |
575503 |
case 'o':
|
|
Packit |
575503 |
base += 8;
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
parse_next_arg();
|
|
Packit |
575503 |
(void) force_number(arg);
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
if (is_mpg_integer(arg)) {
|
|
Packit |
575503 |
mpz0:
|
|
Packit |
575503 |
zi = arg->mpg_i;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (cs1 != 'd' && cs1 != 'i') {
|
|
Packit |
575503 |
if (mpz_sgn(zi) <= 0) {
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Negative value or 0 requires special handling.
|
|
Packit |
575503 |
* Unlike MPFR, GMP does not allow conversion
|
|
Packit |
575503 |
* to (u)intmax_t. So we first convert GMP type to
|
|
Packit |
575503 |
* a MPFR type.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
mf = mpz2mpfr(zi);
|
|
Packit |
575503 |
goto mpf1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
signchar = '\0'; /* Don't print '+' */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* See comments above about when to fill with zeros */
|
|
Packit |
575503 |
zero_flag = (! lj
|
|
Packit |
575503 |
&& ((zero_flag && ! have_prec)
|
|
Packit |
575503 |
|| (fw == 0 && have_prec)));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
|
|
Packit |
575503 |
goto fmt0;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
} else if (is_mpg_float(arg)) {
|
|
Packit |
575503 |
mpf0:
|
|
Packit |
575503 |
mf = arg->mpg_numbr;
|
|
Packit |
575503 |
if (! mpfr_number_p(mf)) {
|
|
Packit |
575503 |
/* inf or NaN */
|
|
Packit |
575503 |
cs1 = 'g';
|
|
Packit |
575503 |
fmt_type = MP_FLOAT;
|
|
Packit |
575503 |
goto fmt1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (cs1 != 'd' && cs1 != 'i') {
|
|
Packit |
575503 |
mpf1:
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* The output of printf("%#.0x", 0) is 0 instead of 0x, hence <= in
|
|
Packit |
575503 |
* the comparison below.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (mpfr_sgn(mf) <= 0) {
|
|
Packit |
575503 |
if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) {
|
|
Packit |
575503 |
/* -ve number is too large */
|
|
Packit |
575503 |
cs1 = 'g';
|
|
Packit |
575503 |
fmt_type = MP_FLOAT;
|
|
Packit |
575503 |
goto fmt1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmpval = uval = (uintmax_t) mpfr_get_sj(mf, ROUND_MODE);
|
|
Packit |
575503 |
if (! alt && have_prec && prec == 0 && tmpval == 0)
|
|
Packit |
575503 |
goto pr_tail; /* printf("%.0x", 0) is no characters */
|
|
Packit |
575503 |
goto int0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
signchar = '\0'; /* Don't print '+' */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* See comments above about when to fill with zeros */
|
|
Packit |
575503 |
zero_flag = (! lj
|
|
Packit |
575503 |
&& ((zero_flag && ! have_prec)
|
|
Packit |
575503 |
|| (fw == 0 && have_prec)));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
(void) mpfr_get_z(mpzval, mf, MPFR_RNDZ); /* convert to GMP integer */
|
|
Packit |
575503 |
fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
|
|
Packit |
575503 |
zi = mpzval;
|
|
Packit |
575503 |
goto fmt0;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
tmpval = arg->numbr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* ``The result of converting a zero value with a
|
|
Packit |
575503 |
* precision of zero is no characters.''
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* If I remember the ANSI C standard, though,
|
|
Packit |
575503 |
* it says that for octal conversions
|
|
Packit |
575503 |
* the precision is artificially increased
|
|
Packit |
575503 |
* to add an extra 0 if # is supplied.
|
|
Packit |
575503 |
* Indeed, in C,
|
|
Packit |
575503 |
* printf("%#.0o\n", 0);
|
|
Packit |
575503 |
* prints a single 0.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (! alt && have_prec && prec == 0 && tmpval == 0)
|
|
Packit |
575503 |
goto pr_tail;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (tmpval < 0) {
|
|
Packit |
575503 |
uval = (uintmax_t) (intmax_t) tmpval;
|
|
Packit |
575503 |
if ((AWKNUM)(intmax_t)uval != double_to_int(tmpval))
|
|
Packit |
575503 |
goto out_of_range;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
uval = (uintmax_t) tmpval;
|
|
Packit |
575503 |
if ((AWKNUM)uval != double_to_int(tmpval))
|
|
Packit |
575503 |
goto out_of_range;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
int0:
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
#if defined(HAVE_LOCALE_H)
|
|
Packit |
575503 |
quote_flag = (quote_flag && loc.thousands_sep[0] != 0);
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* When to fill with zeroes is of course not simple.
|
|
Packit |
575503 |
* First: No zero fill if left-justifying.
|
|
Packit |
575503 |
* Next: There seem to be two cases:
|
|
Packit |
575503 |
* A '0' without a precision, e.g. %06d
|
|
Packit |
575503 |
* A precision with no field width, e.g. %.10d
|
|
Packit |
575503 |
* Any other case, we don't want to fill with zeroes.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (! lj
|
|
Packit |
575503 |
&& ((zero_flag && ! have_prec)
|
|
Packit |
575503 |
|| (fw == 0 && have_prec)))
|
|
Packit |
575503 |
fill = zero_string;
|
|
Packit |
575503 |
ii = jj = 0;
|
|
Packit |
575503 |
do {
|
|
Packit |
575503 |
PREPEND(chbuf[uval % base]);
|
|
Packit |
575503 |
uval /= base;
|
|
Packit |
575503 |
#if defined(HAVE_LOCALE_H)
|
|
Packit |
575503 |
if (base == 10 && quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
|
|
Packit |
575503 |
if (uval) { /* only add if more digits coming */
|
|
Packit |
575503 |
int k;
|
|
Packit |
575503 |
const char *ts = loc.thousands_sep;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (k = strlen(ts) - 1; k >= 0; k--) {
|
|
Packit |
575503 |
PREPEND(ts[k]);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (loc.grouping[ii+1] == 0)
|
|
Packit |
575503 |
jj = 0; /* keep using current val in loc.grouping[ii] */
|
|
Packit |
575503 |
else if (loc.grouping[ii+1] == CHAR_MAX)
|
|
Packit |
575503 |
quote_flag = false;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
ii++;
|
|
Packit |
575503 |
jj = 0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
} while (uval > 0);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* add more output digits to match the precision */
|
|
Packit |
575503 |
if (have_prec) {
|
|
Packit |
575503 |
while (cend - cp < prec)
|
|
Packit |
575503 |
PREPEND('0');
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (alt && tmpval != 0) {
|
|
Packit |
575503 |
if (base == 16) {
|
|
Packit |
575503 |
PREPEND(cs1);
|
|
Packit |
575503 |
PREPEND('0');
|
|
Packit |
575503 |
if (fill != sp) {
|
|
Packit |
575503 |
bchunk(cp, 2);
|
|
Packit |
575503 |
cp += 2;
|
|
Packit |
575503 |
fw -= 2;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else if (base == 8)
|
|
Packit |
575503 |
PREPEND('0');
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
base = 0;
|
|
Packit |
575503 |
if (prec > fw)
|
|
Packit |
575503 |
fw = prec;
|
|
Packit |
575503 |
prec = cend - cp;
|
|
Packit |
575503 |
pr_tail:
|
|
Packit |
575503 |
if (! lj) {
|
|
Packit |
575503 |
while (fw > prec) {
|
|
Packit |
575503 |
bchunk_one(fill);
|
|
Packit |
575503 |
fw--;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
copy_count = prec;
|
|
Packit |
575503 |
if (fw == 0 && ! have_prec)
|
|
Packit |
575503 |
;
|
|
Packit |
575503 |
else if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
if (cs1 == 's') {
|
|
Packit |
575503 |
assert(cp == arg->stptr || cp == cpbuf);
|
|
Packit |
575503 |
copy_count = mbc_byte_count(arg->stptr, prec);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/* prec was set by code for %c */
|
|
Packit |
575503 |
/* else
|
|
Packit |
575503 |
copy_count = prec; */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
bchunk(cp, copy_count);
|
|
Packit |
575503 |
while (fw > prec) {
|
|
Packit |
575503 |
bchunk_one(fill);
|
|
Packit |
575503 |
fw--;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
s0 = s1;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
out_of_range:
|
|
Packit |
575503 |
/* out of range - emergency use of %g format */
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"),
|
|
Packit |
575503 |
(double) tmpval, cs1);
|
|
Packit |
575503 |
cs1 = 'g';
|
|
Packit |
575503 |
goto fmt1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
case 'F':
|
|
Packit |
575503 |
#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
|
|
Packit |
575503 |
cs1 = 'f';
|
|
Packit |
575503 |
/* FALL THROUGH */
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
case 'g':
|
|
Packit |
575503 |
case 'G':
|
|
Packit |
575503 |
case 'e':
|
|
Packit |
575503 |
case 'f':
|
|
Packit |
575503 |
case 'E':
|
|
Packit |
575503 |
need_format = false;
|
|
Packit |
575503 |
parse_next_arg();
|
|
Packit |
575503 |
(void) force_number(arg);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (! is_mpg_number(arg))
|
|
Packit |
575503 |
tmpval = arg->numbr;
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
else if (is_mpg_float(arg)) {
|
|
Packit |
575503 |
mf = arg->mpg_numbr;
|
|
Packit |
575503 |
fmt_type = MP_FLOAT;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/* arbitrary-precision integer, convert to MPFR float */
|
|
Packit |
575503 |
assert(mf == NULL);
|
|
Packit |
575503 |
mf = mpz2mpfr(arg->mpg_i);
|
|
Packit |
575503 |
fmt_type = MP_FLOAT;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
fmt1:
|
|
Packit |
575503 |
if (! have_prec)
|
|
Packit |
575503 |
prec = DEFAULT_G_PRECISION;
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
fmt0:
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
chksize(fw + prec + 11); /* 11 == slop */
|
|
Packit |
575503 |
cp = cpbuf;
|
|
Packit |
575503 |
*cp++ = '%';
|
|
Packit |
575503 |
if (lj)
|
|
Packit |
575503 |
*cp++ = '-';
|
|
Packit |
575503 |
if (signchar)
|
|
Packit |
575503 |
*cp++ = signchar;
|
|
Packit |
575503 |
if (alt)
|
|
Packit |
575503 |
*cp++ = '#';
|
|
Packit |
575503 |
if (zero_flag)
|
|
Packit |
575503 |
*cp++ = '0';
|
|
Packit |
575503 |
if (quote_flag)
|
|
Packit |
575503 |
*cp++ = '\'';
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if defined(LC_NUMERIC)
|
|
Packit |
575503 |
if (quote_flag && ! use_lc_numeric)
|
|
Packit |
575503 |
setlocale(LC_NUMERIC, "");
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
switch (fmt_type) {
|
|
Packit |
575503 |
#ifdef HAVE_MPFR
|
|
Packit |
575503 |
case MP_INT_WITH_PREC:
|
|
Packit |
575503 |
sprintf(cp, "*.*Z%c", cs1);
|
|
Packit |
575503 |
while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
|
|
Packit |
575503 |
(int) fw, (int) prec, zi)) >= ofre)
|
|
Packit |
575503 |
chksize(nc)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case MP_INT_WITHOUT_PREC:
|
|
Packit |
575503 |
sprintf(cp, "*Z%c", cs1);
|
|
Packit |
575503 |
while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
|
|
Packit |
575503 |
(int) fw, zi)) >= ofre)
|
|
Packit |
575503 |
chksize(nc)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case MP_FLOAT:
|
|
Packit |
575503 |
sprintf(cp, "*.*R*%c", cs1);
|
|
Packit |
575503 |
while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
|
|
Packit |
575503 |
(int) fw, (int) prec, ROUND_MODE, mf)) >= ofre)
|
|
Packit |
575503 |
chksize(nc)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
default:
|
|
Packit |
575503 |
sprintf(cp, "*.*%c", cs1);
|
|
Packit |
575503 |
while ((nc = snprintf(obufout, ofre, cpbuf,
|
|
Packit |
575503 |
(int) fw, (int) prec,
|
|
Packit |
575503 |
(double) tmpval)) >= ofre)
|
|
Packit |
575503 |
chksize(nc)
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if defined(LC_NUMERIC)
|
|
Packit |
575503 |
if (quote_flag && ! use_lc_numeric)
|
|
Packit |
575503 |
setlocale(LC_NUMERIC, "C");
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
len = strlen(obufout);
|
|
Packit |
575503 |
ofre -= len;
|
|
Packit |
575503 |
obufout += len;
|
|
Packit |
575503 |
s0 = s1;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
default:
|
|
Packit |
575503 |
if (do_lint && is_alpha(cs1))
|
|
Packit |
575503 |
lintwarn(_("ignoring unknown format specifier character `%c': no argument converted"), cs1);
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (toofew) {
|
|
Packit |
575503 |
msg("%s\n\t`%s'\n\t%*s%s",
|
|
Packit |
575503 |
_("fatal: not enough arguments to satisfy format string"),
|
|
Packit |
575503 |
fmt_string, (int) (s1 - fmt_string - 1), "",
|
|
Packit |
575503 |
_("^ ran out for this one"));
|
|
Packit |
575503 |
goto out;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if (need_format)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("[s]printf: format specifier does not have control letter"));
|
|
Packit |
575503 |
if (cur_arg < num_args)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("too many arguments supplied for format string"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
bchunk(s0, s1 - s0);
|
|
Packit |
575503 |
olen_final = obufout - obuf;
|
|
Packit |
575503 |
if (ofre > 0)
|
|
Packit |
575503 |
erealloc(obuf, char *, olen_final + 1, "format_tree");
|
|
Packit |
575503 |
r = make_str_node(obuf, olen_final, ALREADY_MALLOCED);
|
|
Packit |
575503 |
obuf = NULL;
|
|
Packit |
575503 |
out:
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
size_t k;
|
|
Packit |
575503 |
size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
|
|
Packit |
575503 |
for (k = 0; k < count; k++) {
|
|
Packit |
575503 |
if (cpbufs[k].buf != cpbufs[k].stackbuf)
|
|
Packit |
575503 |
efree(cpbufs[k].buf);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (obuf != NULL)
|
|
Packit |
575503 |
efree(obuf);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (r == NULL)
|
|
Packit |
575503 |
gawk_exit(EXIT_FATAL);
|
|
Packit |
575503 |
return r;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* printf_common --- common code for sprintf and printf */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static NODE *
|
|
Packit |
575503 |
printf_common(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
int i;
|
|
Packit |
575503 |
NODE *r, *tmp;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
assert(nargs > 0 && nargs <= max_args);
|
|
Packit |
575503 |
for (i = 1; i <= nargs; i++) {
|
|
Packit |
575503 |
tmp = args_array[nargs - i] = POP();
|
|
Packit |
575503 |
if (tmp->type == Node_var_array) {
|
|
Packit |
575503 |
while (--i > 0)
|
|
Packit |
575503 |
DEREF(args_array[nargs - i]);
|
|
Packit |
575503 |
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
args_array[0] = force_string(args_array[0]);
|
|
Packit |
575503 |
r = format_tree(args_array[0]->stptr, args_array[0]->stlen, args_array, nargs);
|
|
Packit |
575503 |
for (i = 0; i < nargs; i++)
|
|
Packit |
575503 |
DEREF(args_array[i]);
|
|
Packit |
575503 |
return r;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_sprintf --- perform sprintf */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_sprintf(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *r;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 0)
|
|
Packit |
575503 |
fatal(_("sprintf: no arguments"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
r = printf_common(nargs);
|
|
Packit |
575503 |
if (r == NULL)
|
|
Packit |
575503 |
gawk_exit(EXIT_FATAL);
|
|
Packit |
575503 |
return r;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_printf --- perform printf, including redirection */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
void
|
|
Packit |
575503 |
do_printf(int nargs, int redirtype)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
FILE *fp = NULL;
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
struct redirect *rp = NULL;
|
|
Packit |
575503 |
int errflg = 0;
|
|
Packit |
575503 |
NODE *redir_exp = NULL;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 0) {
|
|
Packit |
575503 |
if (do_traditional) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("printf: no arguments"));
|
|
Packit |
575503 |
if (redirtype != 0) {
|
|
Packit |
575503 |
redir_exp = TOP();
|
|
Packit |
575503 |
if (redir_exp->type != Node_val)
|
|
Packit |
575503 |
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
|
|
Packit |
575503 |
rp = redirect(redir_exp, redirtype, & errflg, true);
|
|
Packit |
575503 |
DEREF(redir_exp);
|
|
Packit |
575503 |
decr_sp();
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
return; /* bwk accepts it silently */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
fatal(_("printf: no arguments"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (redirtype != 0) {
|
|
Packit |
575503 |
redir_exp = PEEK(nargs);
|
|
Packit |
575503 |
if (redir_exp->type != Node_val)
|
|
Packit |
575503 |
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
|
|
Packit |
575503 |
rp = redirect(redir_exp, redirtype, & errflg, true);
|
|
Packit |
575503 |
if (rp != NULL) {
|
|
Packit |
575503 |
if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) {
|
|
Packit |
575503 |
if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
|
|
Packit |
575503 |
update_ERRNO_int(EBADF);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
(void) close_rp(rp, CLOSE_ALL);
|
|
Packit |
575503 |
fatal(_("printf: attempt to write to closed write end of two-way pipe"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
fp = rp->output.fp;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
else if (errflg) {
|
|
Packit |
575503 |
update_ERRNO_int(errflg);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else if (do_debug) /* only the debugger can change the default output */
|
|
Packit |
575503 |
fp = output_fp;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
fp = stdout;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = printf_common(nargs);
|
|
Packit |
575503 |
if (redir_exp != NULL) {
|
|
Packit |
575503 |
DEREF(redir_exp);
|
|
Packit |
575503 |
decr_sp();
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (tmp != NULL) {
|
|
Packit |
575503 |
if (fp == NULL) {
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
efwrite(tmp->stptr, sizeof(char), tmp->stlen, fp, "printf", rp, true);
|
|
Packit |
575503 |
if (rp != NULL && (rp->flag & RED_TWOWAY) != 0)
|
|
Packit |
575503 |
rp->output.gawk_fflush(rp->output.fp, rp->output.opaque);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
gawk_exit(EXIT_FATAL);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_sqrt --- do the sqrt function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_sqrt(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double arg;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("sqrt: received non-numeric argument"));
|
|
Packit |
575503 |
arg = (double) force_number(tmp)->numbr;
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
if (arg < 0.0)
|
|
Packit |
575503 |
warning(_("sqrt: called with negative argument %g"), arg);
|
|
Packit |
575503 |
return make_number((AWKNUM) sqrt(arg));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_substr --- do the substr function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_substr(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1;
|
|
Packit |
575503 |
NODE *r;
|
|
Packit |
575503 |
size_t indx;
|
|
Packit |
575503 |
size_t length = 0;
|
|
Packit |
575503 |
double d_index = 0, d_length = 0;
|
|
Packit |
575503 |
size_t src_len;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 3) {
|
|
Packit |
575503 |
t1 = POP_NUMBER();
|
|
Packit |
575503 |
d_length = get_number_d(t1);
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = POP_NUMBER();
|
|
Packit |
575503 |
d_index = get_number_d(t1);
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = POP_STRING();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 3) {
|
|
Packit |
575503 |
if (! (d_length >= 1)) {
|
|
Packit |
575503 |
if (do_lint == DO_LINT_ALL)
|
|
Packit |
575503 |
lintwarn(_("substr: length %g is not >= 1"), d_length);
|
|
Packit |
575503 |
else if (do_lint == DO_LINT_INVALID && ! (d_length >= 0))
|
|
Packit |
575503 |
lintwarn(_("substr: length %g is not >= 0"), d_length);
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Return explicit null string instead of doing
|
|
Packit |
575503 |
* dupnode(Nnull_string) so that if the result
|
|
Packit |
575503 |
* is checked with the combination of length()
|
|
Packit |
575503 |
* and lint, no error is reported about using
|
|
Packit |
575503 |
* an uninitialized value. Same thing later, too.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
return make_string("", 0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if (double_to_int(d_length) != d_length)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("substr: non-integer length %g will be truncated"),
|
|
Packit |
575503 |
d_length);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (d_length > SIZE_MAX)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("substr: length %g too big for string indexing, truncating to %g"),
|
|
Packit |
575503 |
d_length, (double) SIZE_MAX);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (d_length < SIZE_MAX)
|
|
Packit |
575503 |
length = d_length;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
length = SIZE_MAX;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* the weird `! (foo)' tests help catch NaN values. */
|
|
Packit |
575503 |
if (! (d_index >= 1)) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("substr: start index %g is invalid, using 1"),
|
|
Packit |
575503 |
d_index);
|
|
Packit |
575503 |
d_index = 1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (do_lint && double_to_int(d_index) != d_index)
|
|
Packit |
575503 |
lintwarn(_("substr: non-integer start index %g will be truncated"),
|
|
Packit |
575503 |
d_index);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* awk indices are from 1, C's are from 0 */
|
|
Packit |
575503 |
if (d_index <= SIZE_MAX)
|
|
Packit |
575503 |
indx = d_index - 1;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
indx = SIZE_MAX;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 2) { /* third arg. missing */
|
|
Packit |
575503 |
/* use remainder of string */
|
|
Packit |
575503 |
length = t1->stlen - indx; /* default to bytes */
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
t1 = force_wstring(t1);
|
|
Packit |
575503 |
if (t1->wstlen > 0) /* use length of wide char string if we have one */
|
|
Packit |
575503 |
length = t1->wstlen - indx;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
d_length = length; /* set here in case used in diagnostics, below */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (t1->stlen == 0) {
|
|
Packit |
575503 |
/* substr("", 1, 0) produces a warning only if LINT_ALL */
|
|
Packit |
575503 |
if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 0)))
|
|
Packit |
575503 |
lintwarn(_("substr: source string is zero length"));
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return make_string("", 0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* get total len of input string, for following checks */
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
t1 = force_wstring(t1);
|
|
Packit |
575503 |
src_len = t1->wstlen;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
src_len = t1->stlen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (indx >= src_len) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("substr: start index %g is past end of string"),
|
|
Packit |
575503 |
d_index);
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return make_string("", 0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (length > src_len - indx) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(
|
|
Packit |
575503 |
_("substr: length %g at start index %g exceeds length of first argument (%lu)"),
|
|
Packit |
575503 |
d_length, d_index, (unsigned long int) src_len);
|
|
Packit |
575503 |
length = src_len - indx;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* force_wstring() already called */
|
|
Packit |
575503 |
if (gawk_mb_cur_max == 1 || t1->wstlen == t1->stlen)
|
|
Packit |
575503 |
/* single byte case */
|
|
Packit |
575503 |
r = make_string(t1->stptr + indx, length);
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
/* multibyte case, more work */
|
|
Packit |
575503 |
size_t result;
|
|
Packit |
575503 |
wchar_t *wp;
|
|
Packit |
575503 |
mbstate_t mbs;
|
|
Packit |
575503 |
char *substr, *cp;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Convert the wide chars in t1->wstptr back into m.b. chars.
|
|
Packit |
575503 |
* This is pretty grotty, but it's the most straightforward
|
|
Packit |
575503 |
* way to do things.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
memset(& mbs, 0, sizeof(mbs));
|
|
Packit |
575503 |
emalloc(substr, char *, (length * gawk_mb_cur_max) + 1, "do_substr");
|
|
Packit |
575503 |
wp = t1->wstptr + indx;
|
|
Packit |
575503 |
for (cp = substr; length > 0; length--) {
|
|
Packit |
575503 |
result = wcrtomb(cp, *wp, & mbs);
|
|
Packit |
575503 |
if (result == (size_t) -1) /* what to do? break seems best */
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
cp += result;
|
|
Packit |
575503 |
wp++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
*cp = '\0';
|
|
Packit |
575503 |
r = make_str_node(substr, cp - substr, ALREADY_MALLOCED);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return r;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_strftime --- format a time stamp */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_strftime(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1, *t2, *t3, *ret;
|
|
Packit |
575503 |
struct tm *tm;
|
|
Packit |
575503 |
time_t fclock;
|
|
Packit |
575503 |
double clock_val;
|
|
Packit |
575503 |
char *bufp;
|
|
Packit |
575503 |
size_t buflen, bufsize;
|
|
Packit |
575503 |
char buf[BUFSIZ];
|
|
Packit |
575503 |
const char *format;
|
|
Packit |
575503 |
int formatlen;
|
|
Packit |
575503 |
bool do_gmt;
|
|
Packit |
575503 |
NODE *val = NULL;
|
|
Packit |
575503 |
NODE *sub = NULL;
|
|
Packit |
575503 |
char save = '\0'; // initialize to avoid compiler warnings
|
|
Packit |
575503 |
static const time_t time_t_min = TYPE_MINIMUM(time_t);
|
|
Packit |
575503 |
static const time_t time_t_max = TYPE_MAXIMUM(time_t);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* set defaults first */
|
|
Packit |
575503 |
format = def_strftime_format; /* traditional date format */
|
|
Packit |
575503 |
formatlen = strlen(format);
|
|
Packit |
575503 |
(void) time(& fclock); /* current time of day */
|
|
Packit |
575503 |
do_gmt = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (PROCINFO_node != NULL) {
|
|
Packit |
575503 |
sub = make_string("strftime", 8);
|
|
Packit |
575503 |
val = in_array(PROCINFO_node, sub);
|
|
Packit |
575503 |
unref(sub);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (val != NULL) {
|
|
Packit |
575503 |
if (do_lint && (fixtype(val)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("strftime: format value in PROCINFO[\"strftime\"] has numeric type"));
|
|
Packit |
575503 |
val = force_string(val);
|
|
Packit |
575503 |
format = val->stptr;
|
|
Packit |
575503 |
formatlen = val->stlen;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = t2 = t3 = NULL;
|
|
Packit |
575503 |
if (nargs > 0) { /* have args */
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 3) {
|
|
Packit |
575503 |
t3 = POP_SCALAR();
|
|
Packit |
575503 |
do_gmt = boolval(t3);
|
|
Packit |
575503 |
DEREF(t3);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs >= 2) {
|
|
Packit |
575503 |
t2 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(t2)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("strftime: received non-numeric second argument"));
|
|
Packit |
575503 |
(void) force_number(t2);
|
|
Packit |
575503 |
clock_val = get_number_d(t2);
|
|
Packit |
575503 |
fclock = (time_t) clock_val;
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Protect against negative value being assigned
|
|
Packit |
575503 |
* to unsigned time_t.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (clock_val < 0 && fclock > 0) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("strftime: second argument less than 0 or too big for time_t"));
|
|
Packit |
575503 |
return make_string("", 0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* And check that the value is in range */
|
|
Packit |
575503 |
if (clock_val < time_t_min || clock_val > time_t_max) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("strftime: second argument out of range for time_t"));
|
|
Packit |
575503 |
return make_string("", 0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("strftime: received non-string first argument"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = force_string(tmp);
|
|
Packit |
575503 |
format = t1->stptr;
|
|
Packit |
575503 |
formatlen = t1->stlen;
|
|
Packit |
575503 |
if (formatlen == 0) {
|
|
Packit |
575503 |
if (do_lint)
|
|
Packit |
575503 |
lintwarn(_("strftime: received empty format string"));
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return make_string("", 0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
str_terminate(t1, save);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_gmt)
|
|
Packit |
575503 |
tm = gmtime(& fclock);
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
tm = localtime(& fclock);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (tm == NULL) {
|
|
Packit |
575503 |
ret = make_string("", 0);
|
|
Packit |
575503 |
goto done;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
bufp = buf;
|
|
Packit |
575503 |
bufsize = sizeof(buf);
|
|
Packit |
575503 |
for (;;) {
|
|
Packit |
575503 |
*bufp = '\0';
|
|
Packit |
575503 |
buflen = strftime(bufp, bufsize, format, tm);
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* buflen can be zero EITHER because there's not enough
|
|
Packit |
575503 |
* room in the string, or because the control command
|
|
Packit |
575503 |
* goes to the empty string. Make a reasonable guess that
|
|
Packit |
575503 |
* if the buffer is 1024 times bigger than the length of the
|
|
Packit |
575503 |
* format string, it's not failing for lack of room.
|
|
Packit |
575503 |
* Thanks to Paul Eggert for pointing out this issue.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (buflen > 0 || bufsize >= 1024 * formatlen)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
bufsize *= 2;
|
|
Packit |
575503 |
if (bufp == buf)
|
|
Packit |
575503 |
emalloc(bufp, char *, bufsize, "do_strftime");
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
erealloc(bufp, char *, bufsize, "do_strftime");
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
ret = make_string(bufp, buflen);
|
|
Packit |
575503 |
if (bufp != buf)
|
|
Packit |
575503 |
efree(bufp);
|
|
Packit |
575503 |
done:
|
|
Packit |
575503 |
if (t1) {
|
|
Packit |
575503 |
str_restore(t1, save);
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
return ret;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_systime --- get the time of day */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_systime(int nargs ATTRIBUTE_UNUSED)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
time_t lclock;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
(void) time(& lclock);
|
|
Packit |
575503 |
return make_number((AWKNUM) lclock);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* mktime_tz --- based on Linux timegm man page */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static time_t
|
|
Packit |
575503 |
mktime_tz(struct tm *tm, const char *tzreq)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
time_t ret;
|
|
Packit |
575503 |
char *tz = getenv("TZ");
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (tz)
|
|
Packit |
575503 |
tz = estrdup(tz, strlen(tz));
|
|
Packit |
575503 |
if (setenv("TZ", tzreq, 1) < 0) {
|
|
Packit |
575503 |
warning(_("setenv(TZ, %s) failed (%s)"), tzreq, strerror(errno));
|
|
Packit |
575503 |
return -1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
tzset();
|
|
Packit |
575503 |
ret = mktime(tm);
|
|
Packit |
575503 |
if (tz) {
|
|
Packit |
575503 |
if (setenv("TZ", tz, 1) < 0)
|
|
Packit |
575503 |
fatal(_("setenv(TZ, %s) restoration failed (%s)"), tz, strerror(errno));
|
|
Packit |
575503 |
free(tz);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
if (unsetenv("TZ") < 0)
|
|
Packit |
575503 |
fatal(_("unsetenv(TZ) failed (%s)"), strerror(errno));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
tzset();
|
|
Packit |
575503 |
return ret;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_mktime --- turn a time string into a timestamp */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_mktime(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1, *t2;
|
|
Packit |
575503 |
struct tm then;
|
|
Packit |
575503 |
long year;
|
|
Packit |
575503 |
int month, day, hour, minute, second, count;
|
|
Packit |
575503 |
int dst = -1; /* default is unknown */
|
|
Packit |
575503 |
time_t then_stamp;
|
|
Packit |
575503 |
char save;
|
|
Packit |
575503 |
bool do_gmt;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 2) {
|
|
Packit |
575503 |
t2 = POP_SCALAR();
|
|
Packit |
575503 |
do_gmt = boolval(t2);
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
do_gmt = false;
|
|
Packit |
575503 |
t1 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(t1)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("mktime: received non-string argument"));
|
|
Packit |
575503 |
t1 = force_string(t1);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
save = t1->stptr[t1->stlen];
|
|
Packit |
575503 |
t1->stptr[t1->stlen] = '\0';
|
|
Packit |
575503 |
|
|
Packit |
575503 |
count = sscanf(t1->stptr, "%ld %d %d %d %d %d %d",
|
|
Packit |
575503 |
& year, & month, & day,
|
|
Packit |
575503 |
& hour, & minute, & second,
|
|
Packit |
575503 |
& dst);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ( do_lint /* Ready? Set! Go: */
|
|
Packit |
575503 |
&& ( (second < 0 || second > 60)
|
|
Packit |
575503 |
|| (minute < 0 || minute > 59)
|
|
Packit |
575503 |
|| (hour < 0 || hour > 23) /* FIXME ISO 8601 allows 24 ? */
|
|
Packit |
575503 |
|| (day < 1 || day > 31)
|
|
Packit |
575503 |
|| (month < 1 || month > 12) ))
|
|
Packit |
575503 |
lintwarn(_("mktime: at least one of the values is out of the default range"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1->stptr[t1->stlen] = save;
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (count < 6
|
|
Packit |
575503 |
|| month == INT_MIN
|
|
Packit |
575503 |
|| year < INT_MIN + 1900
|
|
Packit |
575503 |
|| year - 1900 > INT_MAX)
|
|
Packit |
575503 |
return make_number((AWKNUM) -1);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& then, '\0', sizeof(then));
|
|
Packit |
575503 |
then.tm_sec = second;
|
|
Packit |
575503 |
then.tm_min = minute;
|
|
Packit |
575503 |
then.tm_hour = hour;
|
|
Packit |
575503 |
then.tm_mday = day;
|
|
Packit |
575503 |
then.tm_mon = month - 1;
|
|
Packit |
575503 |
then.tm_year = year - 1900;
|
|
Packit |
575503 |
then.tm_isdst = dst;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
then_stamp = (do_gmt ? mktime_tz(& then, "UTC+0") : mktime(& then));
|
|
Packit |
575503 |
return make_number((AWKNUM) then_stamp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_system --- run an external command */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_system(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
AWKNUM ret = 0; /* floating point on purpose, compat Unix awk */
|
|
Packit |
575503 |
char *cmd;
|
|
Packit |
575503 |
char save;
|
|
Packit |
575503 |
int status;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_sandbox)
|
|
Packit |
575503 |
fatal(_("'system' function not allowed in sandbox mode"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
(void) flush_io(); /* so output is synchronous with gawk's */
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("system: received non-string argument"));
|
|
Packit |
575503 |
cmd = force_string(tmp)->stptr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (cmd && *cmd) {
|
|
Packit |
575503 |
/* insure arg to system is zero-terminated */
|
|
Packit |
575503 |
save = cmd[tmp->stlen];
|
|
Packit |
575503 |
cmd[tmp->stlen] = '\0';
|
|
Packit |
575503 |
|
|
Packit |
575503 |
os_restore_mode(fileno(stdin));
|
|
Packit |
575503 |
set_sigpipe_to_default();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
status = system(cmd);
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* 3/2016. What to do with ret? It's never simple.
|
|
Packit |
575503 |
* POSIX says to use the full return value. BWK awk
|
|
Packit |
575503 |
* divides the result by 256. That normally gives the
|
|
Packit |
575503 |
* exit status but gives a weird result for death-by-signal.
|
|
Packit |
575503 |
* So we compromise as follows:
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
ret = status;
|
|
Packit |
575503 |
if (status != -1) {
|
|
Packit |
575503 |
if (do_posix)
|
|
Packit |
575503 |
; /* leave it alone, full 16 bits */
|
|
Packit |
575503 |
else if (do_traditional)
|
|
Packit |
575503 |
#ifdef __MINGW32__
|
|
Packit |
575503 |
ret = (((unsigned)status) & ~0xC0000000);
|
|
Packit |
575503 |
#else
|
|
Packit |
575503 |
ret = (status / 256.0);
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
ret = sanitize_exit_status(status);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((BINMODE & BINMODE_INPUT) != 0)
|
|
Packit |
575503 |
os_setbinmode(fileno(stdin), O_BINARY);
|
|
Packit |
575503 |
ignore_sigpipe();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
cmd[tmp->stlen] = save;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) ret);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_print --- print items, separated by OFS, terminated with ORS */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
void
|
|
Packit |
575503 |
do_print(int nargs, int redirtype)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
struct redirect *rp = NULL;
|
|
Packit |
575503 |
int errflg = 0;
|
|
Packit |
575503 |
FILE *fp = NULL;
|
|
Packit |
575503 |
int i;
|
|
Packit |
575503 |
NODE *redir_exp = NULL;
|
|
Packit |
575503 |
NODE *tmp = NULL;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
assert(nargs <= max_args);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (redirtype != 0) {
|
|
Packit |
575503 |
redir_exp = PEEK(nargs);
|
|
Packit |
575503 |
if (redir_exp->type != Node_val)
|
|
Packit |
575503 |
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
|
|
Packit |
575503 |
rp = redirect(redir_exp, redirtype, & errflg, true);
|
|
Packit |
575503 |
if (rp != NULL) {
|
|
Packit |
575503 |
if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) {
|
|
Packit |
575503 |
if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
|
|
Packit |
575503 |
update_ERRNO_int(EBADF);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
(void) close_rp(rp, CLOSE_ALL);
|
|
Packit |
575503 |
fatal(_("print: attempt to write to closed write end of two-way pipe"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
fp = rp->output.fp;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
else if (errflg) {
|
|
Packit |
575503 |
update_ERRNO_int(errflg);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else if (do_debug) /* only the debugger can change the default output */
|
|
Packit |
575503 |
fp = output_fp;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
fp = stdout;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (i = 1; i <= nargs; i++) {
|
|
Packit |
575503 |
tmp = args_array[i] = POP();
|
|
Packit |
575503 |
if (tmp->type == Node_var_array) {
|
|
Packit |
575503 |
while (--i > 0)
|
|
Packit |
575503 |
DEREF(args_array[i]);
|
|
Packit |
575503 |
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(tmp));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
// Let force_string_ofmt handle checking if things
|
|
Packit |
575503 |
// are already valid.
|
|
Packit |
575503 |
args_array[i] = force_string_ofmt(tmp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (redir_exp != NULL) {
|
|
Packit |
575503 |
DEREF(redir_exp);
|
|
Packit |
575503 |
decr_sp();
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (fp == NULL) {
|
|
Packit |
575503 |
for (i = nargs; i > 0; i--)
|
|
Packit |
575503 |
DEREF(args_array[i]);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (i = nargs; i > 0; i--) {
|
|
Packit |
575503 |
efwrite(args_array[i]->stptr, sizeof(char), args_array[i]->stlen, fp, "print", rp, false);
|
|
Packit |
575503 |
DEREF(args_array[i]);
|
|
Packit |
575503 |
if (i != 1 && OFSlen > 0)
|
|
Packit |
575503 |
efwrite(OFS, sizeof(char), (size_t) OFSlen,
|
|
Packit |
575503 |
fp, "print", rp, false);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (ORSlen > 0)
|
|
Packit |
575503 |
efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, true);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (rp != NULL && (rp->flag & RED_TWOWAY) != 0)
|
|
Packit |
575503 |
rp->output.gawk_fflush(rp->output.fp, rp->output.opaque);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_print_rec --- special case printing of $0, for speed */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
void
|
|
Packit |
575503 |
do_print_rec(int nargs, int redirtype)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
FILE *fp = NULL;
|
|
Packit |
575503 |
NODE *f0;
|
|
Packit |
575503 |
struct redirect *rp = NULL;
|
|
Packit |
575503 |
int errflg = 0;
|
|
Packit |
575503 |
NODE *redir_exp = NULL;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
assert(nargs == 0);
|
|
Packit |
575503 |
if (redirtype != 0) {
|
|
Packit |
575503 |
redir_exp = TOP();
|
|
Packit |
575503 |
rp = redirect(redir_exp, redirtype, & errflg, true);
|
|
Packit |
575503 |
if (rp != NULL) {
|
|
Packit |
575503 |
if ((rp->flag & RED_TWOWAY) != 0 && rp->output.fp == NULL) {
|
|
Packit |
575503 |
if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
|
|
Packit |
575503 |
update_ERRNO_int(EBADF);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
(void) close_rp(rp, CLOSE_ALL);
|
|
Packit |
575503 |
fatal(_("print: attempt to write to closed write end of two-way pipe"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
fp = rp->output.fp;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
DEREF(redir_exp);
|
|
Packit |
575503 |
decr_sp();
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
fp = output_fp;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (errflg) {
|
|
Packit |
575503 |
update_ERRNO_int(errflg);
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (fp == NULL)
|
|
Packit |
575503 |
return;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (! field0_valid)
|
|
Packit |
575503 |
(void) get_field(0L, NULL); /* rebuild record */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
f0 = fields_arr[0];
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint && (f0->flags & NULL_FIELD) != 0)
|
|
Packit |
575503 |
lintwarn(_("reference to uninitialized field `$%d'"), 0);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
efwrite(f0->stptr, sizeof(char), f0->stlen, fp, "print", rp, false);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (ORSlen > 0)
|
|
Packit |
575503 |
efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, true);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (rp != NULL && (rp->flag & RED_TWOWAY) != 0)
|
|
Packit |
575503 |
rp->output.gawk_fflush(rp->output.fp, rp->output.opaque);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* is_wupper --- function version of iswupper for passing function pointers */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static int
|
|
Packit |
575503 |
is_wupper(wchar_t c)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
return iswupper(c);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* is_wlower --- function version of iswlower for passing function pointers */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static int
|
|
Packit |
575503 |
is_wlower(wchar_t c)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
return iswlower(c);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* to_wupper --- function version of towupper for passing function pointers */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static int
|
|
Packit |
575503 |
to_wlower(wchar_t c)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
return towlower(c);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* to_wlower --- function version of towlower for passing function pointers */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static int
|
|
Packit |
575503 |
to_wupper(wchar_t c)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
return towupper(c);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* wide_change_case --- generic case converter for wide characters */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static void
|
|
Packit |
575503 |
wide_change_case(wchar_t *wstr,
|
|
Packit |
575503 |
size_t wlen,
|
|
Packit |
575503 |
int (*is_x)(wchar_t c),
|
|
Packit |
575503 |
int (*to_y)(wchar_t c))
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
size_t i;
|
|
Packit |
575503 |
wchar_t *wcp;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (i = 0, wcp = wstr; i < wlen; i++, wcp++)
|
|
Packit |
575503 |
if (is_x(*wcp))
|
|
Packit |
575503 |
*wcp = to_y(*wcp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* wide_toupper --- map a wide string to upper case */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static void
|
|
Packit |
575503 |
wide_toupper(wchar_t *wstr, size_t wlen)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
wide_change_case(wstr, wlen, is_wlower, to_wupper);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* wide_tolower --- map a wide string to lower case */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static void
|
|
Packit |
575503 |
wide_tolower(wchar_t *wstr, size_t wlen)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
wide_change_case(wstr, wlen, is_wupper, to_wlower);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_tolower --- lower case a string */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_tolower(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1, *t2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(t1)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("tolower: received non-string argument"));
|
|
Packit |
575503 |
t1 = force_string(t1);
|
|
Packit |
575503 |
t2 = make_string(t1->stptr, t1->stlen);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (gawk_mb_cur_max == 1) {
|
|
Packit |
575503 |
unsigned char *cp, *cp2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (cp = (unsigned char *)t2->stptr,
|
|
Packit |
575503 |
cp2 = (unsigned char *)(t2->stptr + t2->stlen);
|
|
Packit |
575503 |
cp < cp2; cp++)
|
|
Packit |
575503 |
if (isupper(*cp))
|
|
Packit |
575503 |
*cp = tolower(*cp);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
force_wstring(t2);
|
|
Packit |
575503 |
wide_tolower(t2->wstptr, t2->wstlen);
|
|
Packit |
575503 |
wstr2str(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return t2;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_toupper --- upper case a string */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_toupper(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1, *t2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(t1)->flags & STRING) == 0)
|
|
Packit |
575503 |
lintwarn(_("toupper: received non-string argument"));
|
|
Packit |
575503 |
t1 = force_string(t1);
|
|
Packit |
575503 |
t2 = make_string(t1->stptr, t1->stlen);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (gawk_mb_cur_max == 1) {
|
|
Packit |
575503 |
unsigned char *cp, *cp2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (cp = (unsigned char *)t2->stptr,
|
|
Packit |
575503 |
cp2 = (unsigned char *)(t2->stptr + t2->stlen);
|
|
Packit |
575503 |
cp < cp2; cp++)
|
|
Packit |
575503 |
if (islower(*cp))
|
|
Packit |
575503 |
*cp = toupper(*cp);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
force_wstring(t2);
|
|
Packit |
575503 |
wide_toupper(t2->wstptr, t2->wstlen);
|
|
Packit |
575503 |
wstr2str(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return t2;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_atan2 --- do the atan2 function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_atan2(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1, *t2;
|
|
Packit |
575503 |
double d1, d2;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
POP_TWO_SCALARS(t1, t2);
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if ((fixtype(t1)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("atan2: received non-numeric first argument"));
|
|
Packit |
575503 |
if ((fixtype(t2)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("atan2: received non-numeric second argument"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
d1 = force_number(t1)->numbr;
|
|
Packit |
575503 |
d2 = force_number(t2)->numbr;
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
return make_number((AWKNUM) atan2(d1, d2));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_sin --- do the sin function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_sin(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double d;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("sin: received non-numeric argument"));
|
|
Packit |
575503 |
d = sin((double) force_number(tmp)->numbr);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) d);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_cos --- do the cos function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_cos(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double d;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("cos: received non-numeric argument"));
|
|
Packit |
575503 |
d = cos((double) force_number(tmp)->numbr);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) d);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_rand --- do the rand function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static bool firstrand = true;
|
|
Packit |
575503 |
/* Some systems require this array to be integer aligned. Sigh. */
|
|
Packit |
575503 |
#define SIZEOF_STATE 256
|
|
Packit |
575503 |
static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
|
|
Packit |
575503 |
static char *const state = (char *const) istate;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* ARGSUSED */
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_rand(int nargs ATTRIBUTE_UNUSED)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
double tmprand;
|
|
Packit |
575503 |
#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0)
|
|
Packit |
575503 |
if (firstrand) {
|
|
Packit |
575503 |
(void) initstate((unsigned) 1, state, SIZEOF_STATE);
|
|
Packit |
575503 |
/* don't need to srandom(1), initstate() does it for us. */
|
|
Packit |
575503 |
firstrand = false;
|
|
Packit |
575503 |
setstate(state);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Per historical practice and POSIX, return value N is
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* 0 <= n < 1
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Date: Wed, 28 Aug 2013 17:52:46 -0700
|
|
Packit |
575503 |
* From: Bob Jewett <jewett@bill.scs.agilent.com>
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* Call random() twice to fill in more bits in the value
|
|
Packit |
575503 |
* of the double. Also, there is a bug in random() such
|
|
Packit |
575503 |
* that when the values of successive values are combined
|
|
Packit |
575503 |
* like (rand1*rand2)^2, (rand3*rand4)^2, ... the
|
|
Packit |
575503 |
* resulting time series is not white noise. The
|
|
Packit |
575503 |
* following also seems to fix that bug.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* The add/subtract 0.5 keeps small bits from filling
|
|
Packit |
575503 |
* below 2^-53 in the double, not that anyone should be
|
|
Packit |
575503 |
* looking down there.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* Date: Wed, 25 Sep 2013 10:45:38 -0600 (MDT)
|
|
Packit |
575503 |
* From: "Nelson H. F. Beebe" <beebe@math.utah.edu>
|
|
Packit |
575503 |
* (4) The code is typical of many published fragments for converting
|
|
Packit |
575503 |
* from integer to floating-point, and I discuss the serious pitfalls
|
|
Packit |
575503 |
* in my book, because it leads to platform-dependent behavior at the
|
|
Packit |
575503 |
* end points of the interval [0,1]
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* (5) the documentation in the gawk info node says
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* `rand()'
|
|
Packit |
575503 |
* Return a random number. The values of `rand()' are uniformly
|
|
Packit |
575503 |
* distributed between zero and one. The value could be zero but is
|
|
Packit |
575503 |
* never one.(1)
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* The division by RAND_DIVISOR may not guarantee that 1.0 is never
|
|
Packit |
575503 |
* returned: the programmer forgot the platform-dependent issue of
|
|
Packit |
575503 |
* rounding.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* For points 4 and 5, the safe way is a loop:
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* double
|
|
Packit |
575503 |
* rand(void) // return value in [0.0, 1.0)
|
|
Packit |
575503 |
* {
|
|
Packit |
575503 |
* value = internal_rand();
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* while (value == 1.0)
|
|
Packit |
575503 |
* value = internal_rand();
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* return (value);
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
do {
|
|
Packit |
575503 |
long d1, d2;
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Do the calls in predictable order to avoid
|
|
Packit |
575503 |
* compiler differences in order of evaluation.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
d1 = random();
|
|
Packit |
575503 |
d2 = random();
|
|
Packit |
575503 |
tmprand = 0.5 + ( (d1/RAND_DIVISOR + d2) / RAND_DIVISOR );
|
|
Packit |
575503 |
tmprand -= 0.5;
|
|
Packit |
575503 |
} while (tmprand == 1.0);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_number((AWKNUM) tmprand);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_srand --- seed the random number generator */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_srand(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
static long save_seed = 1;
|
|
Packit |
575503 |
long ret = save_seed; /* SVR4 awk srand returns previous seed */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (firstrand) {
|
|
Packit |
575503 |
(void) initstate((unsigned) 1, state, SIZEOF_STATE);
|
|
Packit |
575503 |
/* don't need to srandom(1), we're changing the seed below */
|
|
Packit |
575503 |
firstrand = false;
|
|
Packit |
575503 |
(void) setstate(state);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 0)
|
|
Packit |
575503 |
srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("srand: received non-numeric argument"));
|
|
Packit |
575503 |
srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr));
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
return make_number((AWKNUM) ret);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_match --- match a regexp, set RSTART and RLENGTH,
|
|
Packit |
575503 |
* optional third arg is array filled with text of
|
|
Packit |
575503 |
* subpatterns enclosed in parens and start and len info.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_match(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tre, *t1, *dest, *it;
|
|
Packit |
575503 |
int rstart, len, ii;
|
|
Packit |
575503 |
int rlength;
|
|
Packit |
575503 |
Regexp *rp;
|
|
Packit |
575503 |
regoff_t s;
|
|
Packit |
575503 |
char *start;
|
|
Packit |
575503 |
char *buf = NULL;
|
|
Packit |
575503 |
char buff[100];
|
|
Packit |
575503 |
size_t amt, oldamt = 0, ilen, slen;
|
|
Packit |
575503 |
char *subsepstr;
|
|
Packit |
575503 |
size_t subseplen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
dest = NULL;
|
|
Packit |
575503 |
if (nargs == 3) { /* 3rd optional arg for the subpatterns */
|
|
Packit |
575503 |
dest = POP_PARAM();
|
|
Packit |
575503 |
if (dest->type != Node_var_array)
|
|
Packit |
575503 |
fatal(_("match: third argument is not an array"));
|
|
Packit |
575503 |
assoc_clear(dest);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
tre = POP();
|
|
Packit |
575503 |
rp = re_update(tre);
|
|
Packit |
575503 |
t1 = POP_STRING();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
rstart = research(rp, t1->stptr, 0, t1->stlen, RE_NEED_START);
|
|
Packit |
575503 |
if (rstart >= 0) { /* match succeded */
|
|
Packit |
575503 |
size_t *wc_indices = NULL;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr); /* byte length */
|
|
Packit |
575503 |
if (rlength > 0 && gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
t1 = str2wstr(t1, & wc_indices);
|
|
Packit |
575503 |
rlength = wc_indices[rstart + rlength - 1] - wc_indices[rstart] + 1;
|
|
Packit |
575503 |
rstart = wc_indices[rstart];
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
rstart++; /* now it's 1-based indexing */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* Build the array only if the caller wants the optional subpatterns */
|
|
Packit |
575503 |
if (dest != NULL) {
|
|
Packit |
575503 |
subsepstr = SUBSEP_node->var_value->stptr;
|
|
Packit |
575503 |
subseplen = SUBSEP_node->var_value->stlen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (ii = 0; ii < NUMSUBPATS(rp, t1->stptr); ii++) {
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Loop over all the subpats; some of them may have
|
|
Packit |
575503 |
* matched even if all of them did not.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if ((s = SUBPATSTART(rp, t1->stptr, ii)) != -1) {
|
|
Packit |
575503 |
size_t subpat_start;
|
|
Packit |
575503 |
size_t subpat_len;
|
|
Packit |
575503 |
NODE **lhs;
|
|
Packit |
575503 |
NODE *sub;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
start = t1->stptr + s;
|
|
Packit |
575503 |
subpat_start = s;
|
|
Packit |
575503 |
subpat_len = len = SUBPATEND(rp, t1->stptr, ii) - s;
|
|
Packit |
575503 |
if (len > 0 && gawk_mb_cur_max > 1) {
|
|
Packit |
575503 |
subpat_start = wc_indices[s];
|
|
Packit |
575503 |
subpat_len = wc_indices[s + len - 1] - subpat_start + 1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
it = make_string(start, len);
|
|
Packit |
575503 |
it->flags |= USER_INPUT;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
sub = make_number((AWKNUM) (ii));
|
|
Packit |
575503 |
lhs = assoc_lookup(dest, sub);
|
|
Packit |
575503 |
unref(*lhs);
|
|
Packit |
575503 |
*lhs = it;
|
|
Packit |
575503 |
/* execute post-assignment routine if any */
|
|
Packit |
575503 |
if (dest->astore != NULL)
|
|
Packit |
575503 |
(*dest->astore)(dest, sub);
|
|
Packit |
575503 |
unref(sub);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
sprintf(buff, "%d", ii);
|
|
Packit |
575503 |
ilen = strlen(buff);
|
|
Packit |
575503 |
amt = ilen + subseplen + strlen("length") + 1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (oldamt == 0) {
|
|
Packit |
575503 |
emalloc(buf, char *, amt, "do_match");
|
|
Packit |
575503 |
} else if (amt > oldamt) {
|
|
Packit |
575503 |
erealloc(buf, char *, amt, "do_match");
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
oldamt = amt;
|
|
Packit |
575503 |
memcpy(buf, buff, ilen);
|
|
Packit |
575503 |
memcpy(buf + ilen, subsepstr, subseplen);
|
|
Packit |
575503 |
memcpy(buf + ilen + subseplen, "start", 6);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
slen = ilen + subseplen + 5;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
it = make_number((AWKNUM) subpat_start + 1);
|
|
Packit |
575503 |
sub = make_string(buf, slen);
|
|
Packit |
575503 |
lhs = assoc_lookup(dest, sub);
|
|
Packit |
575503 |
unref(*lhs);
|
|
Packit |
575503 |
*lhs = it;
|
|
Packit |
575503 |
if (dest->astore != NULL)
|
|
Packit |
575503 |
(*dest->astore)(dest, sub);
|
|
Packit |
575503 |
unref(sub);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memcpy(buf, buff, ilen);
|
|
Packit |
575503 |
memcpy(buf + ilen, subsepstr, subseplen);
|
|
Packit |
575503 |
memcpy(buf + ilen + subseplen, "length", 7);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
slen = ilen + subseplen + 6;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
it = make_number((AWKNUM) subpat_len);
|
|
Packit |
575503 |
sub = make_string(buf, slen);
|
|
Packit |
575503 |
lhs = assoc_lookup(dest, sub);
|
|
Packit |
575503 |
unref(*lhs);
|
|
Packit |
575503 |
*lhs = it;
|
|
Packit |
575503 |
if (dest->astore != NULL)
|
|
Packit |
575503 |
(*dest->astore)(dest, sub);
|
|
Packit |
575503 |
unref(sub);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
efree(buf);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (wc_indices != NULL)
|
|
Packit |
575503 |
efree(wc_indices);
|
|
Packit |
575503 |
} else { /* match failed */
|
|
Packit |
575503 |
rstart = 0;
|
|
Packit |
575503 |
rlength = -1;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
unref(RSTART_node->var_value);
|
|
Packit |
575503 |
RSTART_node->var_value = make_number((AWKNUM) rstart);
|
|
Packit |
575503 |
unref(RLENGTH_node->var_value);
|
|
Packit |
575503 |
RLENGTH_node->var_value = make_number((AWKNUM) rlength);
|
|
Packit |
575503 |
return make_number((AWKNUM) rstart);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_sub --- do the work for sub, gsub, and gensub */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Gsub can be tricksy; particularly when handling the case of null strings.
|
|
Packit |
575503 |
* The following awk code was useful in debugging problems. It is too bad
|
|
Packit |
575503 |
* that it does not readily translate directly into the C code, below.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* #! /usr/local/bin/mawk -f
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* BEGIN {
|
|
Packit |
575503 |
* true = 1; false = 0
|
|
Packit |
575503 |
* print "--->", mygsub("abc", "b+", "FOO")
|
|
Packit |
575503 |
* print "--->", mygsub("abc", "x*", "X")
|
|
Packit |
575503 |
* print "--->", mygsub("abc", "b*", "X")
|
|
Packit |
575503 |
* print "--->", mygsub("abc", "c", "X")
|
|
Packit |
575503 |
* print "--->", mygsub("abc", "c+", "X")
|
|
Packit |
575503 |
* print "--->", mygsub("abc", "x*$", "X")
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* function mygsub(str, regex, replace, origstr, newstr, eosflag, nonzeroflag)
|
|
Packit |
575503 |
* {
|
|
Packit |
575503 |
* origstr = str;
|
|
Packit |
575503 |
* eosflag = nonzeroflag = false
|
|
Packit |
575503 |
* while (match(str, regex)) {
|
|
Packit |
575503 |
* if (RLENGTH > 0) { # easy case
|
|
Packit |
575503 |
* nonzeroflag = true
|
|
Packit |
575503 |
* if (RSTART == 1) { # match at front of string
|
|
Packit |
575503 |
* newstr = newstr replace
|
|
Packit |
575503 |
* } else {
|
|
Packit |
575503 |
* newstr = newstr substr(str, 1, RSTART-1) replace
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
* str = substr(str, RSTART+RLENGTH)
|
|
Packit |
575503 |
* } else if (nonzeroflag) {
|
|
Packit |
575503 |
* # last match was non-zero in length, and at the
|
|
Packit |
575503 |
* # current character, we get a zero length match,
|
|
Packit |
575503 |
* # which we don't really want, so skip over it
|
|
Packit |
575503 |
* newstr = newstr substr(str, 1, 1)
|
|
Packit |
575503 |
* str = substr(str, 2)
|
|
Packit |
575503 |
* nonzeroflag = false
|
|
Packit |
575503 |
* } else {
|
|
Packit |
575503 |
* # 0-length match
|
|
Packit |
575503 |
* if (RSTART == 1) {
|
|
Packit |
575503 |
* newstr = newstr replace substr(str, 1, 1)
|
|
Packit |
575503 |
* str = substr(str, 2)
|
|
Packit |
575503 |
* } else {
|
|
Packit |
575503 |
* return newstr str replace
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
* if (length(str) == 0)
|
|
Packit |
575503 |
* if (eosflag)
|
|
Packit |
575503 |
* break
|
|
Packit |
575503 |
* else
|
|
Packit |
575503 |
* eosflag = true
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
* if (length(str) > 0)
|
|
Packit |
575503 |
* newstr = newstr str # rest of string
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* return newstr
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* 1/2004: The gawk sub/gsub behavior dates from 1996, when we proposed it
|
|
Packit |
575503 |
* for POSIX. The proposal fell through the cracks, and the 2001 POSIX
|
|
Packit |
575503 |
* standard chose a more simple behavior.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* The relevant text is to be found on lines 6394-6407 (pages 166, 167) of the
|
|
Packit |
575503 |
* 2001 standard:
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* sub(ere, repl[, in ])
|
|
Packit |
575503 |
* Substitute the string repl in place of the first instance of the
|
|
Packit |
575503 |
* extended regular expression ERE in string in and return the number of
|
|
Packit |
575503 |
* substitutions. An ampersand ('&') appearing in the string repl shall
|
|
Packit |
575503 |
* be replaced by the string from in that matches the ERE. An ampersand
|
|
Packit |
575503 |
* preceded with a backslash ('\') shall be interpreted as the literal
|
|
Packit |
575503 |
* ampersand character. An occurrence of two consecutive backslashes shall
|
|
Packit |
575503 |
* be interpreted as just a single literal backslash character. Any other
|
|
Packit |
575503 |
* occurrence of a backslash (for example, preceding any other character)
|
|
Packit |
575503 |
* shall be treated as a literal backslash character. Note that if repl is a
|
|
Packit |
575503 |
* string literal (the lexical token STRING; see Grammar (on page 170)), the
|
|
Packit |
575503 |
* handling of the ampersand character occurs after any lexical processing,
|
|
Packit |
575503 |
* including any lexical backslash escape sequence processing. If in is
|
|
Packit |
575503 |
* specified and it is not an lvalue (see Expressions in awk (on page 156)),
|
|
Packit |
575503 |
* the behavior is undefined. If in is omitted, awk shall use the current
|
|
Packit |
575503 |
* record ($0) in its place.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* 11/2010: The text in the 2008 standard is the same as just quoted.
|
|
Packit |
575503 |
* However, POSIX behavior is now the default. This can change the behavior
|
|
Packit |
575503 |
* of awk programs. The old behavior is not available.
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* 7/2011: Reverted backslash handling to what it used to be. It was in
|
|
Packit |
575503 |
* gawk for too long. Should have known better.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* NB: `howmany' conflicts with a SunOS 4.x macro in <sys/param.h>.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_sub(int nargs, unsigned int flags)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
char *scan;
|
|
Packit |
575503 |
char *bp, *cp;
|
|
Packit |
575503 |
char *buf = NULL;
|
|
Packit |
575503 |
size_t buflen;
|
|
Packit |
575503 |
char *matchend;
|
|
Packit |
575503 |
size_t len;
|
|
Packit |
575503 |
char *matchstart;
|
|
Packit |
575503 |
char *text;
|
|
Packit |
575503 |
size_t textlen = 0;
|
|
Packit |
575503 |
char *repl;
|
|
Packit |
575503 |
char *replend;
|
|
Packit |
575503 |
size_t repllen;
|
|
Packit |
575503 |
int sofar;
|
|
Packit |
575503 |
int ampersands;
|
|
Packit |
575503 |
int matches = 0;
|
|
Packit |
575503 |
Regexp *rp;
|
|
Packit |
575503 |
NODE *rep_node; /* replacement text */
|
|
Packit |
575503 |
NODE *target; /* string to make sub. in; $0 if none given */
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
NODE **lhs = NULL;
|
|
Packit |
575503 |
long how_many = 1; /* one substitution for sub, also gensub default */
|
|
Packit |
575503 |
bool global;
|
|
Packit |
575503 |
long current;
|
|
Packit |
575503 |
bool lastmatchnonzero;
|
|
Packit |
575503 |
char *mb_indices = NULL;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((flags & GENSUB) != 0) {
|
|
Packit |
575503 |
double d;
|
|
Packit |
575503 |
NODE *glob_flag;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = PEEK(3);
|
|
Packit |
575503 |
rp = re_update(tmp);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
target = POP_STRING(); /* original string */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
glob_flag = POP_SCALAR(); /* value of global flag */
|
|
Packit |
575503 |
if ( (glob_flag->flags & STRING) != 0
|
|
Packit |
575503 |
&& glob_flag->stlen > 0
|
|
Packit |
575503 |
&& (glob_flag->stptr[0] == 'g' || glob_flag->stptr[0] == 'G'))
|
|
Packit |
575503 |
how_many = -1;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
(void) force_number(glob_flag);
|
|
Packit |
575503 |
d = get_number_d(glob_flag);
|
|
Packit |
575503 |
if (d < 1)
|
|
Packit |
575503 |
how_many = 1;
|
|
Packit |
575503 |
else if (d < LONG_MAX)
|
|
Packit |
575503 |
how_many = d;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
how_many = LONG_MAX;
|
|
Packit |
575503 |
if (d <= 0) {
|
|
Packit |
575503 |
(void) force_string(glob_flag);
|
|
Packit |
575503 |
warning(_("gensub: third argument `%.*s' treated as 1"),
|
|
Packit |
575503 |
(int) glob_flag->stlen,
|
|
Packit |
575503 |
glob_flag->stptr);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
DEREF(glob_flag);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/* take care of regexp early, in case re_update is fatal */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = PEEK(2);
|
|
Packit |
575503 |
rp = re_update(tmp);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((flags & GSUB) != 0)
|
|
Packit |
575503 |
how_many = -1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* original string */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((flags & LITERAL) != 0)
|
|
Packit |
575503 |
target = POP_STRING();
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
lhs = POP_ADDRESS();
|
|
Packit |
575503 |
target = force_string(*lhs);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
global = (how_many == -1);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
rep_node = POP_STRING(); /* replacement text */
|
|
Packit |
575503 |
decr_sp(); /* regexp, already updated above */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do the search early to avoid work on non-match */
|
|
Packit |
575503 |
if (research(rp, target->stptr, 0, target->stlen, RE_NEED_START) == -1 ||
|
|
Packit |
575503 |
RESTART(rp, target->stptr) > target->stlen)
|
|
Packit |
575503 |
goto done;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
target->flags |= STRING;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
text = target->stptr;
|
|
Packit |
575503 |
textlen = target->stlen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
repl = rep_node->stptr;
|
|
Packit |
575503 |
replend = repl + rep_node->stlen;
|
|
Packit |
575503 |
repllen = replend - repl;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
ampersands = 0;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Some systems' malloc() can't handle being called with an
|
|
Packit |
575503 |
* argument of zero. Thus we have to have some special case
|
|
Packit |
575503 |
* code to check for `repllen == 0'. This can occur for
|
|
Packit |
575503 |
* something like:
|
|
Packit |
575503 |
* sub(/foo/, "", mystring)
|
|
Packit |
575503 |
* for example.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (gawk_mb_cur_max > 1 && repllen > 0) {
|
|
Packit |
575503 |
emalloc(mb_indices, char *, repllen * sizeof(char), "do_sub");
|
|
Packit |
575503 |
index_multibyte_buffer(repl, mb_indices, repllen);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* compute length of replacement string, number of ampersands */
|
|
Packit |
575503 |
for (scan = repl; scan < replend; scan++) {
|
|
Packit |
575503 |
if ((gawk_mb_cur_max == 1 || (repllen > 0 && mb_indices[scan - repl] == 1))
|
|
Packit |
575503 |
&& (*scan == '&')) {
|
|
Packit |
575503 |
repllen--;
|
|
Packit |
575503 |
ampersands++;
|
|
Packit |
575503 |
} else if (*scan == '\\') {
|
|
Packit |
575503 |
if ((flags & GENSUB) != 0) { /* gensub, behave sanely */
|
|
Packit |
575503 |
if (isdigit((unsigned char) scan[1])) {
|
|
Packit |
575503 |
ampersands++;
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
} else { /* \q for any q --> q */
|
|
Packit |
575503 |
repllen--;
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else if (do_posix) {
|
|
Packit |
575503 |
/* \& --> &, \\ --> \ */
|
|
Packit |
575503 |
if (scan[1] == '&' || scan[1] == '\\') {
|
|
Packit |
575503 |
repllen--;
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
} /* else
|
|
Packit |
575503 |
leave alone, it goes into the output */
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/* gawk default behavior since 1996 */
|
|
Packit |
575503 |
if (strncmp(scan, "\\\\\\&", 4) == 0
|
|
Packit |
575503 |
|| strncmp(scan, "\\\\\\\\", 4) == 0) { /* 2016: fixed */
|
|
Packit |
575503 |
/* \\\& --> \& */
|
|
Packit |
575503 |
/* \\\\ --> \\ */
|
|
Packit |
575503 |
repllen -= 2;
|
|
Packit |
575503 |
scan += 3;
|
|
Packit |
575503 |
} else if (strncmp(scan, "\\\\&", 3) == 0) {
|
|
Packit |
575503 |
/* \\& --> \<string> */
|
|
Packit |
575503 |
ampersands++;
|
|
Packit |
575503 |
repllen--;
|
|
Packit |
575503 |
scan += 2;
|
|
Packit |
575503 |
} else if (scan[1] == '&') {
|
|
Packit |
575503 |
/* \& --> & */
|
|
Packit |
575503 |
repllen--;
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
} /* else
|
|
Packit |
575503 |
leave alone, it goes into the output */
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
lastmatchnonzero = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* guesstimate how much room to allocate; +1 forces > 0 */
|
|
Packit |
575503 |
buflen = textlen + (ampersands + 1) * repllen + 1;
|
|
Packit |
575503 |
emalloc(buf, char *, buflen + 1, "do_sub");
|
|
Packit |
575503 |
buf[buflen] = '\0';
|
|
Packit |
575503 |
|
|
Packit |
575503 |
bp = buf;
|
|
Packit |
575503 |
for (current = 1;; current++) {
|
|
Packit |
575503 |
matches++;
|
|
Packit |
575503 |
matchstart = target->stptr + RESTART(rp, target->stptr);
|
|
Packit |
575503 |
matchend = target->stptr + REEND(rp, target->stptr);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* create the result, copying in parts of the original
|
|
Packit |
575503 |
* string. note that length of replacement string can
|
|
Packit |
575503 |
* vary since ampersand is actual text of regexp match.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* add 1 to len to handle "empty" case where
|
|
Packit |
575503 |
* matchend == matchstart and we force a match on a single
|
|
Packit |
575503 |
* char. Use 'matchend - text' instead of 'matchstart - text'
|
|
Packit |
575503 |
* because we may not actually make any substitution depending
|
|
Packit |
575503 |
* on the 'global' and 'how_many' values.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
len = matchend - text + repllen
|
|
Packit |
575503 |
+ ampersands * (matchend - matchstart) + 1;
|
|
Packit |
575503 |
sofar = bp - buf;
|
|
Packit |
575503 |
while (buflen < (sofar + len + 1)) {
|
|
Packit |
575503 |
buflen *= 2;
|
|
Packit |
575503 |
erealloc(buf, char *, buflen, "sub_common");
|
|
Packit |
575503 |
bp = buf + sofar;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
for (scan = text; scan < matchstart; scan++)
|
|
Packit |
575503 |
*bp++ = *scan;
|
|
Packit |
575503 |
if (global || current == how_many) {
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* If the current match matched the null string,
|
|
Packit |
575503 |
* and the last match didn't and did a replacement,
|
|
Packit |
575503 |
* and the match of the null string is at the front of
|
|
Packit |
575503 |
* the text (meaning right after end of the previous
|
|
Packit |
575503 |
* replacement), then skip this one.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (matchstart == matchend
|
|
Packit |
575503 |
&& lastmatchnonzero
|
|
Packit |
575503 |
&& matchstart == text) {
|
|
Packit |
575503 |
lastmatchnonzero = false;
|
|
Packit |
575503 |
matches--;
|
|
Packit |
575503 |
goto empty;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* If replacing all occurrences, or this is the
|
|
Packit |
575503 |
* match we want, copy in the replacement text,
|
|
Packit |
575503 |
* making substitutions as we go.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
for (scan = repl; scan < replend; scan++)
|
|
Packit |
575503 |
if (*scan == '&'
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Don't test repllen here. A simple "&" could
|
|
Packit |
575503 |
* end up with repllen == 0.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
&& (gawk_mb_cur_max == 1
|
|
Packit |
575503 |
|| mb_indices[scan - repl] == 1)
|
|
Packit |
575503 |
) {
|
|
Packit |
575503 |
for (cp = matchstart; cp < matchend; cp++)
|
|
Packit |
575503 |
*bp++ = *cp;
|
|
Packit |
575503 |
} else if (*scan == '\\'
|
|
Packit |
575503 |
&& (gawk_mb_cur_max == 1
|
|
Packit |
575503 |
|| (repllen > 0 && mb_indices[scan - repl] == 1))
|
|
Packit |
575503 |
) {
|
|
Packit |
575503 |
if (flags & GENSUB) { /* gensub, behave sanely */
|
|
Packit |
575503 |
if (isdigit((unsigned char) scan[1])) {
|
|
Packit |
575503 |
int dig = scan[1] - '0';
|
|
Packit |
575503 |
if (dig < NUMSUBPATS(rp, target->stptr) && SUBPATSTART(rp, tp->stptr, dig) != -1) {
|
|
Packit |
575503 |
char *start, *end;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
start = target->stptr
|
|
Packit |
575503 |
+ SUBPATSTART(rp, target->stptr, dig);
|
|
Packit |
575503 |
end = target->stptr
|
|
Packit |
575503 |
+ SUBPATEND(rp, target->stptr, dig);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (cp = start; cp < end; cp++)
|
|
Packit |
575503 |
*bp++ = *cp;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
} else /* \q for any q --> q */
|
|
Packit |
575503 |
*bp++ = *++scan;
|
|
Packit |
575503 |
} else if (do_posix) {
|
|
Packit |
575503 |
/* \& --> &, \\ --> \ */
|
|
Packit |
575503 |
if (scan[1] == '&' || scan[1] == '\\')
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
*bp++ = *scan;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/* gawk default behavior since 1996 */
|
|
Packit |
575503 |
if (strncmp(scan, "\\\\\\&", 4) == 0
|
|
Packit |
575503 |
|| strncmp(scan, "\\\\\\\\", 4) == 0) { /* 2016: fixed */
|
|
Packit |
575503 |
/* \\\& --> \& */
|
|
Packit |
575503 |
/* \\\\ --> \\ */
|
|
Packit |
575503 |
*bp++ = '\\';
|
|
Packit |
575503 |
*bp++ = scan[3];
|
|
Packit |
575503 |
scan += 3;
|
|
Packit |
575503 |
} else if (strncmp(scan, "\\\\&", 3) == 0) {
|
|
Packit |
575503 |
/* \\& --> \<string> */
|
|
Packit |
575503 |
*bp++ = '\\';
|
|
Packit |
575503 |
for (cp = matchstart; cp < matchend; cp++)
|
|
Packit |
575503 |
*bp++ = *cp;
|
|
Packit |
575503 |
scan += 2;
|
|
Packit |
575503 |
} else if (scan[1] == '&') {
|
|
Packit |
575503 |
/* \& --> & */
|
|
Packit |
575503 |
*bp++ = '&';
|
|
Packit |
575503 |
scan++;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
*bp++ = *scan;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
*bp++ = *scan;
|
|
Packit |
575503 |
if (matchstart != matchend)
|
|
Packit |
575503 |
lastmatchnonzero = true;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* don't want this match, skip over it by copying
|
|
Packit |
575503 |
* in current text.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
for (cp = matchstart; cp < matchend; cp++)
|
|
Packit |
575503 |
*bp++ = *cp;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
empty:
|
|
Packit |
575503 |
/* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */
|
|
Packit |
575503 |
if (matchstart == matchend && matchend < text + textlen) {
|
|
Packit |
575503 |
*bp++ = *matchend;
|
|
Packit |
575503 |
matchend++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
textlen = text + textlen - matchend;
|
|
Packit |
575503 |
text = matchend;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if 0
|
|
Packit |
575503 |
if (bp - buf > sofar + len)
|
|
Packit |
575503 |
fprintf(stderr, "debug: len = %zu, but used %ld\n", len, (long)((bp - buf) - (long)sofar));
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((current >= how_many && ! global)
|
|
Packit |
575503 |
|| ((long) textlen <= 0 && matchstart == matchend)
|
|
Packit |
575503 |
|| research(rp, target->stptr, text - target->stptr, textlen, RE_NEED_START) == -1)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
sofar = bp - buf;
|
|
Packit |
575503 |
if (buflen < (sofar + textlen + 1)) {
|
|
Packit |
575503 |
buflen = sofar + textlen + 1;
|
|
Packit |
575503 |
erealloc(buf, char *, buflen, "do_sub");
|
|
Packit |
575503 |
bp = buf + sofar;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Note that text == matchend, since that assignment is made before
|
|
Packit |
575503 |
* exiting the 'for' loop above. Thus we copy in the rest of the
|
|
Packit |
575503 |
* original string.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
for (scan = text; scan < text + textlen; scan++)
|
|
Packit |
575503 |
*bp++ = *scan;
|
|
Packit |
575503 |
*bp = '\0';
|
|
Packit |
575503 |
textlen = bp - buf;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (mb_indices != NULL)
|
|
Packit |
575503 |
efree(mb_indices);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
done:
|
|
Packit |
575503 |
DEREF(rep_node);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((matches == 0 || (flags & LITERAL) != 0) && buf != NULL) {
|
|
Packit |
575503 |
efree(buf);
|
|
Packit |
575503 |
buf = NULL;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (flags & GENSUB) {
|
|
Packit |
575503 |
if (matches > 0) {
|
|
Packit |
575503 |
/* return the result string */
|
|
Packit |
575503 |
DEREF(target);
|
|
Packit |
575503 |
assert(buf != NULL);
|
|
Packit |
575503 |
return make_str_node(buf, textlen, ALREADY_MALLOCED);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* return the original string */
|
|
Packit |
575503 |
return target;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* For a string literal, must not change the original string. */
|
|
Packit |
575503 |
if ((flags & LITERAL) != 0)
|
|
Packit |
575503 |
DEREF(target);
|
|
Packit |
575503 |
else if (matches > 0) {
|
|
Packit |
575503 |
unref(*lhs);
|
|
Packit |
575503 |
*lhs = make_str_node(buf, textlen, ALREADY_MALLOCED);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_number((AWKNUM) matches);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* call_sub --- call do_sub indirectly */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
call_sub(const char *name, int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
unsigned int flags = 0;
|
|
Packit |
575503 |
NODE *regex, *replace, *glob_flag;
|
|
Packit |
575503 |
NODE **lhs, *rhs;
|
|
Packit |
575503 |
NODE *zero = make_number(0.0);
|
|
Packit |
575503 |
NODE *result;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (name[0] == 'g') {
|
|
Packit |
575503 |
if (name[1] == 'e')
|
|
Packit |
575503 |
flags = GENSUB;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
flags = GSUB;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (flags == 0 || flags == GSUB) {
|
|
Packit |
575503 |
/* sub or gsub */
|
|
Packit |
575503 |
if (nargs != 2)
|
|
Packit |
575503 |
fatal(_("%s: can be called indirectly only with two arguments"), name);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
replace = POP_STRING();
|
|
Packit |
575503 |
regex = POP(); /* the regex */
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* push regex
|
|
Packit |
575503 |
* push replace
|
|
Packit |
575503 |
* push $0
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if ((regex->flags & REGEX) != 0)
|
|
Packit |
575503 |
regex = regex->typed_re;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
regex = make_regnode(Node_regex, regex);
|
|
Packit |
575503 |
PUSH(regex);
|
|
Packit |
575503 |
PUSH(replace);
|
|
Packit |
575503 |
lhs = r_get_field(zero, (Func_ptr *) 0, true);
|
|
Packit |
575503 |
nargs++;
|
|
Packit |
575503 |
PUSH_ADDRESS(lhs);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
/* gensub */
|
|
Packit |
575503 |
if (nargs == 4)
|
|
Packit |
575503 |
rhs = POP();
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
rhs = NULL;
|
|
Packit |
575503 |
glob_flag = POP_STRING();
|
|
Packit |
575503 |
replace = POP_STRING();
|
|
Packit |
575503 |
regex = POP(); /* the regex */
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* push regex
|
|
Packit |
575503 |
* push replace
|
|
Packit |
575503 |
* push glob_flag
|
|
Packit |
575503 |
* if (nargs = 3) {
|
|
Packit |
575503 |
* push $0
|
|
Packit |
575503 |
* nargs++
|
|
Packit |
575503 |
* }
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if ((regex->flags & REGEX) != 0)
|
|
Packit |
575503 |
regex = regex->typed_re;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
regex = make_regnode(Node_regex, regex);
|
|
Packit |
575503 |
PUSH(regex);
|
|
Packit |
575503 |
PUSH(replace);
|
|
Packit |
575503 |
PUSH(glob_flag);
|
|
Packit |
575503 |
if (rhs == NULL) {
|
|
Packit |
575503 |
lhs = r_get_field(zero, (Func_ptr *) 0, true);
|
|
Packit |
575503 |
rhs = *lhs;
|
|
Packit |
575503 |
UPREF(rhs);
|
|
Packit |
575503 |
PUSH(rhs);
|
|
Packit |
575503 |
nargs++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
PUSH(rhs);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
unref(zero);
|
|
Packit |
575503 |
result = do_sub(nargs, flags);
|
|
Packit |
575503 |
if (flags != GENSUB)
|
|
Packit |
575503 |
reset_record();
|
|
Packit |
575503 |
return result;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* call_match --- call do_match indirectly */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
call_match(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *regex, *text, *array;
|
|
Packit |
575503 |
NODE *result;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
regex = text = array = NULL;
|
|
Packit |
575503 |
if (nargs == 3)
|
|
Packit |
575503 |
array = POP();
|
|
Packit |
575503 |
regex = POP();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* Don't need to pop the string just to push it back ... */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if ((regex->flags & REGEX) != 0)
|
|
Packit |
575503 |
regex = regex->typed_re;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
regex = make_regnode(Node_regex, regex);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
PUSH(regex);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (array)
|
|
Packit |
575503 |
PUSH(array);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
result = do_match(nargs);
|
|
Packit |
575503 |
return result;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* call_split_func --- call do_split or do_pat_split indirectly */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
call_split_func(const char *name, int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *regex, *seps;
|
|
Packit |
575503 |
NODE *result;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
regex = seps = NULL;
|
|
Packit |
575503 |
if (nargs < 2)
|
|
Packit |
575503 |
fatal(_("indirect call to %s requires at least two arguments"),
|
|
Packit |
575503 |
name);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 4)
|
|
Packit |
575503 |
seps = POP();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs >= 3) {
|
|
Packit |
575503 |
regex = POP_STRING();
|
|
Packit |
575503 |
if ((regex->flags & REGEX) != 0)
|
|
Packit |
575503 |
regex = regex->typed_re;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
regex = make_regnode(Node_regex, regex);
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
if (name[0] == 's') {
|
|
Packit |
575503 |
regex = make_regnode(Node_regex, FS_node->var_value);
|
|
Packit |
575503 |
regex->re_flags |= FS_DFLT;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
regex = make_regnode(Node_regex, FPAT_node->var_value);
|
|
Packit |
575503 |
nargs++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* Don't need to pop the string or the data array */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
PUSH(regex);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (seps)
|
|
Packit |
575503 |
PUSH(seps);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
result = (name[0] == 's') ? do_split(nargs) : do_patsplit(nargs);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return result;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* make_integer - Convert an integer to a number node. */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static NODE *
|
|
Packit |
575503 |
make_integer(uintmax_t n)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
n = adjust_uint(n);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_number((AWKNUM) n);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_lshift --- perform a << operation */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_lshift(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *s1, *s2;
|
|
Packit |
575503 |
uintmax_t uval, ushift, res;
|
|
Packit |
575503 |
AWKNUM val, shift;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
POP_TWO_SCALARS(s1, s2);
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if ((fixtype(s1)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("lshift: received non-numeric first argument"));
|
|
Packit |
575503 |
if ((fixtype(s2)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("lshift: received non-numeric second argument"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
val = force_number(s1)->numbr;
|
|
Packit |
575503 |
shift = force_number(s2)->numbr;
|
|
Packit |
575503 |
if (val < 0 || shift < 0)
|
|
Packit |
575503 |
fatal(_("lshift(%f, %f): negative values are not allowed"), val, shift);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if (double_to_int(val) != val || double_to_int(shift) != shift)
|
|
Packit |
575503 |
lintwarn(_("lshift(%f, %f): fractional values will be truncated"), val, shift);
|
|
Packit |
575503 |
if (shift >= sizeof(uintmax_t) * CHAR_BIT)
|
|
Packit |
575503 |
lintwarn(_("lshift(%f, %f): too large shift value will give strange results"), val, shift);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(s1);
|
|
Packit |
575503 |
DEREF(s2);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
uval = (uintmax_t) val;
|
|
Packit |
575503 |
ushift = (uintmax_t) shift;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
res = uval << ushift;
|
|
Packit |
575503 |
return make_integer(res);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_rshift --- perform a >> operation */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_rshift(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *s1, *s2;
|
|
Packit |
575503 |
uintmax_t uval, ushift, res;
|
|
Packit |
575503 |
AWKNUM val, shift;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
POP_TWO_SCALARS(s1, s2);
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if ((fixtype(s1)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("rshift: received non-numeric first argument"));
|
|
Packit |
575503 |
if ((fixtype(s2)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("rshift: received non-numeric second argument"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
val = force_number(s1)->numbr;
|
|
Packit |
575503 |
shift = force_number(s2)->numbr;
|
|
Packit |
575503 |
if (val < 0 || shift < 0)
|
|
Packit |
575503 |
fatal(_("rshift(%f, %f): negative values are not allowed"), val, shift);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if (double_to_int(val) != val || double_to_int(shift) != shift)
|
|
Packit |
575503 |
lintwarn(_("rshift(%f, %f): fractional values will be truncated"), val, shift);
|
|
Packit |
575503 |
if (shift >= sizeof(uintmax_t) * CHAR_BIT)
|
|
Packit |
575503 |
lintwarn(_("rshift(%f, %f): too large shift value will give strange results"), val, shift);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(s1);
|
|
Packit |
575503 |
DEREF(s2);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
uval = (uintmax_t) val;
|
|
Packit |
575503 |
ushift = (uintmax_t) shift;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
res = uval >> ushift;
|
|
Packit |
575503 |
return make_integer(res);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_and --- perform an & operation */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_and(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *s1;
|
|
Packit |
575503 |
uintmax_t res, uval;
|
|
Packit |
575503 |
AWKNUM val;
|
|
Packit |
575503 |
int i;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
res = ~0; /* start off with all ones */
|
|
Packit |
575503 |
if (nargs < 2)
|
|
Packit |
575503 |
fatal(_("and: called with less than two arguments"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (i = 1; nargs > 0; nargs--, i++) {
|
|
Packit |
575503 |
s1 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(s1)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("and: argument %d is non-numeric"), i);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
val = force_number(s1)->numbr;
|
|
Packit |
575503 |
if (val < 0)
|
|
Packit |
575503 |
fatal(_("and: argument %d negative value %g is not allowed"), i, val);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
uval = (uintmax_t) val;
|
|
Packit |
575503 |
res &= uval;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(s1);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_integer(res);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_or --- perform an | operation */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_or(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *s1;
|
|
Packit |
575503 |
uintmax_t res, uval;
|
|
Packit |
575503 |
AWKNUM val;
|
|
Packit |
575503 |
int i;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
res = 0;
|
|
Packit |
575503 |
if (nargs < 2)
|
|
Packit |
575503 |
fatal(_("or: called with less than two arguments"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (i = 1; nargs > 0; nargs--, i++) {
|
|
Packit |
575503 |
s1 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(s1)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("or: argument %d is non-numeric"), i);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
val = force_number(s1)->numbr;
|
|
Packit |
575503 |
if (val < 0)
|
|
Packit |
575503 |
fatal(_("or: argument %d negative value %g is not allowed"), i, val);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
uval = (uintmax_t) val;
|
|
Packit |
575503 |
res |= uval;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(s1);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_integer(res);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_xor --- perform an ^ operation */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_xor(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *s1;
|
|
Packit |
575503 |
uintmax_t res, uval;
|
|
Packit |
575503 |
AWKNUM val;
|
|
Packit |
575503 |
int i;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs < 2)
|
|
Packit |
575503 |
fatal(_("xor: called with less than two arguments"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
res = 0; /* silence compiler warning */
|
|
Packit |
575503 |
for (i = 1; nargs > 0; nargs--, i++) {
|
|
Packit |
575503 |
s1 = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(s1)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("xor: argument %d is non-numeric"), i);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
val = force_number(s1)->numbr;
|
|
Packit |
575503 |
if (val < 0)
|
|
Packit |
575503 |
fatal(_("xor: argument %d negative value %g is not allowed"), i, val);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
uval = (uintmax_t) val;
|
|
Packit |
575503 |
if (i == 1)
|
|
Packit |
575503 |
res = uval;
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
res ^= uval;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(s1);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_integer(res);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_compl --- perform a ~ operation */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_compl(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
double d;
|
|
Packit |
575503 |
uintmax_t uval;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = POP_SCALAR();
|
|
Packit |
575503 |
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("compl: received non-numeric argument"));
|
|
Packit |
575503 |
d = force_number(tmp)->numbr;
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (d < 0)
|
|
Packit |
575503 |
fatal(_("compl(%f): negative value is not allowed"), d);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint && double_to_int(d) != d)
|
|
Packit |
575503 |
lintwarn(_("compl(%f): fractional value will be truncated"), d);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
uval = (uintmax_t) d;
|
|
Packit |
575503 |
uval = ~ uval;
|
|
Packit |
575503 |
return make_integer(uval);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_strtonum --- the strtonum function */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_strtonum(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp;
|
|
Packit |
575503 |
AWKNUM d;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
tmp = fixtype(POP_SCALAR());
|
|
Packit |
575503 |
if ((tmp->flags & NUMBER) != 0)
|
|
Packit |
575503 |
d = (AWKNUM) tmp->numbr;
|
|
Packit |
575503 |
else if (get_numbase(tmp->stptr, tmp->stlen, use_lc_numeric) != 10)
|
|
Packit |
575503 |
d = nondec2awknum(tmp->stptr, tmp->stlen, NULL);
|
|
Packit |
575503 |
else
|
|
Packit |
575503 |
d = (AWKNUM) force_number(tmp)->numbr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
return make_number((AWKNUM) d);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* nondec2awknum --- convert octal or hex value to double */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Because of awk's concatenation rules and the way awk.y:yylex()
|
|
Packit |
575503 |
* collects a number, this routine has to be willing to stop on the
|
|
Packit |
575503 |
* first invalid character.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
AWKNUM
|
|
Packit |
575503 |
nondec2awknum(char *str, size_t len, char **endptr)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
AWKNUM retval = 0.0;
|
|
Packit |
575503 |
char save;
|
|
Packit |
575503 |
short val;
|
|
Packit |
575503 |
char *start = str;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (len >= 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* User called strtonum("0x") or some such,
|
|
Packit |
575503 |
* so just quit early.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
if (len <= 2) {
|
|
Packit |
575503 |
if (endptr)
|
|
Packit |
575503 |
*endptr = start;
|
|
Packit |
575503 |
return (AWKNUM) 0.0;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (str += 2, len -= 2; len > 0; len--, str++) {
|
|
Packit |
575503 |
switch (*str) {
|
|
Packit |
575503 |
case '0':
|
|
Packit |
575503 |
case '1':
|
|
Packit |
575503 |
case '2':
|
|
Packit |
575503 |
case '3':
|
|
Packit |
575503 |
case '4':
|
|
Packit |
575503 |
case '5':
|
|
Packit |
575503 |
case '6':
|
|
Packit |
575503 |
case '7':
|
|
Packit |
575503 |
case '8':
|
|
Packit |
575503 |
case '9':
|
|
Packit |
575503 |
val = *str - '0';
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case 'a':
|
|
Packit |
575503 |
case 'b':
|
|
Packit |
575503 |
case 'c':
|
|
Packit |
575503 |
case 'd':
|
|
Packit |
575503 |
case 'e':
|
|
Packit |
575503 |
case 'f':
|
|
Packit |
575503 |
val = *str - 'a' + 10;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case 'A':
|
|
Packit |
575503 |
case 'B':
|
|
Packit |
575503 |
case 'C':
|
|
Packit |
575503 |
case 'D':
|
|
Packit |
575503 |
case 'E':
|
|
Packit |
575503 |
case 'F':
|
|
Packit |
575503 |
val = *str - 'A' + 10;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
default:
|
|
Packit |
575503 |
if (endptr)
|
|
Packit |
575503 |
*endptr = str;
|
|
Packit |
575503 |
goto done;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
retval = (retval * 16) + val;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (endptr)
|
|
Packit |
575503 |
*endptr = str;
|
|
Packit |
575503 |
} else if (len >= 1 && *str == '0') {
|
|
Packit |
575503 |
for (; len > 0; len--) {
|
|
Packit |
575503 |
if (! isdigit((unsigned char) *str)) {
|
|
Packit |
575503 |
if (endptr)
|
|
Packit |
575503 |
*endptr = str;
|
|
Packit |
575503 |
goto done;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
else if (*str == '8' || *str == '9') {
|
|
Packit |
575503 |
str = start;
|
|
Packit |
575503 |
goto decimal;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
retval = (retval * 8) + (*str - '0');
|
|
Packit |
575503 |
str++;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (endptr)
|
|
Packit |
575503 |
*endptr = str;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
decimal:
|
|
Packit |
575503 |
save = str[len];
|
|
Packit |
575503 |
str[len] = '\0';
|
|
Packit |
575503 |
retval = strtod(str, endptr);
|
|
Packit |
575503 |
str[len] = save;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
done:
|
|
Packit |
575503 |
return retval;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_dcgettext, do_dcngettext --- handle i18n translations */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static int
|
|
Packit |
575503 |
localecategory_from_argument(NODE *t)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
static const struct category_table {
|
|
Packit |
575503 |
int val;
|
|
Packit |
575503 |
const char *name;
|
|
Packit |
575503 |
} cat_tab[] = {
|
|
Packit |
575503 |
#ifdef LC_ALL
|
|
Packit |
575503 |
{ LC_ALL, "LC_ALL" },
|
|
Packit |
575503 |
#endif /* LC_ALL */
|
|
Packit |
575503 |
#ifdef LC_COLLATE
|
|
Packit |
575503 |
{ LC_COLLATE, "LC_COLLATE" },
|
|
Packit |
575503 |
#endif /* LC_COLLATE */
|
|
Packit |
575503 |
#ifdef LC_CTYPE
|
|
Packit |
575503 |
{ LC_CTYPE, "LC_CTYPE" },
|
|
Packit |
575503 |
#endif /* LC_CTYPE */
|
|
Packit |
575503 |
#ifdef LC_MESSAGES
|
|
Packit |
575503 |
{ LC_MESSAGES, "LC_MESSAGES" },
|
|
Packit |
575503 |
#endif /* LC_MESSAGES */
|
|
Packit |
575503 |
#ifdef LC_MONETARY
|
|
Packit |
575503 |
{ LC_MONETARY, "LC_MONETARY" },
|
|
Packit |
575503 |
#endif /* LC_MONETARY */
|
|
Packit |
575503 |
#ifdef LC_NUMERIC
|
|
Packit |
575503 |
{ LC_NUMERIC, "LC_NUMERIC" },
|
|
Packit |
575503 |
#endif /* LC_NUMERIC */
|
|
Packit |
575503 |
#ifdef LC_RESPONSE
|
|
Packit |
575503 |
{ LC_RESPONSE, "LC_RESPONSE" },
|
|
Packit |
575503 |
#endif /* LC_RESPONSE */
|
|
Packit |
575503 |
#ifdef LC_TIME
|
|
Packit |
575503 |
{ LC_TIME, "LC_TIME" },
|
|
Packit |
575503 |
#endif /* LC_TIME */
|
|
Packit |
575503 |
};
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (t != NULL) {
|
|
Packit |
575503 |
int low, high, i, mid;
|
|
Packit |
575503 |
char *category;
|
|
Packit |
575503 |
int lc_cat = -1;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
char save = t->stptr[t->stlen];
|
|
Packit |
575503 |
t->stptr[t->stlen] = '\0';
|
|
Packit |
575503 |
category = t->stptr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* binary search the table */
|
|
Packit |
575503 |
low = 0;
|
|
Packit |
575503 |
high = (sizeof(cat_tab) / sizeof(cat_tab[0])) - 1;
|
|
Packit |
575503 |
while (low <= high) {
|
|
Packit |
575503 |
mid = (low + high) / 2;
|
|
Packit |
575503 |
i = strcmp(category, cat_tab[mid].name);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (i < 0) /* category < mid */
|
|
Packit |
575503 |
high = mid - 1;
|
|
Packit |
575503 |
else if (i > 0) /* category > mid */
|
|
Packit |
575503 |
low = mid + 1;
|
|
Packit |
575503 |
else {
|
|
Packit |
575503 |
lc_cat = cat_tab[mid].val;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
t->stptr[t->stlen] = save;
|
|
Packit |
575503 |
if (lc_cat == -1) /* not there */
|
|
Packit |
575503 |
fatal(_("dcgettext: `%s' is not a valid locale category"), category);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return lc_cat;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
return LC_MESSAGES;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* awk usage is
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* str = dcgettext(string [, domain [, category]])
|
|
Packit |
575503 |
* str = dcngettext(string1, string2, number [, domain [, category]])
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* Default domain is TEXTDOMAIN, default category is LC_MESSAGES.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_dcgettext(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp, *t1, *t2 = NULL;
|
|
Packit |
575503 |
char *string;
|
|
Packit |
575503 |
char *the_result;
|
|
Packit |
575503 |
size_t reslen;
|
|
Packit |
575503 |
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
|
|
Packit |
575503 |
int lc_cat;
|
|
Packit |
575503 |
char *domain;
|
|
Packit |
575503 |
char save1 = '\0', save2 = '\0';
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 3) { /* third argument */
|
|
Packit |
575503 |
tmp = POP_STRING();
|
|
Packit |
575503 |
lc_cat = localecategory_from_argument(tmp);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
lc_cat = LC_MESSAGES;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs >= 2) { /* second argument */
|
|
Packit |
575503 |
t2 = POP_STRING();
|
|
Packit |
575503 |
domain = t2->stptr;
|
|
Packit |
575503 |
str_terminate(t2, save2);
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
domain = TEXTDOMAIN;
|
|
Packit |
575503 |
#else
|
|
Packit |
575503 |
if (nargs == 3) {
|
|
Packit |
575503 |
tmp = POP_STRING();
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (nargs >= 2) {
|
|
Packit |
575503 |
t2 = POP_STRING();
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = POP_STRING(); /* first argument */
|
|
Packit |
575503 |
string = t1->stptr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
|
|
Packit |
575503 |
str_terminate(t1, save1);
|
|
Packit |
575503 |
the_result = dcgettext(domain, string, lc_cat);
|
|
Packit |
575503 |
str_restore(t1, save1);
|
|
Packit |
575503 |
if (t2 != NULL) {
|
|
Packit |
575503 |
str_restore(t2, save2);
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
reslen = strlen(the_result);
|
|
Packit |
575503 |
#else
|
|
Packit |
575503 |
the_result = string;
|
|
Packit |
575503 |
reslen = t1->stlen;
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
return make_string(the_result, reslen);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_dcngettext(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *tmp, *t1, *t2, *t3;
|
|
Packit |
575503 |
char *string1, *string2;
|
|
Packit |
575503 |
unsigned long number;
|
|
Packit |
575503 |
AWKNUM d;
|
|
Packit |
575503 |
char *the_result;
|
|
Packit |
575503 |
size_t reslen;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
|
|
Packit |
575503 |
int lc_cat;
|
|
Packit |
575503 |
char *domain;
|
|
Packit |
575503 |
char save = '\0', save1 = '\0', save2 = '\0';
|
|
Packit |
575503 |
bool saved_end = false;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 5) { /* fifth argument */
|
|
Packit |
575503 |
tmp = POP_STRING();
|
|
Packit |
575503 |
lc_cat = localecategory_from_argument(tmp);
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
lc_cat = LC_MESSAGES;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t3 = NULL;
|
|
Packit |
575503 |
if (nargs >= 4) { /* fourth argument */
|
|
Packit |
575503 |
t3 = POP_STRING();
|
|
Packit |
575503 |
domain = t3->stptr;
|
|
Packit |
575503 |
save = domain[t3->stlen];
|
|
Packit |
575503 |
domain[t3->stlen] = '\0';
|
|
Packit |
575503 |
saved_end = true;
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
domain = TEXTDOMAIN;
|
|
Packit |
575503 |
#else
|
|
Packit |
575503 |
if (nargs == 5) {
|
|
Packit |
575503 |
tmp = POP_STRING();
|
|
Packit |
575503 |
DEREF(tmp);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
if (nargs >= 4) {
|
|
Packit |
575503 |
t3 = POP_STRING();
|
|
Packit |
575503 |
DEREF(t3);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t2 = POP_NUMBER(); /* third argument */
|
|
Packit |
575503 |
d = get_number_d(t2);
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
number = (unsigned long) double_to_int(d);
|
|
Packit |
575503 |
t2 = POP_STRING(); /* second argument */
|
|
Packit |
575503 |
string2 = t2->stptr;
|
|
Packit |
575503 |
t1 = POP_STRING(); /* first argument */
|
|
Packit |
575503 |
string1 = t1->stptr;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
|
|
Packit |
575503 |
|
|
Packit |
575503 |
str_terminate(t1, save1);
|
|
Packit |
575503 |
str_terminate(t2, save2);
|
|
Packit |
575503 |
the_result = dcngettext(domain, string1, string2, number, lc_cat);
|
|
Packit |
575503 |
reslen = strlen(the_result);
|
|
Packit |
575503 |
str_restore(t1, save1);
|
|
Packit |
575503 |
str_restore(t2, save2);
|
|
Packit |
575503 |
if (saved_end)
|
|
Packit |
575503 |
domain[t3->stlen] = save;
|
|
Packit |
575503 |
if (t3 != NULL)
|
|
Packit |
575503 |
DEREF(t3);
|
|
Packit |
575503 |
#else
|
|
Packit |
575503 |
if (number == 1) {
|
|
Packit |
575503 |
the_result = string1;
|
|
Packit |
575503 |
reslen = t1->stlen;
|
|
Packit |
575503 |
} else {
|
|
Packit |
575503 |
the_result = string2;
|
|
Packit |
575503 |
reslen = t2->stlen;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
return make_string(the_result, reslen);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_bindtextdomain --- set the directory for a text domain */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* awk usage is
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* binding = bindtextdomain(dir [, domain])
|
|
Packit |
575503 |
*
|
|
Packit |
575503 |
* If dir is "", pass NULL to C version.
|
|
Packit |
575503 |
* Default domain is TEXTDOMAIN.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_bindtextdomain(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *t1, *t2;
|
|
Packit |
575503 |
const char *directory, *domain;
|
|
Packit |
575503 |
const char *the_result;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
t1 = t2 = NULL;
|
|
Packit |
575503 |
/* set defaults */
|
|
Packit |
575503 |
directory = NULL;
|
|
Packit |
575503 |
domain = TEXTDOMAIN;
|
|
Packit |
575503 |
char save = '\0', save1 = '\0';
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (nargs == 2) { /* second argument */
|
|
Packit |
575503 |
t2 = POP_STRING();
|
|
Packit |
575503 |
domain = (const char *) t2->stptr;
|
|
Packit |
575503 |
save = t2->stptr[t2->stlen];
|
|
Packit |
575503 |
t2->stptr[t2->stlen] = '\0';
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* first argument */
|
|
Packit |
575503 |
t1 = POP_STRING();
|
|
Packit |
575503 |
if (t1->stlen > 0) {
|
|
Packit |
575503 |
directory = (const char *) t1->stptr;
|
|
Packit |
575503 |
str_terminate(t1, save1);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
the_result = bindtextdomain(domain, directory);
|
|
Packit |
575503 |
if (directory)
|
|
Packit |
575503 |
str_restore(t1, save1);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(t1);
|
|
Packit |
575503 |
if (t2 != NULL) {
|
|
Packit |
575503 |
t2->stptr[t2->stlen] = save;
|
|
Packit |
575503 |
DEREF(t2);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_string(the_result, strlen(the_result));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
#ifdef SUPPLY_INTDIV
|
|
Packit |
575503 |
/* do_intdiv --- do integer division, return quotient and remainder in dest array */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* We define the semantics as:
|
|
Packit |
575503 |
* numerator = int(numerator)
|
|
Packit |
575503 |
* denominator = int(denonmator)
|
|
Packit |
575503 |
* quotient = int(numerator / denomator)
|
|
Packit |
575503 |
* remainder = int(numerator % denomator)
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_intdiv(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *numerator, *denominator, *result;
|
|
Packit |
575503 |
double num, denom, quotient, remainder;
|
|
Packit |
575503 |
NODE *sub, **lhs;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
result = POP_PARAM();
|
|
Packit |
575503 |
if (result->type != Node_var_array)
|
|
Packit |
575503 |
fatal(_("intdiv: third argument is not an array"));
|
|
Packit |
575503 |
assoc_clear(result);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
denominator = POP_SCALAR();
|
|
Packit |
575503 |
numerator = POP_SCALAR();
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (do_lint) {
|
|
Packit |
575503 |
if ((fixtype(numerator)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("intdiv: received non-numeric first argument"));
|
|
Packit |
575503 |
if ((fixtype(denominator)->flags & NUMBER) == 0)
|
|
Packit |
575503 |
lintwarn(_("intdiv: received non-numeric second argument"));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
(void) force_number(numerator);
|
|
Packit |
575503 |
(void) force_number(denominator);
|
|
Packit |
575503 |
num = double_to_int(get_number_d(numerator));
|
|
Packit |
575503 |
denom = double_to_int(get_number_d(denominator));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (denom == 0.0)
|
|
Packit |
575503 |
fatal(_("intdiv: division by zero attempted"));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
quotient = double_to_int(num / denom);
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* FIXME: This code is duplicated, factor it out to a
|
|
Packit |
575503 |
* separate function.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
#ifdef HAVE_FMOD
|
|
Packit |
575503 |
remainder = fmod(num, denom);
|
|
Packit |
575503 |
#else /* ! HAVE_FMOD */
|
|
Packit |
575503 |
(void) modf(num / denom, & remainder);
|
|
Packit |
575503 |
remainder = num - remainder * denom;
|
|
Packit |
575503 |
#endif /* ! HAVE_FMOD */
|
|
Packit |
575503 |
remainder = double_to_int(remainder);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
sub = make_string("quotient", 8);
|
|
Packit |
575503 |
lhs = assoc_lookup(result, sub);
|
|
Packit |
575503 |
unref(*lhs);
|
|
Packit |
575503 |
*lhs = make_number((AWKNUM) quotient);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
sub = make_string("remainder", 9);
|
|
Packit |
575503 |
lhs = assoc_lookup(result, sub);
|
|
Packit |
575503 |
unref(*lhs);
|
|
Packit |
575503 |
*lhs = make_number((AWKNUM) remainder);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
DEREF(denominator);
|
|
Packit |
575503 |
DEREF(numerator);
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return make_number((AWKNUM) 0.0);
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
#endif /* SUPPLY_INTDIV */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* do_typeof --- return a string with the type of the arg */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
NODE *
|
|
Packit |
575503 |
do_typeof(int nargs)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
NODE *arg;
|
|
Packit |
575503 |
char *res = NULL;
|
|
Packit |
575503 |
bool deref = true;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
arg = POP();
|
|
Packit |
575503 |
switch (arg->type) {
|
|
Packit |
575503 |
case Node_var_array:
|
|
Packit |
575503 |
/* Node_var_array is never UPREF'ed */
|
|
Packit |
575503 |
res = "array";
|
|
Packit |
575503 |
deref = false;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case Node_val:
|
|
Packit |
575503 |
switch (fixtype(arg)->flags & (STRING|NUMBER|USER_INPUT|REGEX)) {
|
|
Packit |
575503 |
case NUMBER:
|
|
Packit |
575503 |
res = "number";
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case NUMBER|USER_INPUT:
|
|
Packit |
575503 |
res = "strnum";
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case REGEX:
|
|
Packit |
575503 |
res = "regexp";
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case STRING:
|
|
Packit |
575503 |
res = "string";
|
|
Packit |
575503 |
// fall through
|
|
Packit |
575503 |
case NUMBER|STRING:
|
|
Packit |
575503 |
if (arg == Nnull_string || (arg->flags & NULL_FIELD) != 0) {
|
|
Packit |
575503 |
res = "unassigned";
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
/* fall through */
|
|
Packit |
575503 |
default:
|
|
Packit |
575503 |
if (res == NULL) {
|
|
Packit |
575503 |
warning(_("typeof detected invalid flags combination `%s'; please file a bug report."), flags2str(arg->flags));
|
|
Packit |
575503 |
res = "unknown";
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case Node_var_new:
|
|
Packit |
575503 |
res = "untyped";
|
|
Packit |
575503 |
deref = false;
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
case Node_var:
|
|
Packit |
575503 |
/*
|
|
Packit |
575503 |
* Note: this doesn't happen because the function calling code
|
|
Packit |
575503 |
* in interpret.h pushes Node_var->var_value.
|
|
Packit |
575503 |
*/
|
|
Packit |
575503 |
fatal(_("typeof: invalid argument type `%s'"),
|
|
Packit |
575503 |
nodetype2str(arg->type));
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
default:
|
|
Packit |
575503 |
fatal(_("typeof: unknown argument type `%s'"),
|
|
Packit |
575503 |
nodetype2str(arg->type));
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (deref)
|
|
Packit |
575503 |
DEREF(arg);
|
|
Packit |
575503 |
return make_string(res, strlen(res));
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* mbc_byte_count --- return number of bytes for corresponding numchars multibyte characters */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static size_t
|
|
Packit |
575503 |
mbc_byte_count(const char *ptr, size_t numchars)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
mbstate_t cur_state;
|
|
Packit |
575503 |
size_t sum = 0;
|
|
Packit |
575503 |
int mb_len;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& cur_state, 0, sizeof(cur_state));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
assert(gawk_mb_cur_max > 1);
|
|
Packit |
575503 |
mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
|
|
Packit |
575503 |
if (mb_len <= 0)
|
|
Packit |
575503 |
return numchars; /* no valid m.b. char */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
for (; numchars > 0; numchars--) {
|
|
Packit |
575503 |
mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
|
|
Packit |
575503 |
if (mb_len <= 0)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
sum += mb_len;
|
|
Packit |
575503 |
ptr += mb_len;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return sum;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* mbc_char_count --- return number of m.b. chars in string, up to numbytes bytes */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
static size_t
|
|
Packit |
575503 |
mbc_char_count(const char *ptr, size_t numbytes)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
mbstate_t cur_state;
|
|
Packit |
575503 |
size_t sum = 0;
|
|
Packit |
575503 |
int mb_len;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (gawk_mb_cur_max == 1)
|
|
Packit |
575503 |
return numbytes;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
memset(& cur_state, 0, sizeof(cur_state));
|
|
Packit |
575503 |
|
|
Packit |
575503 |
mb_len = mbrlen(ptr, numbytes, &cur_state);
|
|
Packit |
575503 |
if (mb_len <= 0)
|
|
Packit |
575503 |
return numbytes; /* no valid m.b. char */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
while (numbytes > 0) {
|
|
Packit |
575503 |
mb_len = mbrlen(ptr, numbytes, &cur_state);
|
|
Packit |
575503 |
if (mb_len <= 0)
|
|
Packit |
575503 |
break;
|
|
Packit |
575503 |
sum++;
|
|
Packit |
575503 |
ptr += mb_len;
|
|
Packit |
575503 |
numbytes -= mb_len;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return sum;
|
|
Packit |
575503 |
}
|
|
Packit |
575503 |
|
|
Packit |
575503 |
/* sanitize_exit_status --- convert a 16 bit Unix exit status into something reasonable */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
int sanitize_exit_status(int status)
|
|
Packit |
575503 |
{
|
|
Packit |
575503 |
int ret = 0;
|
|
Packit |
575503 |
|
|
Packit |
575503 |
if (WIFEXITED(status))
|
|
Packit |
575503 |
ret = WEXITSTATUS(status); /* normal exit */
|
|
Packit |
575503 |
else if (WIFSIGNALED(status)) {
|
|
Packit |
575503 |
bool coredumped = false;
|
|
Packit |
575503 |
#ifdef WCOREDUMP
|
|
Packit |
575503 |
coredumped = WCOREDUMP(status);
|
|
Packit |
575503 |
#endif
|
|
Packit |
575503 |
/* use 256 since exit values are 8 bits */
|
|
Packit |
575503 |
ret = WTERMSIG(status) + (coredumped ? 512 : 256);
|
|
Packit |
575503 |
} else
|
|
Packit |
575503 |
ret = 0; /* shouldn't get here */
|
|
Packit |
575503 |
|
|
Packit |
575503 |
return ret;
|
|
Packit |
575503 |
}
|