1/* 2 * builtin.c - Builtin functions and various utility procedures 3 */ 4 5/* 6 * Copyright (C) 1986, 1988, 1989, 1991-2003 the Free Software Foundation, Inc. 7 * 8 * This file is part of GAWK, the GNU implementation of the 9 * AWK Programming Language. 10 * 11 * GAWK is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * GAWK is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 24 */ 25 26 27#include "awk.h" 28#if defined(HAVE_FCNTL_H) 29#include <fcntl.h> 30#endif 31#undef HUGE 32#undef CHARBITS 33#undef INTBITS 34#if HAVE_INTTYPES_H 35# include <inttypes.h> 36#else 37# if HAVE_STDINT_H 38# include <stdint.h> 39# endif 40#endif 41#include <math.h> 42#include "random.h" 43 44#ifndef CHAR_BIT 45# define CHAR_BIT 8 46#endif 47 48/* The extra casts work around common compiler bugs. */ 49#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) 50/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. 51 It is necessary at least when t == time_t. */ 52#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ 53 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) 54#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) 55 56#ifndef INTMAX_MIN 57# define INTMAX_MIN TYPE_MINIMUM (intmax_t) 58#endif 59#ifndef UINTMAX_MAX 60# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t) 61#endif 62 63#ifndef SIZE_MAX /* C99 constant, can't rely on it everywhere */ 64#define SIZE_MAX ((size_t) -1) 65#endif 66 67/* can declare these, since we always use the random shipped with gawk */ 68extern char *initstate P((unsigned long seed, char *state, long n)); 69extern char *setstate P((char *state)); 70extern long random P((void)); 71extern void srandom P((unsigned long seed)); 72 73extern NODE **fields_arr; 74extern int output_is_tty; 75 76static NODE *sub_common P((NODE *tree, long how_many, int backdigs)); 77 78#ifdef _CRAY 79/* Work around a problem in conversion of doubles to exact integers. */ 80#include <float.h> 81#define Floor(n) floor((n) * (1.0 + DBL_EPSILON)) 82#define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON)) 83 84/* Force the standard C compiler to use the library math functions. */ 85extern double exp(double); 86double (*Exp)() = exp; 87#define exp(x) (*Exp)(x) 88extern double log(double); 89double (*Log)() = log; 90#define log(x) (*Log)(x) 91#else 92#define Floor(n) floor(n) 93#define Ceil(n) ceil(n) 94#endif 95 96#define DEFAULT_G_PRECISION 6 97 98#ifdef GFMT_WORKAROUND 99/* semi-temporary hack, mostly to gracefully handle VMS */ 100static void sgfmt P((char *buf, const char *format, int alt, 101 int fwidth, int precision, double value)); 102#endif /* GFMT_WORKAROUND */ 103 104/* 105 * Since we supply the version of random(), we know what 106 * value to use here. 107 */ 108#define GAWK_RANDOM_MAX 0x7fffffffL 109 110static void efwrite P((const void *ptr, size_t size, size_t count, FILE *fp, 111 const char *from, struct redirect *rp, int flush)); 112 113/* efwrite --- like fwrite, but with error checking */ 114 115static void 116efwrite(const void *ptr, 117 size_t size, 118 size_t count, 119 FILE *fp, 120 const char *from, 121 struct redirect *rp, 122 int flush) 123{ 124 errno = 0; 125 if (fwrite(ptr, size, count, fp) != count) 126 goto wrerror; 127 if (flush 128 && ((fp == stdout && output_is_tty) 129 || (rp != NULL && (rp->flag & RED_NOBUF)))) { 130 fflush(fp); 131 if (ferror(fp)) 132 goto wrerror; 133 } 134 return; 135 136wrerror: 137 fatal(_("%s to \"%s\" failed (%s)"), from, 138 rp ? rp->value : _("standard output"), 139 errno ? strerror(errno) : _("reason unknown")); 140} 141 142/* do_exp --- exponential function */ 143 144NODE * 145do_exp(NODE *tree) 146{ 147 NODE *tmp; 148 double d, res; 149 150 tmp = tree_eval(tree->lnode); 151 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 152 lintwarn(_("exp: received non-numeric argument")); 153 d = force_number(tmp); 154 free_temp(tmp); 155 errno = 0; 156 res = exp(d); 157 if (errno == ERANGE) 158 warning(_("exp: argument %g is out of range"), d); 159 return tmp_number((AWKNUM) res); 160} 161 162/* stdfile --- return fp for a standard file */ 163 164/* 165 * This function allows `fflush("/dev/stdout")' to work. 166 * The other files will be available via getredirect(). 167 * /dev/stdin is not included, since fflush is only for output. 168 */ 169 170static FILE * 171stdfile(const char *name, size_t len) 172{ 173 if (len == 11) { 174 if (STREQN(name, "/dev/stderr", 11)) 175 return stderr; 176 else if (STREQN(name, "/dev/stdout", 11)) 177 return stdout; 178 } 179 180 return NULL; 181} 182 183/* do_fflush --- flush output, either named file or pipe or everything */ 184 185NODE * 186do_fflush(NODE *tree) 187{ 188 struct redirect *rp; 189 NODE *tmp; 190 FILE *fp; 191 int status = 0; 192 const char *file; 193 194 /* fflush() --- flush stdout */ 195 if (tree == NULL) { 196 status = fflush(stdout); 197 return tmp_number((AWKNUM) status); 198 } 199 200 tmp = tree_eval(tree->lnode); 201 tmp = force_string(tmp); 202 file = tmp->stptr; 203 204 /* fflush("") --- flush all */ 205 if (tmp->stlen == 0) { 206 status = flush_io(); 207 free_temp(tmp); 208 return tmp_number((AWKNUM) status); 209 } 210 211 rp = getredirect(tmp->stptr, tmp->stlen); 212 status = -1; 213 if (rp != NULL) { 214 if ((rp->flag & (RED_WRITE|RED_APPEND)) == 0) { 215 if (rp->flag & RED_PIPE) 216 warning(_("fflush: cannot flush: pipe `%s' opened for reading, not writing"), 217 file); 218 else 219 warning(_("fflush: cannot flush: file `%s' opened for reading, not writing"), 220 file); 221 free_temp(tmp); 222 return tmp_number((AWKNUM) status); 223 } 224 fp = rp->fp; 225 if (fp != NULL) 226 status = fflush(fp); 227 } else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) { 228 status = fflush(fp); 229 } else { 230 status = -1; 231 warning(_("fflush: `%s' is not an open file, pipe or co-process"), file); 232 } 233 free_temp(tmp); 234 return tmp_number((AWKNUM) status); 235} 236 237#ifdef MBS_SUPPORT 238/* strncasecmpmbs --- like strncasecmp(multibyte string version) */ 239int 240strncasecmpmbs(const char *s1, mbstate_t mbs1, const char *s2, 241 mbstate_t mbs2, size_t n) 242{ 243 int i1, i2, mbclen1, mbclen2, gap; 244 wchar_t wc1, wc2; 245 for (i1 = i2 = 0 ; i1 < n && i2 < n ;i1 += mbclen1, i2 += mbclen2) { 246 mbclen1 = mbrtowc(&wc1, s1 + i1, n - i1, &mbs1); 247 if (mbclen1 == (size_t) -1 || mbclen1 == (size_t) -2 || mbclen1 == 0) { 248 /* We treat it as a singlebyte character. */ 249 mbclen1 = 1; 250 wc1 = s1[i1]; 251 } 252 mbclen2 = mbrtowc(&wc2, s2 + i2, n - i2, &mbs2); 253 if (mbclen2 == (size_t) -1 || mbclen2 == (size_t) -2 || mbclen2 == 0) { 254 /* We treat it as a singlebyte character. */ 255 mbclen2 = 1; 256 wc2 = s2[i2]; 257 } 258 if ((gap = towlower(wc1) - towlower(wc2)) != 0) 259 /* s1 and s2 are not equivalent. */ 260 return gap; 261 } 262 /* s1 and s2 are equivalent. */ 263 return 0; 264} 265 266/* Inspect the buffer `src' and write the index of each byte to `dest'. 267 Caller must allocate `dest'. 268 e.g. str = <mb1(1)>, <mb1(2)>, a, b, <mb2(1)>, <mb2(2)>, <mb2(3)>, c 269 where mb(i) means the `i'-th byte of a multibyte character. 270 dest = 1, 2, 1, 1, 1, 2, 3. 1 271*/ 272static void 273index_multibyte_buffer(char* src, char* dest, int len) 274{ 275 int idx, prev_idx; 276 mbstate_t mbs, prevs; 277 memset(&prevs, 0, sizeof(mbstate_t)); 278 279 for (idx = prev_idx = 0 ; idx < len ; idx++) { 280 size_t mbclen; 281 mbs = prevs; 282 mbclen = mbrlen(src + prev_idx, idx - prev_idx + 1, &mbs); 283 if (mbclen == (size_t) -1 || mbclen == 1 || mbclen == 0) { 284 /* singlebyte character. */ 285 mbclen = 1; 286 prev_idx = idx + 1; 287 } else if (mbclen == (size_t) -2) { 288 /* a part of a multibyte character. */ 289 mbclen = idx - prev_idx + 1; 290 } else if (mbclen > 1) { 291 /* the end of a multibyte character. */ 292 prev_idx = idx + 1; 293 prevs = mbs; 294 } else { 295 /* Can't reach. */ 296 } 297 dest[idx] = mbclen; 298 } 299} 300#endif 301 302/* do_index --- find index of a string */ 303 304NODE * 305do_index(NODE *tree) 306{ 307 NODE *s1, *s2; 308 register const char *p1, *p2; 309 register size_t l1, l2; 310 long ret; 311#ifdef MBS_SUPPORT 312 size_t mbclen = 0; 313 mbstate_t mbs1, mbs2; 314 if (gawk_mb_cur_max > 1) { 315 memset(&mbs1, 0, sizeof(mbstate_t)); 316 memset(&mbs2, 0, sizeof(mbstate_t)); 317 } 318#endif 319 320 321 s1 = tree_eval(tree->lnode); 322 s2 = tree_eval(tree->rnode->lnode); 323 if (do_lint) { 324 if ((s1->flags & (STRING|STRCUR)) == 0) 325 lintwarn(_("index: received non-string first argument")); 326 if ((s2->flags & (STRING|STRCUR)) == 0) 327 lintwarn(_("index: received non-string second argument")); 328 } 329 force_string(s1); 330 force_string(s2); 331 p1 = s1->stptr; 332 p2 = s2->stptr; 333 l1 = s1->stlen; 334 l2 = s2->stlen; 335 ret = 0; 336 337 /* 338 * Icky special case, index(foo, "") should return 1, 339 * since both bwk awk and mawk do, and since match("foo", "") 340 * returns 1. This makes index("", "") work, too, fwiw. 341 */ 342 if (l2 == 0) { 343 ret = 1; 344 goto out; 345 } 346 347 /* IGNORECASE will already be false if posix */ 348 if (IGNORECASE) { 349 while (l1 > 0) { 350 if (l2 > l1) 351 break; 352#ifdef MBS_SUPPORT 353 if (gawk_mb_cur_max > 1) { 354 if (strncasecmpmbs(p1, mbs1, p2, mbs2, l2) == 0) { 355 ret = 1 + s1->stlen - l1; 356 break; 357 } 358 /* Update l1, and p1. */ 359 mbclen = mbrlen(p1, l1, &mbs1); 360 if ((mbclen == 1) || (mbclen == (size_t) -1) 361 || (mbclen == (size_t) -2) || (mbclen == 0)) { 362 /* We treat it as a singlebyte character. */ 363 mbclen = 1; 364 } 365 l1 -= mbclen; 366 p1 += mbclen; 367 } else { 368#endif 369 if (casetable[(unsigned char)*p1] == casetable[(unsigned char)*p2] 370 && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) { 371 ret = 1 + s1->stlen - l1; 372 break; 373 } 374 l1--; 375 p1++; 376#ifdef MBS_SUPPORT 377 } 378#endif 379 } 380 } else { 381 while (l1 > 0) { 382 if (l2 > l1) 383 break; 384 if (*p1 == *p2 385 && (l2 == 1 || STREQN(p1, p2, l2))) { 386 ret = 1 + s1->stlen - l1; 387 break; 388 } 389#ifdef MBS_SUPPORT 390 if (gawk_mb_cur_max > 1) { 391 mbclen = mbrlen(p1, l1, &mbs1); 392 if ((mbclen == 1) || (mbclen == (size_t) -1) || 393 (mbclen == (size_t) -2) || (mbclen == 0)) { 394 /* We treat it as a singlebyte character. */ 395 mbclen = 1; 396 } 397 l1 -= mbclen; 398 p1 += mbclen; 399 } else { 400 l1--; 401 p1++; 402 } 403#else 404 l1--; 405 p1++; 406#endif 407 } 408 } 409out: 410 free_temp(s1); 411 free_temp(s2); 412 return tmp_number((AWKNUM) ret); 413} 414 415/* double_to_int --- convert double to int, used several places */ 416 417double 418double_to_int(double d) 419{ 420 if (d >= 0) 421 d = Floor(d); 422 else 423 d = Ceil(d); 424 return d; 425} 426 427/* do_int --- convert double to int for awk */ 428 429NODE * 430do_int(NODE *tree) 431{ 432 NODE *tmp; 433 double d; 434 435 tmp = tree_eval(tree->lnode); 436 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 437 lintwarn(_("int: received non-numeric argument")); 438 d = force_number(tmp); 439 d = double_to_int(d); 440 free_temp(tmp); 441 return tmp_number((AWKNUM) d); 442} 443 444/* do_length --- length of a string or $0 */ 445 446NODE * 447do_length(NODE *tree) 448{ 449 NODE *tmp; 450 size_t len; 451 452 tmp = tree_eval(tree->lnode); 453 if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) 454 lintwarn(_("length: received non-string argument")); 455 len = force_string(tmp)->stlen; 456 free_temp(tmp); 457 return tmp_number((AWKNUM) len); 458} 459 460/* do_log --- the log function */ 461 462NODE * 463do_log(NODE *tree) 464{ 465 NODE *tmp; 466 double d, arg; 467 468 tmp = tree_eval(tree->lnode); 469 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 470 lintwarn(_("log: received non-numeric argument")); 471 arg = (double) force_number(tmp); 472 if (arg < 0.0) 473 warning(_("log: received negative argument %g"), arg); 474 d = log(arg); 475 free_temp(tmp); 476 return tmp_number((AWKNUM) d); 477} 478 479/* 480 * format_tree() formats nodes of a tree, starting with a left node, 481 * and accordingly to a fmt_string providing a format like in 482 * printf family from C library. Returns a string node which value 483 * is a formatted string. Called by sprintf function. 484 * 485 * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann 486 * for taming this beast and making it compatible with ANSI C. 487 */ 488 489NODE * 490format_tree( 491 const char *fmt_string, 492 size_t n0, 493 register NODE *carg, 494 long num_args) 495{ 496/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */ 497/* difference of pointers should be of ptrdiff_t type, but let us be kind */ 498#define bchunk(s, l) if (l) { \ 499 while ((l) > ofre) { \ 500 long olen = obufout - obuf; \ 501 erealloc(obuf, char *, osiz * 2, "format_tree"); \ 502 ofre += osiz; \ 503 osiz *= 2; \ 504 obufout = obuf + olen; \ 505 } \ 506 memcpy(obufout, s, (size_t) (l)); \ 507 obufout += (l); \ 508 ofre -= (l); \ 509} 510 511/* copy one byte from 's' to 'obufout' checking for space in the process */ 512#define bchunk_one(s) { \ 513 if (ofre < 1) { \ 514 long olen = obufout - obuf; \ 515 erealloc(obuf, char *, osiz * 2, "format_tree"); \ 516 ofre += osiz; \ 517 osiz *= 2; \ 518 obufout = obuf + olen; \ 519 } \ 520 *obufout++ = *s; \ 521 --ofre; \ 522} 523 524/* Is there space for something L big in the buffer? */ 525#define chksize(l) if ((l) > ofre) { \ 526 long olen = obufout - obuf; \ 527 erealloc(obuf, char *, osiz * 2, "format_tree"); \ 528 obufout = obuf + olen; \ 529 ofre += osiz; \ 530 osiz *= 2; \ 531} 532 533 static NODE **the_args = 0; 534 static size_t args_size = 0; 535 size_t cur_arg = 0; 536 537 auto NODE **save_args = 0; 538 auto size_t save_args_size = 0; 539 static int call_level = 0; 540 541 NODE *r; 542 int i; 543 int toofew = FALSE; 544 char *obuf, *obufout; 545 size_t osiz, ofre; 546 const char *chbuf; 547 const char *s0, *s1; 548 int cs1; 549 NODE *arg; 550 long fw, prec, argnum; 551 int used_dollar; 552 int lj, alt, big, bigbig, small, have_prec, need_format; 553 long *cur = NULL; 554#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */ 555 long tmp_uval; /* on 386i 4.0.1 C compiler -- it just hangs */ 556#endif 557 uintmax_t uval; 558 int sgn; 559 int base = 0; 560 char cpbuf[30]; /* if we have numbers bigger than 30 */ 561 char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */ 562 char *cp; 563 const char *fill; 564 double tmpval; 565 char signchar = FALSE; 566 size_t len; 567 int zero_flag = FALSE; 568 static const char sp[] = " "; 569 static const char zero_string[] = "0"; 570 static const char lchbuf[] = "0123456789abcdef"; 571 static const char Uchbuf[] = "0123456789ABCDEF"; 572 573#define INITIAL_OUT_SIZE 512 574 emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree"); 575 obufout = obuf; 576 osiz = INITIAL_OUT_SIZE; 577 ofre = osiz - 1; 578 579 /* 580 * Icky problem. If the args make a nested call to printf/sprintf, 581 * we end up clobbering the static variable `the_args'. Not good. 582 * We don't just malloc and free the_args each time, since most of the 583 * time there aren't nested calls. But if this is a nested call, 584 * save the memory pointed to by the_args and allocate a fresh 585 * array. Then free it on end. 586 */ 587 if (++call_level > 1) { /* nested */ 588 save_args = the_args; 589 save_args_size = args_size; 590 591 args_size = 0; /* force fresh allocation */ 592 } 593 594 if (args_size == 0) { 595 /* allocate array */ 596 emalloc(the_args, NODE **, (num_args+1) * sizeof(NODE *), "format_tree"); 597 args_size = num_args + 1; 598 } else if (num_args + 1 > args_size) { 599 /* grow it */ 600 erealloc(the_args, NODE **, (num_args+1) * sizeof(NODE *), "format_tree"); 601 args_size = num_args + 1; 602 } 603 604 605 /* fill it in */ 606 /* 607 * We ignore the_args[0] since format strings use 608 * 1-based numbers to indicate the arguments. It's 609 * easiest to just convert to int and index, without 610 * having to remember to subtract 1. 611 */ 612 memset(the_args, '\0', num_args * sizeof(NODE *)); 613 for (i = 1; carg != NULL; i++, carg = carg->rnode) { 614 NODE *tmp; 615 616 /* Here lies the wumpus's other brother. R.I.P. */ 617 tmp = tree_eval(carg->lnode); 618 the_args[i] = dupnode(tmp); 619 free_temp(tmp); 620 } 621 assert(i == num_args); 622 cur_arg = 1; 623 624 /* 625 * Check first for use of `count$'. 626 * If plain argument retrieval was used earlier, choke. 627 * Otherwise, return the requested argument. 628 * If not `count$' now, but it was used earlier, choke. 629 * If this format is more than total number of args, choke. 630 * Otherwise, return the current argument. 631 */ 632#define parse_next_arg() { \ 633 if (argnum > 0) { \ 634 if (cur_arg > 1) \ 635 fatal(_("must use `count$' on all formats or none")); \ 636 arg = the_args[argnum]; \ 637 } else if (used_dollar) { \ 638 fatal(_("must use `count$' on all formats or none")); \ 639 arg = 0; /* shutup the compiler */ \ 640 } else if (cur_arg >= num_args) { \ 641 arg = 0; /* shutup the compiler */ \ 642 toofew = TRUE; \ 643 break; \ 644 } else { \ 645 arg = the_args[cur_arg]; \ 646 cur_arg++; \ 647 } \ 648} 649 650 need_format = FALSE; 651 used_dollar = FALSE; 652 653 s0 = s1 = fmt_string; 654 while (n0-- > 0) { 655 if (*s1 != '%') { 656 s1++; 657 continue; 658 } 659 need_format = TRUE; 660 bchunk(s0, s1 - s0); 661 s0 = s1; 662 cur = &fw; 663 fw = 0; 664 prec = 0; 665 argnum = 0; 666 have_prec = FALSE; 667 signchar = FALSE; 668 zero_flag = FALSE; 669 lj = alt = big = bigbig = small = FALSE; 670 fill = sp; 671 cp = cend; 672 chbuf = lchbuf; 673 s1++; 674 675retry: 676 if (n0-- == 0) /* ran out early! */ 677 break; 678 679 switch (cs1 = *s1++) { 680 case (-1): /* dummy case to allow for checking */ 681check_pos: 682 if (cur != &fw) 683 break; /* reject as a valid format */ 684 goto retry; 685 case '%': 686 need_format = FALSE; 687 /* 688 * 29 Oct. 2002: 689 * The C99 standard pages 274 and 279 seem to imply that 690 * since there's no arg converted, the field width doesn't 691 * apply. The code already was that way, but this 692 * comment documents it, at least in the code. 693 */ 694 bchunk_one("%"); 695 s0 = s1; 696 break; 697 698 case '0': 699 /* 700 * Only turn on zero_flag if we haven't seen 701 * the field width or precision yet. Otherwise, 702 * screws up floating point formatting. 703 */ 704 if (cur == & fw) 705 zero_flag = TRUE; 706 if (lj) 707 goto retry; 708 /* FALL through */ 709 case '1': 710 case '2': 711 case '3': 712 case '4': 713 case '5': 714 case '6': 715 case '7': 716 case '8': 717 case '9': 718 if (cur == NULL) 719 break; 720 if (prec >= 0) 721 *cur = cs1 - '0'; 722 /* 723 * with a negative precision *cur is already set 724 * to -1, so it will remain negative, but we have 725 * to "eat" precision digits in any case 726 */ 727 while (n0 > 0 && *s1 >= '0' && *s1 <= '9') { 728 --n0; 729 *cur = *cur * 10 + *s1++ - '0'; 730 } 731 if (prec < 0) /* negative precision is discarded */ 732 have_prec = FALSE; 733 if (cur == &prec) 734 cur = NULL; 735 if (n0 == 0) /* badly formatted control string */ 736 continue; 737 goto retry; 738 case '$': 739 if (do_traditional) 740 fatal(_("`$' is not permitted in awk formats")); 741 if (cur == &fw) { 742 argnum = fw; 743 fw = 0; 744 used_dollar = TRUE; 745 if (argnum <= 0) 746 fatal(_("arg count with `$' must be > 0")); 747 if (argnum >= num_args) 748 fatal(_("arg count %ld greater than total number of supplied arguments"), argnum); 749 } else 750 fatal(_("`$' not permitted after period in format")); 751 goto retry; 752 case '*': 753 if (cur == NULL) 754 break; 755 if (! do_traditional && ISDIGIT(*s1)) { 756 int val = 0; 757 758 for (; n0 > 0 && *s1 && ISDIGIT(*s1); s1++, n0--) { 759 val *= 10; 760 val += *s1 - '0'; 761 } 762 if (*s1 != '$') { 763 fatal(_("no `$' supplied for positional field width or precision")); 764 } else { 765 s1++; 766 n0--; 767 } 768 769 arg = the_args[val]; 770 } else { 771 parse_next_arg(); 772 } 773 *cur = force_number(arg); 774 if (*cur < 0 && cur == &fw) { 775 *cur = -*cur; 776 lj++; 777 } 778 if (cur == &prec) { 779 if (*cur >= 0) 780 have_prec = TRUE; 781 else 782 have_prec = FALSE; 783 cur = NULL; 784 } 785 goto retry; 786 case ' ': /* print ' ' or '-' */ 787 /* 'space' flag is ignored */ 788 /* if '+' already present */ 789 if (signchar != FALSE) 790 goto check_pos; 791 /* FALL THROUGH */ 792 case '+': /* print '+' or '-' */ 793 signchar = cs1; 794 goto check_pos; 795 case '-': 796 if (prec < 0) 797 break; 798 if (cur == &prec) { 799 prec = -1; 800 goto retry; 801 } 802 fill = sp; /* if left justified then other */ 803 lj++; /* filling is ignored */ 804 goto check_pos; 805 case '.': 806 if (cur != &fw) 807 break; 808 cur = ≺ 809 have_prec = TRUE; 810 goto retry; 811 case '#': 812 alt = TRUE; 813 goto check_pos; 814 case 'l': 815 if (big) 816 break; 817 else { 818 static int warned = FALSE; 819 820 if (do_lint && ! warned) { 821 lintwarn(_("`l' is meaningless in awk formats; ignored")); 822 warned = TRUE; 823 } 824 if (do_posix) 825 fatal(_("`l' is not permitted in POSIX awk formats")); 826 } 827 big = TRUE; 828 goto retry; 829 case 'L': 830 if (bigbig) 831 break; 832 else { 833 static int warned = FALSE; 834 835 if (do_lint && ! warned) { 836 lintwarn(_("`L' is meaningless in awk formats; ignored")); 837 warned = TRUE; 838 } 839 if (do_posix) 840 fatal(_("`L' is not permitted in POSIX awk formats")); 841 } 842 bigbig = TRUE; 843 goto retry; 844 case 'h': 845 if (small) 846 break; 847 else { 848 static int warned = FALSE; 849 850 if (do_lint && ! warned) { 851 lintwarn(_("`h' is meaningless in awk formats; ignored")); 852 warned = TRUE; 853 } 854 if (do_posix) 855 fatal(_("`h' is not permitted in POSIX awk formats")); 856 } 857 small = TRUE; 858 goto retry; 859 case 'c': 860 need_format = FALSE; 861 if (zero_flag && ! lj) 862 fill = zero_string; 863 parse_next_arg(); 864 /* user input that looks numeric is numeric */ 865 if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM) 866 (void) force_number(arg); 867 if (arg->flags & NUMBER) { 868#ifdef sun386 869 tmp_uval = arg->numbr; 870 uval = (unsigned long) tmp_uval; 871#else 872 uval = (uintmax_t) arg->numbr; 873#endif 874 cpbuf[0] = uval; 875 prec = 1; 876 cp = cpbuf; 877 goto pr_tail; 878 } 879 /* 880 * As per POSIX, only output first character of a 881 * string value. Thus, we ignore any provided 882 * precision, forcing it to 1. (Didn't this 883 * used to work? 6/2003.) 884 */ 885 prec = 1; 886 cp = arg->stptr; 887 goto pr_tail; 888 case 's': 889 need_format = FALSE; 890 if (zero_flag && ! lj) 891 fill = zero_string; 892 parse_next_arg(); 893 arg = force_string(arg); 894 if (! have_prec || prec > arg->stlen) 895 prec = arg->stlen; 896 cp = arg->stptr; 897 goto pr_tail; 898 case 'd': 899 case 'i': 900 need_format = FALSE; 901 parse_next_arg(); 902 tmpval = force_number(arg); 903 904 /* 905 * ``The result of converting a zero value with a 906 * precision of zero is no characters.'' 907 */ 908 if (have_prec && prec == 0 && tmpval == 0) 909 goto pr_tail; 910 911 if (tmpval < 0) { 912 if (tmpval < INTMAX_MIN) 913 goto out_of_range; 914 sgn = TRUE; 915 uval = - (uintmax_t) (intmax_t) tmpval; 916 } else { 917 /* Use !, so that NaNs are out of range. */ 918 if (! (tmpval <= UINTMAX_MAX)) 919 goto out_of_range; 920 sgn = FALSE; 921 uval = (uintmax_t) tmpval; 922 } 923 do { 924 *--cp = (char) ('0' + uval % 10); 925 uval /= 10; 926 } while (uval > 0); 927 928 /* add more output digits to match the precision */ 929 if (have_prec) { 930 while (cend - cp < prec) 931 *--cp = '0'; 932 } 933 934 if (sgn) 935 *--cp = '-'; 936 else if (signchar) 937 *--cp = signchar; 938 /* 939 * When to fill with zeroes is of course not simple. 940 * First: No zero fill if left-justifying. 941 * Next: There seem to be two cases: 942 * A '0' without a precision, e.g. %06d 943 * A precision with no field width, e.g. %.10d 944 * Any other case, we don't want to fill with zeroes. 945 */ 946 if (! lj 947 && ((zero_flag && ! have_prec) 948 || (fw == 0 && have_prec))) 949 fill = zero_string; 950 if (prec > fw) 951 fw = prec; 952 prec = cend - cp; 953 if (fw > prec && ! lj && fill != sp 954 && (*cp == '-' || signchar)) { 955 bchunk_one(cp); 956 cp++; 957 prec--; 958 fw--; 959 } 960 goto pr_tail; 961 case 'X': 962 chbuf = Uchbuf; /* FALL THROUGH */ 963 case 'x': 964 base += 6; /* FALL THROUGH */ 965 case 'u': 966 base += 2; /* FALL THROUGH */ 967 case 'o': 968 base += 8; 969 need_format = FALSE; 970 parse_next_arg(); 971 tmpval = force_number(arg); 972 973 /* 974 * ``The result of converting a zero value with a 975 * precision of zero is no characters.'' 976 * 977 * If I remember the ANSI C standard, though, 978 * it says that for octal conversions 979 * the precision is artificially increased 980 * to add an extra 0 if # is supplied. 981 * Indeed, in C, 982 * printf("%#.0o\n", 0); 983 * prints a single 0. 984 */ 985 if (! alt && have_prec && prec == 0 && tmpval == 0) 986 goto pr_tail; 987 988 if (tmpval < 0) { 989 if (tmpval < INTMAX_MIN) 990 goto out_of_range; 991 uval = (uintmax_t) (intmax_t) tmpval; 992 } else { 993 /* Use !, so that NaNs are out of range. */ 994 if (! (tmpval <= UINTMAX_MAX)) 995 goto out_of_range; 996 uval = (uintmax_t) tmpval; 997 } 998 /* 999 * When to fill with zeroes is of course not simple. 1000 * First: No zero fill if left-justifying. 1001 * Next: There seem to be two cases: 1002 * A '0' without a precision, e.g. %06d 1003 * A precision with no field width, e.g. %.10d 1004 * Any other case, we don't want to fill with zeroes. 1005 */ 1006 if (! lj 1007 && ((zero_flag && ! have_prec) 1008 || (fw == 0 && have_prec))) 1009 fill = zero_string; 1010 do { 1011 *--cp = chbuf[uval % base]; 1012 uval /= base; 1013 } while (uval > 0); 1014 1015 /* add more output digits to match the precision */ 1016 if (have_prec) { 1017 while (cend - cp < prec) 1018 *--cp = '0'; 1019 } 1020 1021 if (alt && tmpval != 0) { 1022 if (base == 16) { 1023 *--cp = cs1; 1024 *--cp = '0'; 1025 if (fill != sp) { 1026 bchunk(cp, 2); 1027 cp += 2; 1028 fw -= 2; 1029 } 1030 } else if (base == 8) 1031 *--cp = '0'; 1032 } 1033 base = 0; 1034 if (prec > fw) 1035 fw = prec; 1036 prec = cend - cp; 1037 pr_tail: 1038 if (! lj) { 1039 while (fw > prec) { 1040 bchunk_one(fill); 1041 fw--; 1042 } 1043 } 1044 bchunk(cp, (int) prec); 1045 while (fw > prec) { 1046 bchunk_one(fill); 1047 fw--; 1048 } 1049 s0 = s1; 1050 break; 1051 1052 out_of_range: 1053 /* out of range - emergency use of %g format */ 1054 if (do_lint) 1055 lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"), 1056 tmpval, cs1); 1057 cs1 = 'g'; 1058 goto format_float; 1059 1060 case 'g': 1061 case 'G': 1062 case 'e': 1063 case 'f': 1064 case 'E': 1065 need_format = FALSE; 1066 parse_next_arg(); 1067 tmpval = force_number(arg); 1068 format_float: 1069 if (! have_prec) 1070 prec = DEFAULT_G_PRECISION; 1071 chksize(fw + prec + 9); /* 9 == slop */ 1072 1073 cp = cpbuf; 1074 *cp++ = '%'; 1075 if (lj) 1076 *cp++ = '-'; 1077 if (signchar) 1078 *cp++ = signchar; 1079 if (alt) 1080 *cp++ = '#'; 1081 if (zero_flag) 1082 *cp++ = '0'; 1083 strcpy(cp, "*.*"); 1084 cp += 3; 1085 *cp++ = cs1; 1086 *cp = '\0'; 1087#ifndef GFMT_WORKAROUND 1088 (void) sprintf(obufout, cpbuf, 1089 (int) fw, (int) prec, (double) tmpval); 1090#else /* GFMT_WORKAROUND */ 1091 if (cs1 == 'g' || cs1 == 'G') 1092 sgfmt(obufout, cpbuf, (int) alt, 1093 (int) fw, (int) prec, (double) tmpval); 1094 else 1095 (void) sprintf(obufout, cpbuf, 1096 (int) fw, (int) prec, (double) tmpval); 1097#endif /* GFMT_WORKAROUND */ 1098 len = strlen(obufout); 1099 ofre -= len; 1100 obufout += len; 1101 s0 = s1; 1102 break; 1103 default: 1104 break; 1105 } 1106 if (toofew) 1107 fatal("%s\n\t`%s'\n\t%*s%s", 1108 _("not enough arguments to satisfy format string"), 1109 fmt_string, (int) (s1 - fmt_string - 1), "", 1110 _("^ ran out for this one")); 1111 } 1112 if (do_lint) { 1113 if (need_format) 1114 lintwarn( 1115 _("[s]printf: format specifier does not have control letter")); 1116 if (cur_arg < num_args) 1117 lintwarn( 1118 _("too many arguments supplied for format string")); 1119 } 1120 bchunk(s0, s1 - s0); 1121 r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED); 1122 r->flags |= TEMP; 1123 1124 for (i = 1; i < num_args; i++) { 1125 unref(the_args[i]); 1126 } 1127 1128 if (call_level-- > 1) { 1129 free(the_args); 1130 the_args = save_args; 1131 args_size = save_args_size; 1132 } 1133 1134 return r; 1135} 1136 1137/* do_sprintf --- perform sprintf */ 1138 1139NODE * 1140do_sprintf(NODE *tree) 1141{ 1142 NODE *r; 1143 NODE *sfmt = force_string(tree_eval(tree->lnode)); 1144 1145 r = format_tree(sfmt->stptr, sfmt->stlen, tree->rnode, tree->printf_count); 1146 free_temp(sfmt); 1147 return r; 1148} 1149 1150/* 1151 * redirect_to_fp --- return fp for redirection, NULL on failure 1152 * or stdout if no redirection, used by all print routines 1153 */ 1154 1155static inline FILE * 1156redirect_to_fp(NODE *tree, struct redirect **rpp) 1157{ 1158 int errflg; /* not used, sigh */ 1159 struct redirect *rp; 1160 1161 if (tree == NULL) 1162 return stdout; 1163 1164 rp = redirect(tree, &errflg); 1165 if (rp != NULL) { 1166 *rpp = rp; 1167 return rp->fp; 1168 } 1169 1170 return NULL; 1171} 1172 1173/* do_printf --- perform printf, including redirection */ 1174 1175void 1176do_printf(NODE *tree) 1177{ 1178 struct redirect *rp = NULL; 1179 register FILE *fp; 1180 1181 if (tree->lnode == NULL) { 1182 if (do_traditional) { 1183 if (do_lint) 1184 lintwarn(_("printf: no arguments")); 1185 return; /* bwk accepts it silently */ 1186 } 1187 fatal(_("printf: no arguments")); 1188 } 1189 1190 fp = redirect_to_fp(tree->rnode, & rp); 1191 if (fp == NULL) 1192 return; 1193 tree->lnode->printf_count = tree->printf_count; 1194 tree = do_sprintf(tree->lnode); 1195 efwrite(tree->stptr, sizeof(char), tree->stlen, fp, "printf", rp, TRUE); 1196 if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) 1197 fflush(rp->fp); 1198 free_temp(tree); 1199} 1200 1201/* do_sqrt --- do the sqrt function */ 1202 1203NODE * 1204do_sqrt(NODE *tree) 1205{ 1206 NODE *tmp; 1207 double arg; 1208 1209 tmp = tree_eval(tree->lnode); 1210 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 1211 lintwarn(_("sqrt: received non-numeric argument")); 1212 arg = (double) force_number(tmp); 1213 free_temp(tmp); 1214 if (arg < 0.0) 1215 warning(_("sqrt: called with negative argument %g"), arg); 1216 return tmp_number((AWKNUM) sqrt(arg)); 1217} 1218 1219/* do_substr --- do the substr function */ 1220 1221NODE * 1222do_substr(NODE *tree) 1223{ 1224 NODE *t1, *t2, *t3; 1225 NODE *r; 1226 register size_t indx; 1227 size_t length; 1228 double d_index, d_length; 1229 1230 t1 = force_string(tree_eval(tree->lnode)); 1231 t2 = tree_eval(tree->rnode->lnode); 1232 d_index = force_number(t2); 1233 free_temp(t2); 1234 1235 /* the weird `! (foo)' tests help catch NaN values. */ 1236 if (! (d_index >= 1)) { 1237 if (do_lint) 1238 lintwarn(_("substr: start index %g is invalid, using 1"), 1239 d_index); 1240 d_index = 1; 1241 } 1242 if (do_lint && double_to_int(d_index) != d_index) 1243 lintwarn(_("substr: non-integer start index %g will be truncated"), 1244 d_index); 1245 1246 /* awk indices are from 1, C's are from 0 */ 1247 if (d_index <= SIZE_MAX) 1248 indx = d_index - 1; 1249 else 1250 indx = SIZE_MAX; 1251 1252 if (tree->rnode->rnode == NULL) { /* third arg. missing */ 1253 /* use remainder of string */ 1254 length = t1->stlen - indx; 1255 d_length = length; /* set here in case used in diagnostics, below */ 1256 } else { 1257 t3 = tree_eval(tree->rnode->rnode->lnode); 1258 d_length = force_number(t3); 1259 free_temp(t3); 1260 if (! (d_length >= 1)) { 1261 if (do_lint == LINT_ALL) 1262 lintwarn(_("substr: length %g is not >= 1"), d_length); 1263 else if (do_lint == LINT_INVALID && ! (d_length >= 0)) 1264 lintwarn(_("substr: length %g is not >= 0"), d_length); 1265 free_temp(t1); 1266 return Nnull_string; 1267 } 1268 if (do_lint) { 1269 if (double_to_int(d_length) != d_length) 1270 lintwarn( 1271 _("substr: non-integer length %g will be truncated"), 1272 d_length); 1273 1274 if (d_length > SIZE_MAX) 1275 lintwarn( 1276 _("substr: length %g too big for string indexing, truncating to %g"), 1277 d_length, (double) SIZE_MAX); 1278 } 1279 if (d_length < SIZE_MAX) 1280 length = d_length; 1281 else 1282 length = SIZE_MAX; 1283 } 1284 1285 if (t1->stlen == 0) { 1286 /* substr("", 1, 0) produces a warning only if LINT_ALL */ 1287 if (do_lint && (do_lint == LINT_ALL || ((indx | length) != 0))) 1288 lintwarn(_("substr: source string is zero length")); 1289 free_temp(t1); 1290 return Nnull_string; 1291 } 1292 if (indx >= t1->stlen) { 1293 if (do_lint) 1294 lintwarn(_("substr: start index %g is past end of string"), 1295 d_index); 1296 free_temp(t1); 1297 return Nnull_string; 1298 } 1299 if (length > t1->stlen - indx) { 1300 if (do_lint) 1301 lintwarn( 1302 _("substr: length %g at start index %g exceeds length of first argument (%lu)"), 1303 d_length, d_index, (unsigned long int) t1->stlen); 1304 length = t1->stlen - indx; 1305 } 1306 r = tmp_string(t1->stptr + indx, length); 1307 free_temp(t1); 1308 return r; 1309} 1310 1311/* do_strftime --- format a time stamp */ 1312 1313NODE * 1314do_strftime(NODE *tree) 1315{ 1316 NODE *t1, *t2, *ret; 1317 struct tm *tm; 1318 time_t fclock; 1319 char *bufp; 1320 size_t buflen, bufsize; 1321 char buf[BUFSIZ]; 1322 /* FIXME: One day make %d be %e, after C 99 is common. */ 1323 static const char def_format[] = "%a %b %d %H:%M:%S %Z %Y"; 1324 const char *format; 1325 int formatlen; 1326 1327 /* set defaults first */ 1328 format = def_format; /* traditional date format */ 1329 formatlen = strlen(format); 1330 (void) time(&fclock); /* current time of day */ 1331 1332 t1 = t2 = NULL; 1333 if (tree != NULL) { /* have args */ 1334 if (tree->lnode != NULL) { 1335 NODE *tmp = tree_eval(tree->lnode); 1336 if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) 1337 lintwarn(_("strftime: received non-string first argument")); 1338 t1 = force_string(tmp); 1339 format = t1->stptr; 1340 formatlen = t1->stlen; 1341 if (formatlen == 0) { 1342 if (do_lint) 1343 lintwarn(_("strftime: received empty format string")); 1344 free_temp(t1); 1345 return tmp_string("", 0); 1346 } 1347 } 1348 1349 if (tree->rnode != NULL) { 1350 t2 = tree_eval(tree->rnode->lnode); 1351 if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0) 1352 lintwarn(_("strftime: received non-numeric second argument")); 1353 fclock = (time_t) force_number(t2); 1354 free_temp(t2); 1355 } 1356 } 1357 1358 tm = localtime(&fclock); 1359 1360 bufp = buf; 1361 bufsize = sizeof(buf); 1362 for (;;) { 1363 *bufp = '\0'; 1364 buflen = strftime(bufp, bufsize, format, tm); 1365 /* 1366 * buflen can be zero EITHER because there's not enough 1367 * room in the string, or because the control command 1368 * goes to the empty string. Make a reasonable guess that 1369 * if the buffer is 1024 times bigger than the length of the 1370 * format string, it's not failing for lack of room. 1371 * Thanks to Paul Eggert for pointing out this issue. 1372 */ 1373 if (buflen > 0 || bufsize >= 1024 * formatlen) 1374 break; 1375 bufsize *= 2; 1376 if (bufp == buf) 1377 emalloc(bufp, char *, bufsize, "do_strftime"); 1378 else 1379 erealloc(bufp, char *, bufsize, "do_strftime"); 1380 } 1381 ret = tmp_string(bufp, buflen); 1382 if (bufp != buf) 1383 free(bufp); 1384 if (t1) 1385 free_temp(t1); 1386 return ret; 1387} 1388 1389/* do_systime --- get the time of day */ 1390 1391NODE * 1392do_systime(NODE *tree ATTRIBUTE_UNUSED) 1393{ 1394 time_t lclock; 1395 1396 (void) time(&lclock); 1397 return tmp_number((AWKNUM) lclock); 1398} 1399 1400/* do_mktime --- turn a time string into a timestamp */ 1401 1402NODE * 1403do_mktime(NODE *tree) 1404{ 1405 NODE *t1; 1406 struct tm then; 1407 long year; 1408 int month, day, hour, minute, second, count; 1409 int dst = -1; /* default is unknown */ 1410 time_t then_stamp; 1411 char save; 1412 1413 t1 = tree_eval(tree->lnode); 1414 if (do_lint && (t1->flags & (STRING|STRCUR)) == 0) 1415 lintwarn(_("mktime: received non-string argument")); 1416 t1 = force_string(t1); 1417 1418 save = t1->stptr[t1->stlen]; 1419 t1->stptr[t1->stlen] = '\0'; 1420 1421 count = sscanf(t1->stptr, "%ld %d %d %d %d %d %d", 1422 & year, & month, & day, 1423 & hour, & minute, & second, 1424 & dst); 1425 1426 t1->stptr[t1->stlen] = save; 1427 free_temp(t1); 1428 1429 if (count < 6 1430 || month < month - 1 1431 || year < year - 1900 || year - 1900 != (int) (year - 1900)) 1432 return tmp_number((AWKNUM) -1); 1433 1434 memset(& then, '\0', sizeof(then)); 1435 then.tm_sec = second; 1436 then.tm_min = minute; 1437 then.tm_hour = hour; 1438 then.tm_mday = day; 1439 then.tm_mon = month - 1; 1440 then.tm_year = year - 1900; 1441 then.tm_isdst = dst; 1442 1443 then_stamp = mktime(& then); 1444 return tmp_number((AWKNUM) then_stamp); 1445} 1446 1447/* do_system --- run an external command */ 1448 1449NODE * 1450do_system(NODE *tree) 1451{ 1452 NODE *tmp; 1453 int ret = 0; 1454 char *cmd; 1455 char save; 1456 1457 (void) flush_io(); /* so output is synchronous with gawk's */ 1458 tmp = tree_eval(tree->lnode); 1459 if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0) 1460 lintwarn(_("system: received non-string argument")); 1461 cmd = force_string(tmp)->stptr; 1462 1463 if (cmd && *cmd) { 1464 /* insure arg to system is zero-terminated */ 1465 1466 /* 1467 * From: David Trueman <david@cs.dal.ca> 1468 * To: arnold@cc.gatech.edu (Arnold Robbins) 1469 * Date: Wed, 3 Nov 1993 12:49:41 -0400 1470 * 1471 * It may not be necessary to save the character, but 1472 * I'm not sure. It would normally be the field 1473 * separator. If the parse has not yet gone beyond 1474 * that, it could mess up (although I doubt it). If 1475 * FIELDWIDTHS is being used, it might be the first 1476 * character of the next field. Unless someone wants 1477 * to check it out exhaustively, I suggest saving it 1478 * for now... 1479 */ 1480 save = cmd[tmp->stlen]; 1481 cmd[tmp->stlen] = '\0'; 1482 1483 os_restore_mode(fileno(stdin)); 1484 ret = system(cmd); 1485 if (ret != -1) 1486 ret = WEXITSTATUS(ret); 1487#ifdef O_BINARY 1488 if ((BINMODE & 1) != 0) 1489 os_setbinmode(fileno(stdin), O_BINARY); 1490#endif 1491 cmd[tmp->stlen] = save; 1492 } 1493 free_temp(tmp); 1494 return tmp_number((AWKNUM) ret); 1495} 1496 1497extern NODE **fmt_list; /* declared in eval.c */ 1498 1499/* do_print --- print items, separated by OFS, terminated with ORS */ 1500 1501void 1502do_print(register NODE *tree) 1503{ 1504 register NODE **t; 1505 struct redirect *rp = NULL; 1506 register FILE *fp; 1507 int numnodes, i; 1508 NODE *save; 1509 NODE *tval; 1510 1511 fp = redirect_to_fp(tree->rnode, & rp); 1512 if (fp == NULL) 1513 return; 1514 1515 /* 1516 * General idea is to evaluate all the expressions first and 1517 * then print them, otherwise you get suprising behavior. 1518 * See test/prtoeval.awk for an example program. 1519 */ 1520 save = tree = tree->lnode; 1521 for (numnodes = 0; tree != NULL; tree = tree->rnode) 1522 numnodes++; 1523 emalloc(t, NODE **, numnodes * sizeof(NODE *), "do_print"); 1524 1525 tree = save; 1526 for (i = 0; tree != NULL; i++, tree = tree->rnode) { 1527 NODE *n; 1528 1529 /* Here lies the wumpus. R.I.P. */ 1530 n = tree_eval(tree->lnode); 1531 t[i] = dupnode(n); 1532 free_temp(n); 1533 1534 if ((t[i]->flags & (NUMBER|STRING)) == NUMBER) { 1535 if (OFMTidx == CONVFMTidx) 1536 (void) force_string(t[i]); 1537 else { 1538 tval = tmp_number(t[i]->numbr); 1539 unref(t[i]); 1540 t[i] = format_val(OFMT, OFMTidx, tval); 1541 } 1542 } 1543 } 1544 1545 for (i = 0; i < numnodes; i++) { 1546 efwrite(t[i]->stptr, sizeof(char), t[i]->stlen, fp, "print", rp, FALSE); 1547 unref(t[i]); 1548 1549 if (i != numnodes - 1 && OFSlen > 0) 1550 efwrite(OFS, sizeof(char), (size_t) OFSlen, 1551 fp, "print", rp, FALSE); 1552 1553 } 1554 if (ORSlen > 0) 1555 efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, TRUE); 1556 1557 if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) 1558 fflush(rp->fp); 1559 1560 free(t); 1561} 1562 1563/* do_print_rec --- special case printing of $0, for speed */ 1564 1565void 1566do_print_rec(register NODE *tree) 1567{ 1568 struct redirect *rp = NULL; 1569 register FILE *fp; 1570 register NODE *f0; 1571 1572 fp = redirect_to_fp(tree->rnode, & rp); 1573 if (fp == NULL) 1574 return; 1575 1576 if (! field0_valid) 1577 (void) get_field(0L, NULL); /* rebuild record */ 1578 1579 f0 = fields_arr[0]; 1580 1581 if (do_lint && f0 == Nnull_string) 1582 lintwarn(_("reference to uninitialized field `$%d'"), 0); 1583 1584 efwrite(f0->stptr, sizeof(char), f0->stlen, fp, "print", rp, FALSE); 1585 1586 if (ORSlen > 0) 1587 efwrite(ORS, sizeof(char), (size_t) ORSlen, fp, "print", rp, TRUE); 1588 1589 if (rp != NULL && (rp->flag & RED_TWOWAY) != 0) 1590 fflush(rp->fp); 1591} 1592 1593/* do_tolower --- lower case a string */ 1594 1595NODE * 1596do_tolower(NODE *tree) 1597{ 1598 NODE *t1, *t2; 1599 register unsigned char *cp, *cp2; 1600#ifdef MBS_SUPPORT 1601 size_t mbclen = 0; 1602 mbstate_t mbs, prev_mbs; 1603 if (gawk_mb_cur_max > 1) 1604 memset(&mbs, 0, sizeof(mbstate_t)); 1605#endif 1606 1607 t1 = tree_eval(tree->lnode); 1608 if (do_lint && (t1->flags & (STRING|STRCUR)) == 0) 1609 lintwarn(_("tolower: received non-string argument")); 1610 t1 = force_string(t1); 1611 t2 = tmp_string(t1->stptr, t1->stlen); 1612 for (cp = (unsigned char *)t2->stptr, 1613 cp2 = (unsigned char *)(t2->stptr + t2->stlen); cp < cp2; cp++) 1614#ifdef MBS_SUPPORT 1615 if (gawk_mb_cur_max > 1) { 1616 wchar_t wc; 1617 prev_mbs = mbs; 1618 mbclen = (size_t) mbrtowc(&wc, (char *) cp, cp2 - cp, 1619 &mbs); 1620 if ((mbclen != 1) && (mbclen != (size_t) -1) && 1621 (mbclen != (size_t) -2) && (mbclen != 0)) { 1622 /* a multibyte character. */ 1623 if (iswupper(wc)) { 1624 wc = towlower(wc); 1625 wcrtomb((char *) cp, wc, &prev_mbs); 1626 } 1627 /* Adjust the pointer. */ 1628 cp += mbclen - 1; 1629 } else { 1630 /* Otherwise we treat it as a singlebyte character. */ 1631 if (ISUPPER(*cp)) 1632 *cp = tolower(*cp); 1633 } 1634 } else 1635#endif 1636 if (ISUPPER(*cp)) 1637 *cp = TOLOWER(*cp); 1638 free_temp(t1); 1639 return t2; 1640} 1641 1642/* do_toupper --- upper case a string */ 1643 1644NODE * 1645do_toupper(NODE *tree) 1646{ 1647 NODE *t1, *t2; 1648 register unsigned char *cp, *cp2; 1649#ifdef MBS_SUPPORT 1650 size_t mbclen = 0; 1651 mbstate_t mbs, prev_mbs; 1652 if (gawk_mb_cur_max > 1) 1653 memset(&mbs, 0, sizeof(mbstate_t)); 1654#endif 1655 1656 t1 = tree_eval(tree->lnode); 1657 if (do_lint && (t1->flags & (STRING|STRCUR)) == 0) 1658 lintwarn(_("toupper: received non-string argument")); 1659 t1 = force_string(t1); 1660 t2 = tmp_string(t1->stptr, t1->stlen); 1661 for (cp = (unsigned char *)t2->stptr, 1662 cp2 = (unsigned char *)(t2->stptr + t2->stlen); cp < cp2; cp++) 1663#ifdef MBS_SUPPORT 1664 if (gawk_mb_cur_max > 1) { 1665 wchar_t wc; 1666 prev_mbs = mbs; 1667 mbclen = (size_t) mbrtowc(&wc, (char *) cp, cp2 - cp, 1668 &mbs); 1669 if ((mbclen != 1) && (mbclen != (size_t) -1) && 1670 (mbclen != (size_t) -2) && (mbclen != 0)) { 1671 /* a multibyte character. */ 1672 if (iswlower(wc)) { 1673 wc = towupper(wc); 1674 wcrtomb((char *) cp, wc, &prev_mbs); 1675 } 1676 /* Adjust the pointer. */ 1677 cp += mbclen - 1; 1678 } else { 1679 /* Otherwise we treat it as a singlebyte character. */ 1680 if (ISLOWER(*cp)) 1681 *cp = toupper(*cp); 1682 } 1683 } else 1684#endif 1685 if (ISLOWER(*cp)) 1686 *cp = TOUPPER(*cp); 1687 free_temp(t1); 1688 return t2; 1689} 1690 1691/* do_atan2 --- do the atan2 function */ 1692 1693NODE * 1694do_atan2(NODE *tree) 1695{ 1696 NODE *t1, *t2; 1697 double d1, d2; 1698 1699 t1 = tree_eval(tree->lnode); 1700 t2 = tree_eval(tree->rnode->lnode); 1701 if (do_lint) { 1702 if ((t1->flags & (NUMCUR|NUMBER)) == 0) 1703 lintwarn(_("atan2: received non-numeric first argument")); 1704 if ((t2->flags & (NUMCUR|NUMBER)) == 0) 1705 lintwarn(_("atan2: received non-numeric second argument")); 1706 } 1707 d1 = force_number(t1); 1708 d2 = force_number(t2); 1709 free_temp(t1); 1710 free_temp(t2); 1711 return tmp_number((AWKNUM) atan2(d1, d2)); 1712} 1713 1714/* do_sin --- do the sin function */ 1715 1716NODE * 1717do_sin(NODE *tree) 1718{ 1719 NODE *tmp; 1720 double d; 1721 1722 tmp = tree_eval(tree->lnode); 1723 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 1724 lintwarn(_("sin: received non-numeric argument")); 1725 d = sin((double) force_number(tmp)); 1726 free_temp(tmp); 1727 return tmp_number((AWKNUM) d); 1728} 1729 1730/* do_cos --- do the cos function */ 1731 1732NODE * 1733do_cos(NODE *tree) 1734{ 1735 NODE *tmp; 1736 double d; 1737 1738 tmp = tree_eval(tree->lnode); 1739 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 1740 lintwarn(_("cos: received non-numeric argument")); 1741 d = cos((double) force_number(tmp)); 1742 free_temp(tmp); 1743 return tmp_number((AWKNUM) d); 1744} 1745 1746/* do_rand --- do the rand function */ 1747 1748static int firstrand = TRUE; 1749static char state[512]; 1750 1751/* ARGSUSED */ 1752NODE * 1753do_rand(NODE *tree ATTRIBUTE_UNUSED) 1754{ 1755 if (firstrand) { 1756 (void) initstate((unsigned) 1, state, sizeof state); 1757 srandom(1); 1758 firstrand = FALSE; 1759 } 1760 /* 1761 * Per historical practice and POSIX, return value N is 1762 * 1763 * 0 <= n < 1 1764 */ 1765 return tmp_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX); 1766} 1767 1768/* do_srand --- seed the random number generator */ 1769 1770NODE * 1771do_srand(NODE *tree) 1772{ 1773 NODE *tmp; 1774 static long save_seed = 1; 1775 long ret = save_seed; /* SVR4 awk srand returns previous seed */ 1776 1777 if (firstrand) { 1778 (void) initstate((unsigned) 1, state, sizeof state); 1779 /* don't need to srandom(1), we're changing the seed below */ 1780 firstrand = FALSE; 1781 } else 1782 (void) setstate(state); 1783 1784 if (tree == NULL) 1785 srandom((unsigned int) (save_seed = (long) time((time_t *) 0))); 1786 else { 1787 tmp = tree_eval(tree->lnode); 1788 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) 1789 lintwarn(_("srand: received non-numeric argument")); 1790 srandom((unsigned int) (save_seed = (long) force_number(tmp))); 1791 free_temp(tmp); 1792 } 1793 return tmp_number((AWKNUM) ret); 1794} 1795 1796/* do_match --- match a regexp, set RSTART and RLENGTH, 1797 * optional third arg is array filled with text of 1798 * subpatterns enclosed in parens and start and len info. 1799 */ 1800 1801NODE * 1802do_match(NODE *tree) 1803{ 1804 NODE *t1, *dest, *it; 1805 int rstart, len, ii; 1806 AWKNUM rlength; 1807 Regexp *rp; 1808 regoff_t s; 1809 char *start; 1810 char *buf = NULL; 1811 char buff[100]; 1812 size_t amt, oldamt = 0, ilen, slen; 1813 char *subsepstr; 1814 size_t subseplen; 1815 1816 t1 = force_string(tree_eval(tree->lnode)); 1817 tree = tree->rnode; 1818 rp = re_update(tree->lnode); 1819 1820 dest = NULL; 1821 if (tree->rnode != NULL) { /* 3rd optional arg for the subpatterns */ 1822 dest = get_param(tree->rnode->lnode); 1823 if (dest->type != Node_var_array) 1824 fatal(_("match: third argument is not an array")); 1825 1826 assoc_clear(dest); 1827 } 1828 1829 rstart = research(rp, t1->stptr, 0, t1->stlen, TRUE); 1830 if (rstart >= 0) { /* match succeded */ 1831 rstart++; /* 1-based indexing */ 1832 rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr); 1833 1834 /* Build the array only if the caller wants the optional subpatterns */ 1835 if (dest != NULL) { 1836 subsepstr = SUBSEP_node->var_value->stptr; 1837 subseplen = SUBSEP_node->var_value->stlen; 1838 1839 for (ii = 0; ii < NUMSUBPATS(rp, t1->stptr); ii++) { 1840 /* 1841 * Loop over all the subpats; some of them may have 1842 * matched even if all of them did not. 1843 */ 1844 if ((s = SUBPATSTART(rp, t1->stptr, ii)) != -1) { 1845 start = t1->stptr + s; 1846 len = SUBPATEND(rp, t1->stptr, ii) - s; 1847 1848 it = make_string(start, len); 1849 /* 1850 * assoc_lookup() does free_temp() on 2nd arg. 1851 */ 1852 *assoc_lookup(dest, tmp_number((AWKNUM) (ii)), FALSE) = it; 1853 1854 sprintf(buff, "%d", ii); 1855 ilen = strlen(buff); 1856 amt = ilen + subseplen + strlen("length") + 2; 1857 1858 if (oldamt == 0) { 1859 emalloc(buf, char *, amt, "do_match"); 1860 } else if (amt > oldamt) { 1861 erealloc(buf, char *, amt, "do_match"); 1862 } 1863 oldamt = amt; 1864 memcpy(buf, buff, ilen); 1865 memcpy(buf + ilen, subsepstr, subseplen); 1866 memcpy(buf + ilen + subseplen, "start", 6); 1867 1868 slen = ilen + subseplen + 5; 1869 1870 it = make_number((AWKNUM) s + 1); 1871 *assoc_lookup(dest, tmp_string(buf, slen), FALSE) = it; 1872 1873 memcpy(buf, buff, ilen); 1874 memcpy(buf + ilen, subsepstr, subseplen); 1875 memcpy(buf + ilen + subseplen, "length", 7); 1876 1877 slen = ilen + subseplen + 6; 1878 1879 it = make_number((AWKNUM) len); 1880 *assoc_lookup(dest, tmp_string(buf, slen), FALSE) = it; 1881 } 1882 } 1883 1884 free(buf); 1885 } 1886 } else { /* match failed */ 1887 rstart = 0; 1888 rlength = -1.0; 1889 } 1890 free_temp(t1); 1891 unref(RSTART_node->var_value); 1892 RSTART_node->var_value = make_number((AWKNUM) rstart); 1893 unref(RLENGTH_node->var_value); 1894 RLENGTH_node->var_value = make_number(rlength); 1895 return tmp_number((AWKNUM) rstart); 1896} 1897 1898/* sub_common --- the common code (does the work) for sub, gsub, and gensub */ 1899 1900/* 1901 * Gsub can be tricksy; particularly when handling the case of null strings. 1902 * The following awk code was useful in debugging problems. It is too bad 1903 * that it does not readily translate directly into the C code, below. 1904 * 1905 * #! /usr/local/bin/mawk -f 1906 * 1907 * BEGIN { 1908 * TRUE = 1; FALSE = 0 1909 * print "--->", mygsub("abc", "b+", "FOO") 1910 * print "--->", mygsub("abc", "x*", "X") 1911 * print "--->", mygsub("abc", "b*", "X") 1912 * print "--->", mygsub("abc", "c", "X") 1913 * print "--->", mygsub("abc", "c+", "X") 1914 * print "--->", mygsub("abc", "x*$", "X") 1915 * } 1916 * 1917 * function mygsub(str, regex, replace, origstr, newstr, eosflag, nonzeroflag) 1918 * { 1919 * origstr = str; 1920 * eosflag = nonzeroflag = FALSE 1921 * while (match(str, regex)) { 1922 * if (RLENGTH > 0) { # easy case 1923 * nonzeroflag = TRUE 1924 * if (RSTART == 1) { # match at front of string 1925 * newstr = newstr replace 1926 * } else { 1927 * newstr = newstr substr(str, 1, RSTART-1) replace 1928 * } 1929 * str = substr(str, RSTART+RLENGTH) 1930 * } else if (nonzeroflag) { 1931 * # last match was non-zero in length, and at the 1932 * # current character, we get a zero length match, 1933 * # which we don't really want, so skip over it 1934 * newstr = newstr substr(str, 1, 1) 1935 * str = substr(str, 2) 1936 * nonzeroflag = FALSE 1937 * } else { 1938 * # 0-length match 1939 * if (RSTART == 1) { 1940 * newstr = newstr replace substr(str, 1, 1) 1941 * str = substr(str, 2) 1942 * } else { 1943 * return newstr str replace 1944 * } 1945 * } 1946 * if (length(str) == 0) 1947 * if (eosflag) 1948 * break; 1949 * else 1950 * eosflag = TRUE 1951 * } 1952 * if (length(str) > 0) 1953 * newstr = newstr str # rest of string 1954 * 1955 * return newstr 1956 * } 1957 */ 1958 1959/* 1960 * NB: `howmany' conflicts with a SunOS 4.x macro in <sys/param.h>. 1961 */ 1962 1963static NODE * 1964sub_common(NODE *tree, long how_many, int backdigs) 1965{ 1966 register char *scan; 1967 register char *bp, *cp; 1968 char *buf; 1969 size_t buflen; 1970 register char *matchend; 1971 register size_t len; 1972 char *matchstart; 1973 char *text; 1974 size_t textlen; 1975 char *repl; 1976 char *replend; 1977 size_t repllen; 1978 int sofar; 1979 int ampersands; 1980 int matches = 0; 1981 Regexp *rp; 1982 NODE *s; /* subst. pattern */ 1983 NODE *t; /* string to make sub. in; $0 if none given */ 1984 NODE *tmp; 1985 NODE **lhs = &tree; /* value not used -- just different from NULL */ 1986 int priv = FALSE; 1987 Func_ptr after_assign = NULL; 1988 1989 int global = (how_many == -1); 1990 long current; 1991 int lastmatchnonzero; 1992#ifdef MBS_SUPPORT 1993 char *mb_indices; 1994#endif 1995 1996 tmp = tree->lnode; /* regexp */ 1997 rp = re_update(tmp); 1998 1999 tree = tree->rnode; /* replacement text */ 2000 s = tree->lnode; 2001 s = force_string(tree_eval(s)); 2002 2003 tree = tree->rnode; /* original string */ 2004 tmp = tree->lnode; 2005 t = force_string(tree_eval(tmp)); 2006 2007 /* do the search early to avoid work on non-match */ 2008 if (research(rp, t->stptr, 0, t->stlen, TRUE) == -1 || 2009 RESTART(rp, t->stptr) > t->stlen) { 2010 free_temp(t); 2011 free_temp(s); 2012 return tmp_number((AWKNUM) 0.0); 2013 } 2014 2015 if (tmp->type == Node_val) 2016 lhs = NULL; 2017 else 2018 lhs = get_lhs(tmp, &after_assign, FALSE); 2019 t->flags |= STRING; 2020 /* 2021 * create a private copy of the string 2022 */ 2023 if (t->stref > 1 || (t->flags & (PERM|FIELD)) != 0) { 2024 tmp = copynode(t); 2025 t = tmp; 2026 priv = TRUE; 2027 } 2028 text = t->stptr; 2029 textlen = t->stlen; 2030 buflen = textlen + 2; 2031 2032 repl = s->stptr; 2033 replend = repl + s->stlen; 2034 repllen = replend - repl; 2035 emalloc(buf, char *, buflen + 2, "sub_common"); 2036 buf[buflen] = '\0'; 2037 buf[buflen + 1] = '\0'; 2038 ampersands = 0; 2039#ifdef MBS_SUPPORT 2040 /* 2041 * Some systems' malloc() can't handle being called with an 2042 * argument of zero. Thus we have to have some special case 2043 * code to check for `repllen == 0'. This can occur for 2044 * something like: 2045 * sub(/foo/, "", mystring) 2046 * for example. 2047 */ 2048 if (gawk_mb_cur_max > 1 && repllen > 0) { 2049 emalloc(mb_indices, char *, repllen * sizeof(char), "sub_common"); 2050 index_multibyte_buffer(repl, mb_indices, repllen); 2051 } else 2052 mb_indices = NULL; 2053#endif 2054 for (scan = repl; scan < replend; scan++) { 2055#ifdef MBS_SUPPORT 2056 if ((gawk_mb_cur_max == 1 || (repllen > 0 && mb_indices[scan - repl] == 1)) 2057 && (*scan == '&')) { 2058#else 2059 if (*scan == '&') { 2060#endif 2061 repllen--; 2062 ampersands++; 2063 } else if (*scan == '\\') { 2064 if (backdigs) { /* gensub, behave sanely */ 2065 if (ISDIGIT(scan[1])) { 2066 ampersands++; 2067 scan++; 2068 } else { /* \q for any q --> q */ 2069 repllen--; 2070 scan++; 2071 } 2072 } else { /* (proposed) posix '96 mode */ 2073 if (strncmp(scan, "\\\\\\&", 4) == 0) { 2074 /* \\\& --> \& */ 2075 repllen -= 2; 2076 scan += 3; 2077 } else if (strncmp(scan, "\\\\&", 3) == 0) { 2078 /* \\& --> \<string> */ 2079 ampersands++; 2080 repllen--; 2081 scan += 2; 2082 } else if (scan[1] == '&') { 2083 /* \& --> & */ 2084 repllen--; 2085 scan++; 2086 } /* else 2087 leave alone, it goes into the output */ 2088 } 2089 } 2090 } 2091 2092 lastmatchnonzero = FALSE; 2093 bp = buf; 2094 for (current = 1;; current++) { 2095 matches++; 2096 matchstart = t->stptr + RESTART(rp, t->stptr); 2097 matchend = t->stptr + REEND(rp, t->stptr); 2098 2099 /* 2100 * create the result, copying in parts of the original 2101 * string 2102 */ 2103 len = matchstart - text + repllen 2104 + ampersands * (matchend - matchstart); 2105 sofar = bp - buf; 2106 while (buflen < (sofar + len + 1)) { 2107 buflen *= 2; 2108 erealloc(buf, char *, buflen, "sub_common"); 2109 bp = buf + sofar; 2110 } 2111 for (scan = text; scan < matchstart; scan++) 2112 *bp++ = *scan; 2113 if (global || current == how_many) { 2114 /* 2115 * If the current match matched the null string, 2116 * and the last match didn't and did a replacement, 2117 * and the match of the null string is at the front of 2118 * the text (meaning right after end of the previous 2119 * replacement), then skip this one. 2120 */ 2121 if (matchstart == matchend 2122 && lastmatchnonzero 2123 && matchstart == text) { 2124 lastmatchnonzero = FALSE; 2125 matches--; 2126 goto empty; 2127 } 2128 /* 2129 * If replacing all occurrences, or this is the 2130 * match we want, copy in the replacement text, 2131 * making substitutions as we go. 2132 */ 2133 for (scan = repl; scan < replend; scan++) 2134#ifdef MBS_SUPPORT 2135 if ((gawk_mb_cur_max == 1 2136 || (repllen > 0 && mb_indices[scan - repl] == 1)) 2137 && (*scan == '&')) 2138#else 2139 if (*scan == '&') 2140#endif 2141 for (cp = matchstart; cp < matchend; cp++) 2142 *bp++ = *cp; 2143#ifdef MBS_SUPPORT 2144 else if ((gawk_mb_cur_max == 1 2145 || (repllen > 0 && mb_indices[scan - repl] == 1)) 2146 && (*scan == '\\')) { 2147#else 2148 else if (*scan == '\\') { 2149#endif 2150 if (backdigs) { /* gensub, behave sanely */ 2151 if (ISDIGIT(scan[1])) { 2152 int dig = scan[1] - '0'; 2153 char *start, *end; 2154 2155 start = t->stptr 2156 + SUBPATSTART(rp, t->stptr, dig); 2157 end = t->stptr 2158 + SUBPATEND(rp, t->stptr, dig); 2159 2160 for (cp = start; cp < end; cp++) 2161 *bp++ = *cp; 2162 scan++; 2163 } else /* \q for any q --> q */ 2164 *bp++ = *++scan; 2165 } else { /* posix '96 mode, bleah */ 2166 if (strncmp(scan, "\\\\\\&", 4) == 0) { 2167 /* \\\& --> \& */ 2168 *bp++ = '\\'; 2169 *bp++ = '&'; 2170 scan += 3; 2171 } else if (strncmp(scan, "\\\\&", 3) == 0) { 2172 /* \\& --> \<string> */ 2173 *bp++ = '\\'; 2174 for (cp = matchstart; cp < matchend; cp++) 2175 *bp++ = *cp; 2176 scan += 2; 2177 } else if (scan[1] == '&') { 2178 /* \& --> & */ 2179 *bp++ = '&'; 2180 scan++; 2181 } else 2182 *bp++ = *scan; 2183 } 2184 } else 2185 *bp++ = *scan; 2186 if (matchstart != matchend) 2187 lastmatchnonzero = TRUE; 2188 } else { 2189 /* 2190 * don't want this match, skip over it by copying 2191 * in current text. 2192 */ 2193 for (cp = matchstart; cp < matchend; cp++) 2194 *bp++ = *cp; 2195 } 2196 empty: 2197 /* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */ 2198 if (matchstart == matchend && matchend < text + textlen) { 2199 *bp++ = *matchend; 2200 matchend++; 2201 } 2202 textlen = text + textlen - matchend; 2203 text = matchend; 2204 2205 if ((current >= how_many && !global) 2206 || ((long) textlen <= 0 && matchstart == matchend) 2207 || research(rp, t->stptr, text - t->stptr, textlen, TRUE) == -1) 2208 break; 2209 2210 } 2211 sofar = bp - buf; 2212 if (buflen - sofar - textlen - 1) { 2213 buflen = sofar + textlen + 2; 2214 erealloc(buf, char *, buflen, "sub_common"); 2215 bp = buf + sofar; 2216 } 2217 for (scan = matchend; scan < text + textlen; scan++) 2218 *bp++ = *scan; 2219 *bp = '\0'; 2220 textlen = bp - buf; 2221 free(t->stptr); 2222 t->stptr = buf; 2223 t->stlen = textlen; 2224 2225 free_temp(s); 2226 if (matches > 0 && lhs) { 2227 if (priv) { 2228 unref(*lhs); 2229 *lhs = t; 2230 } 2231 if (after_assign != NULL) 2232 (*after_assign)(); 2233 t->flags &= ~(NUMCUR|NUMBER); 2234 } 2235#ifdef MBS_SUPPORT 2236 if (mb_indices != NULL) 2237 free(mb_indices); 2238#endif 2239 return tmp_number((AWKNUM) matches); 2240} 2241 2242/* do_gsub --- global substitution */ 2243 2244NODE * 2245do_gsub(NODE *tree) 2246{ 2247 return sub_common(tree, -1, FALSE); 2248} 2249 2250/* do_sub --- single substitution */ 2251 2252NODE * 2253do_sub(NODE *tree) 2254{ 2255 return sub_common(tree, 1, FALSE); 2256} 2257 2258/* do_gensub --- fix up the tree for sub_common for the gensub function */ 2259 2260NODE * 2261do_gensub(NODE *tree) 2262{ 2263 NODE n1, n2, n3, *t, *tmp, *target, *ret; 2264 long how_many = 1; /* default is one substitution */ 2265 double d; 2266 2267 /* 2268 * We have to pull out the value of the global flag, and 2269 * build up a tree without the flag in it, turning it into the 2270 * kind of tree that sub_common() expects. It helps to draw 2271 * a picture of this ... 2272 */ 2273 n1 = *tree; 2274 n2 = *(tree->rnode); 2275 n1.rnode = & n2; 2276 2277 t = tree_eval(n2.rnode->lnode); /* value of global flag */ 2278 2279 tmp = force_string(tree_eval(n2.rnode->rnode->lnode)); /* target */ 2280 2281 /* 2282 * We make copy of the original target string, and pass that 2283 * in to sub_common() as the target to make the substitution in. 2284 * We will then return the result string as the return value of 2285 * this function. 2286 */ 2287 target = make_string(tmp->stptr, tmp->stlen); 2288 free_temp(tmp); 2289 2290 n3 = *(n2.rnode->rnode); 2291 n3.lnode = target; 2292 n2.rnode = & n3; 2293 2294 if ((t->flags & (STRCUR|STRING)) != 0) { 2295 if (t->stlen > 0 && (t->stptr[0] == 'g' || t->stptr[0] == 'G')) 2296 how_many = -1; 2297 else 2298 how_many = 1; 2299 } else { 2300 d = force_number(t); 2301 if (d < 1) 2302 how_many = 1; 2303 else if (d < LONG_MAX) 2304 how_many = d; 2305 else 2306 how_many = LONG_MAX; 2307 if (d == 0) 2308 warning(_("gensub: third argument of 0 treated as 1")); 2309 } 2310 2311 free_temp(t); 2312 2313 ret = sub_common(&n1, how_many, TRUE); 2314 free_temp(ret); 2315 2316 /* 2317 * Note that we don't care what sub_common() returns, since the 2318 * easiest thing for the programmer is to return the string, even 2319 * if no substitutions were done. 2320 */ 2321 target->flags |= TEMP; 2322 return target; 2323} 2324 2325#ifdef GFMT_WORKAROUND 2326/* 2327 * printf's %g format [can't rely on gcvt()] 2328 * caveat: don't use as argument to *printf()! 2329 * 'format' string HAS to be of "<flags>*.*g" kind, or we bomb! 2330 */ 2331static void 2332sgfmt(char *buf, /* return buffer; assumed big enough to hold result */ 2333 const char *format, 2334 int alt, /* use alternate form flag */ 2335 int fwidth, /* field width in a format */ 2336 int prec, /* indicates desired significant digits, not decimal places */ 2337 double g) /* value to format */ 2338{ 2339 char dform[40]; 2340 register char *gpos; 2341 register char *d, *e, *p; 2342 int again = FALSE; 2343 2344 strncpy(dform, format, sizeof dform - 1); 2345 dform[sizeof dform - 1] = '\0'; 2346 gpos = strrchr(dform, '.'); 2347 2348 if (g == 0.0 && ! alt) { /* easy special case */ 2349 *gpos++ = 'd'; 2350 *gpos = '\0'; 2351 (void) sprintf(buf, dform, fwidth, 0); 2352 return; 2353 } 2354 2355 /* advance to location of 'g' in the format */ 2356 while (*gpos && *gpos != 'g' && *gpos != 'G') 2357 gpos++; 2358 2359 if (prec <= 0) /* negative precision is ignored */ 2360 prec = (prec < 0 ? DEFAULT_G_PRECISION : 1); 2361 2362 if (*gpos == 'G') 2363 again = TRUE; 2364 /* start with 'e' format (it'll provide nice exponent) */ 2365 *gpos = 'e'; 2366 prec--; 2367 (void) sprintf(buf, dform, fwidth, prec, g); 2368 if ((e = strrchr(buf, 'e')) != NULL) { /* find exponent */ 2369 int expn = atoi(e+1); /* fetch exponent */ 2370 if (expn >= -4 && expn <= prec) { /* per K&R2, B1.2 */ 2371 /* switch to 'f' format and re-do */ 2372 *gpos = 'f'; 2373 prec -= expn; /* decimal precision */ 2374 (void) sprintf(buf, dform, fwidth, prec, g); 2375 e = buf + strlen(buf); 2376 while (*--e == ' ') 2377 continue; 2378 e++; 2379 } 2380 else if (again) 2381 *gpos = 'E'; 2382 2383 /* if 'alt' in force, then trailing zeros are not removed */ 2384 if (! alt && (d = strrchr(buf, '.')) != NULL) { 2385 /* throw away an excess of precision */ 2386 for (p = e; p > d && *--p == '0'; ) 2387 prec--; 2388 if (d == p) 2389 prec--; 2390 if (prec < 0) 2391 prec = 0; 2392 /* and do that once again */ 2393 again = TRUE; 2394 } 2395 if (again) 2396 (void) sprintf(buf, dform, fwidth, prec, g); 2397 } 2398} 2399#endif /* GFMT_WORKAROUND */ 2400 2401/* do_lshift --- perform a << operation */ 2402 2403NODE * 2404do_lshift(NODE *tree) 2405{ 2406 NODE *s1, *s2; 2407 uintmax_t uval, ushift, res; 2408 AWKNUM val, shift; 2409 2410 s1 = tree_eval(tree->lnode); 2411 s2 = tree_eval(tree->rnode->lnode); 2412 val = force_number(s1); 2413 shift = force_number(s2); 2414 2415 if (do_lint) { 2416 if ((s1->flags & (NUMCUR|NUMBER)) == 0) 2417 lintwarn(_("lshift: received non-numeric first argument")); 2418 if ((s2->flags & (NUMCUR|NUMBER)) == 0) 2419 lintwarn(_("lshift: received non-numeric first argument")); 2420 if (val < 0 || shift < 0) 2421 lintwarn(_("lshift(%lf, %lf): negative values will give strange results"), val, shift); 2422 if (double_to_int(val) != val || double_to_int(shift) != shift) 2423 lintwarn(_("lshift(%lf, %lf): fractional values will be truncated"), val, shift); 2424 if (shift >= sizeof(uintmax_t) * CHAR_BIT) 2425 lintwarn(_("lshift(%lf, %lf): too large shift value will give strange results"), val, shift); 2426 } 2427 2428 free_temp(s1); 2429 free_temp(s2); 2430 2431 uval = (uintmax_t) val; 2432 ushift = (uintmax_t) shift; 2433 2434 res = uval << ushift; 2435 return tmp_number((AWKNUM) res); 2436} 2437 2438/* do_rshift --- perform a >> operation */ 2439 2440NODE * 2441do_rshift(NODE *tree) 2442{ 2443 NODE *s1, *s2; 2444 uintmax_t uval, ushift, res; 2445 AWKNUM val, shift; 2446 2447 s1 = tree_eval(tree->lnode); 2448 s2 = tree_eval(tree->rnode->lnode); 2449 val = force_number(s1); 2450 shift = force_number(s2); 2451 2452 if (do_lint) { 2453 if ((s1->flags & (NUMCUR|NUMBER)) == 0) 2454 lintwarn(_("rshift: received non-numeric first argument")); 2455 if ((s2->flags & (NUMCUR|NUMBER)) == 0) 2456 lintwarn(_("rshift: received non-numeric first argument")); 2457 if (val < 0 || shift < 0) 2458 lintwarn(_("rshift(%lf, %lf): negative values will give strange results"), val, shift); 2459 if (double_to_int(val) != val || double_to_int(shift) != shift) 2460 lintwarn(_("rshift(%lf, %lf): fractional values will be truncated"), val, shift); 2461 if (shift >= sizeof(uintmax_t) * CHAR_BIT) 2462 lintwarn(_("rshift(%lf, %lf): too large shift value will give strange results"), val, shift); 2463 } 2464 2465 free_temp(s1); 2466 free_temp(s2); 2467 2468 uval = (uintmax_t) val; 2469 ushift = (uintmax_t) shift; 2470 2471 res = uval >> ushift; 2472 return tmp_number((AWKNUM) res); 2473} 2474 2475/* do_and --- perform an & operation */ 2476 2477NODE * 2478do_and(NODE *tree) 2479{ 2480 NODE *s1, *s2; 2481 uintmax_t uleft, uright, res; 2482 AWKNUM left, right; 2483 2484 s1 = tree_eval(tree->lnode); 2485 s2 = tree_eval(tree->rnode->lnode); 2486 left = force_number(s1); 2487 right = force_number(s2); 2488 2489 if (do_lint) { 2490 if ((s1->flags & (NUMCUR|NUMBER)) == 0) 2491 lintwarn(_("and: received non-numeric first argument")); 2492 if ((s2->flags & (NUMCUR|NUMBER)) == 0) 2493 lintwarn(_("and: received non-numeric first argument")); 2494 if (left < 0 || right < 0) 2495 lintwarn(_("and(%lf, %lf): negative values will give strange results"), left, right); 2496 if (double_to_int(left) != left || double_to_int(right) != right) 2497 lintwarn(_("and(%lf, %lf): fractional values will be truncated"), left, right); 2498 } 2499 2500 free_temp(s1); 2501 free_temp(s2); 2502 2503 uleft = (uintmax_t) left; 2504 uright = (uintmax_t) right; 2505 2506 res = uleft & uright; 2507 return tmp_number((AWKNUM) res); 2508} 2509 2510/* do_or --- perform an | operation */ 2511 2512NODE * 2513do_or(NODE *tree) 2514{ 2515 NODE *s1, *s2; 2516 uintmax_t uleft, uright, res; 2517 AWKNUM left, right; 2518 2519 s1 = tree_eval(tree->lnode); 2520 s2 = tree_eval(tree->rnode->lnode); 2521 left = force_number(s1); 2522 right = force_number(s2); 2523 2524 if (do_lint) { 2525 if ((s1->flags & (NUMCUR|NUMBER)) == 0) 2526 lintwarn(_("or: received non-numeric first argument")); 2527 if ((s2->flags & (NUMCUR|NUMBER)) == 0) 2528 lintwarn(_("or: received non-numeric first argument")); 2529 if (left < 0 || right < 0) 2530 lintwarn(_("or(%lf, %lf): negative values will give strange results"), left, right); 2531 if (double_to_int(left) != left || double_to_int(right) != right) 2532 lintwarn(_("or(%lf, %lf): fractional values will be truncated"), left, right); 2533 } 2534 2535 free_temp(s1); 2536 free_temp(s2); 2537 2538 uleft = (uintmax_t) left; 2539 uright = (uintmax_t) right; 2540 2541 res = uleft | uright; 2542 return tmp_number((AWKNUM) res); 2543} 2544 2545/* do_xor --- perform an ^ operation */ 2546 2547NODE * 2548do_xor(NODE *tree) 2549{ 2550 NODE *s1, *s2; 2551 uintmax_t uleft, uright, res; 2552 AWKNUM left, right; 2553 2554 s1 = tree_eval(tree->lnode); 2555 s2 = tree_eval(tree->rnode->lnode); 2556 left = force_number(s1); 2557 right = force_number(s2); 2558 2559 if (do_lint) { 2560 if ((s1->flags & (NUMCUR|NUMBER)) == 0) 2561 lintwarn(_("xor: received non-numeric first argument")); 2562 if ((s2->flags & (NUMCUR|NUMBER)) == 0) 2563 lintwarn(_("xor: received non-numeric first argument")); 2564 if (left < 0 || right < 0) 2565 lintwarn(_("xor(%lf, %lf): negative values will give strange results"), left, right); 2566 if (double_to_int(left) != left || double_to_int(right) != right) 2567 lintwarn(_("xor(%lf, %lf): fractional values will be truncated"), left, right); 2568 } 2569 2570 free_temp(s1); 2571 free_temp(s2); 2572 2573 uleft = (uintmax_t) left; 2574 uright = (uintmax_t) right; 2575 2576 res = uleft ^ uright; 2577 return tmp_number((AWKNUM) res); 2578} 2579 2580/* do_compl --- perform a ~ operation */ 2581 2582NODE * 2583do_compl(NODE *tree) 2584{ 2585 NODE *tmp; 2586 double d; 2587 uintmax_t uval; 2588 2589 tmp = tree_eval(tree->lnode); 2590 d = force_number(tmp); 2591 free_temp(tmp); 2592 2593 if (do_lint) { 2594 if ((tmp->flags & (NUMCUR|NUMBER)) == 0) 2595 lintwarn(_("compl: received non-numeric argument")); 2596 if (d < 0) 2597 lintwarn(_("compl(%lf): negative value will give strange results"), d); 2598 if (double_to_int(d) != d) 2599 lintwarn(_("compl(%lf): fractional value will be truncated"), d); 2600 } 2601 2602 uval = (uintmax_t) d; 2603 uval = ~ uval; 2604 return tmp_number((AWKNUM) uval); 2605} 2606 2607/* do_strtonum --- the strtonum function */ 2608 2609NODE * 2610do_strtonum(NODE *tree) 2611{ 2612 NODE *tmp; 2613 double d; 2614 2615 tmp = tree_eval(tree->lnode); 2616 2617 if ((tmp->flags & (NUMBER|NUMCUR)) != 0) 2618 d = (double) force_number(tmp); 2619 else if (isnondecimal(tmp->stptr)) 2620 d = nondec2awknum(tmp->stptr, tmp->stlen); 2621 else 2622 d = (double) force_number(tmp); 2623 2624 free_temp(tmp); 2625 return tmp_number((AWKNUM) d); 2626} 2627 2628/* nondec2awknum --- convert octal or hex value to double */ 2629 2630/* 2631 * Because of awk's concatenation rules and the way awk.y:yylex() 2632 * collects a number, this routine has to be willing to stop on the 2633 * first invalid character. 2634 */ 2635 2636AWKNUM 2637nondec2awknum(char *str, size_t len) 2638{ 2639 AWKNUM retval = 0.0; 2640 char save; 2641 short val; 2642 char *start = str; 2643 2644 if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) { 2645 /* 2646 * User called strtonum("0x") or some such, 2647 * so just quit early. 2648 */ 2649 if (len <= 2) 2650 return (AWKNUM) 0.0; 2651 2652 for (str += 2, len -= 2; len > 0; len--, str++) { 2653 switch (*str) { 2654 case '0': 2655 case '1': 2656 case '2': 2657 case '3': 2658 case '4': 2659 case '5': 2660 case '6': 2661 case '7': 2662 case '8': 2663 case '9': 2664 val = *str - '0'; 2665 break; 2666 case 'a': 2667 case 'b': 2668 case 'c': 2669 case 'd': 2670 case 'e': 2671 case 'f': 2672 val = *str - 'a' + 10; 2673 break; 2674 case 'A': 2675 case 'B': 2676 case 'C': 2677 case 'D': 2678 case 'E': 2679 case 'F': 2680 val = *str - 'A' + 10; 2681 break; 2682 default: 2683 goto done; 2684 } 2685 retval = (retval * 16) + val; 2686 } 2687 } else if (*str == '0') { 2688 for (; len > 0; len--) { 2689 if (! ISDIGIT(*str)) 2690 goto done; 2691 else if (*str == '8' || *str == '9') { 2692 str = start; 2693 goto decimal; 2694 } 2695 retval = (retval * 8) + (*str - '0'); 2696 str++; 2697 } 2698 } else { 2699decimal: 2700 save = str[len]; 2701 retval = strtod(str, NULL); 2702 str[len] = save; 2703 } 2704done: 2705 return retval; 2706} 2707 2708/* do_dcgettext, do_dcngettext --- handle i18n translations */ 2709 2710#if ENABLE_NLS && HAVE_LC_MESSAGES && HAVE_DCGETTEXT 2711 2712static int 2713localecategory_from_argument(NODE *tree) 2714{ 2715 static const struct category_table { 2716 int val; 2717 const char *name; 2718 } cat_tab[] = { 2719#ifdef LC_ALL 2720 { LC_ALL, "LC_ALL" }, 2721#endif /* LC_ALL */ 2722#ifdef LC_COLLATE 2723 { LC_COLLATE, "LC_COLLATE" }, 2724#endif /* LC_COLLATE */ 2725#ifdef LC_CTYPE 2726 { LC_CTYPE, "LC_CTYPE" }, 2727#endif /* LC_CTYPE */ 2728#ifdef LC_MESSAGES 2729 { LC_MESSAGES, "LC_MESSAGES" }, 2730#endif /* LC_MESSAGES */ 2731#ifdef LC_MONETARY 2732 { LC_MONETARY, "LC_MONETARY" }, 2733#endif /* LC_MONETARY */ 2734#ifdef LC_NUMERIC 2735 { LC_NUMERIC, "LC_NUMERIC" }, 2736#endif /* LC_NUMERIC */ 2737#ifdef LC_RESPONSE 2738 { LC_RESPONSE, "LC_RESPONSE" }, 2739#endif /* LC_RESPONSE */ 2740#ifdef LC_TIME 2741 { LC_TIME, "LC_TIME" }, 2742#endif /* LC_TIME */ 2743 }; 2744 2745 if (tree != NULL) { 2746 int low, high, i, mid; 2747 NODE *tmp, *t; 2748 char *category; 2749 int lc_cat = -1; 2750 2751 tmp = tree->lnode; 2752 t = force_string(tree_eval(tmp)); 2753 category = t->stptr; 2754 2755 /* binary search the table */ 2756 low = 0; 2757 high = (sizeof(cat_tab) / sizeof(cat_tab[0])) - 1; 2758 while (low <= high) { 2759 mid = (low + high) / 2; 2760 i = strcmp(category, cat_tab[mid].name); 2761 2762 if (i < 0) /* category < mid */ 2763 high = mid - 1; 2764 else if (i > 0) /* category > mid */ 2765 low = mid + 1; 2766 else { 2767 lc_cat = cat_tab[mid].val; 2768 break; 2769 } 2770 } 2771 if (lc_cat == -1) /* not there */ 2772 fatal(_("dcgettext: `%s' is not a valid locale category"), category); 2773 2774 free_temp(t); 2775 return lc_cat; 2776 } else 2777 return LC_MESSAGES; 2778} 2779 2780#endif 2781 2782/* 2783 * awk usage is 2784 * 2785 * str = dcgettext(string [, domain [, category]]) 2786 * str = dcngettext(string1, string2, number [, domain [, category]]) 2787 * 2788 * Default domain is TEXTDOMAIN, default category is LC_MESSAGES. 2789 */ 2790 2791NODE * 2792do_dcgettext(NODE *tree) 2793{ 2794 NODE *tmp, *t1, *t2; 2795 char *string; 2796 char *the_result; 2797#if ENABLE_NLS && HAVE_LC_MESSAGES && HAVE_DCGETTEXT 2798 int lc_cat; 2799 char *domain; 2800#endif /* ENABLE_NLS */ 2801 2802 tmp = tree->lnode; /* first argument */ 2803 t1 = force_string(tree_eval(tmp)); 2804 string = t1->stptr; 2805 2806 t2 = NULL; 2807#if ENABLE_NLS && HAVE_LC_MESSAGES && HAVE_DCGETTEXT 2808 tree = tree->rnode; /* second argument */ 2809 if (tree != NULL) { 2810 tmp = tree->lnode; 2811 t2 = force_string(tree_eval(tmp)); 2812 domain = t2->stptr; 2813 } else 2814 domain = TEXTDOMAIN; 2815 2816 if (tree && tree->rnode != NULL) { /* third argument */ 2817 lc_cat = localecategory_from_argument(tree->rnode); 2818 } else 2819 lc_cat = LC_MESSAGES; 2820 2821 the_result = dcgettext(domain, string, lc_cat); 2822#else 2823 the_result = string; 2824#endif 2825 free_temp(t1); 2826 if (t2 != NULL) 2827 free_temp(t2); 2828 2829 return tmp_string(the_result, strlen(the_result)); 2830} 2831 2832NODE * 2833do_dcngettext(NODE *tree) 2834{ 2835 NODE *tmp, *t1, *t2, *t3; 2836 char *string1, *string2; 2837 unsigned long number; 2838 char *the_result; 2839#if ENABLE_NLS && HAVE_LC_MESSAGES && HAVE_DCGETTEXT 2840 int lc_cat; 2841 char *domain; 2842#endif /* ENABLE_NLS */ 2843 2844 tmp = tree->lnode; /* first argument */ 2845 t1 = force_string(tree_eval(tmp)); 2846 string1 = t1->stptr; 2847 2848 tmp = tree->rnode->lnode; /* second argument */ 2849 t2 = force_string(tree_eval(tmp)); 2850 string2 = t2->stptr; 2851 2852 tmp = tree->rnode->rnode->lnode; /* third argument */ 2853 number = (unsigned long) double_to_int(force_number(tree_eval(tmp))); 2854 2855 t3 = NULL; 2856#if ENABLE_NLS && HAVE_LC_MESSAGES && HAVE_DCGETTEXT 2857 tree = tree->rnode->rnode->rnode; /* fourth argument */ 2858 if (tree != NULL) { 2859 tmp = tree->lnode; 2860 t3 = force_string(tree_eval(tmp)); 2861 domain = t3->stptr; 2862 } else 2863 domain = TEXTDOMAIN; 2864 2865 if (tree && tree->rnode != NULL) { /* fifth argument */ 2866 lc_cat = localecategory_from_argument(tree->rnode); 2867 } else 2868 lc_cat = LC_MESSAGES; 2869 2870 the_result = dcngettext(domain, string1, string2, number, lc_cat); 2871#else 2872 the_result = (number == 1 ? string1 : string2); 2873#endif 2874 free_temp(t1); 2875 free_temp(t2); 2876 if (t3 != NULL) 2877 free_temp(t3); 2878 2879 return tmp_string(the_result, strlen(the_result)); 2880} 2881 2882/* do_bindtextdomain --- set the directory for a text domain */ 2883 2884/* 2885 * awk usage is 2886 * 2887 * binding = bindtextdomain(dir [, domain]) 2888 * 2889 * If dir is "", pass NULL to C version. 2890 * Default domain is TEXTDOMAIN. 2891 */ 2892 2893NODE * 2894do_bindtextdomain(NODE *tree) 2895{ 2896 NODE *tmp, *t1, *t2; 2897 char *directory, *domain; 2898 char *the_result; 2899 2900 t1 = t2 = NULL; 2901 /* set defaults */ 2902 directory = NULL; 2903 domain = TEXTDOMAIN; 2904 2905 tmp = tree->lnode; /* first argument */ 2906 t1 = force_string(tree_eval(tmp)); 2907 if (t1->stlen > 0) 2908 directory = t1->stptr; 2909 2910 tree = tree->rnode; /* second argument */ 2911 if (tree != NULL) { 2912 tmp = tree->lnode; 2913 t2 = force_string(tree_eval(tmp)); 2914 domain = t2->stptr; 2915 } 2916 2917 the_result = bindtextdomain(domain, directory); 2918 2919 free_temp(t1); 2920 if (t2 != NULL) 2921 free_temp(t2); 2922 2923 return tmp_string(the_result, strlen(the_result)); 2924} 2925