00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "awk.h"
00028 #if defined(HAVE_FCNTL_H)
00029 #include <fcntl.h>
00030 #endif
00031 #undef HUGE
00032 #undef CHARBITS
00033 #undef INTBITS
00034 #if HAVE_INTTYPES_H
00035 # include <inttypes.h>
00036 #else
00037 # if HAVE_STDINT_H
00038 # include <stdint.h>
00039 # endif
00040 #endif
00041 #include <math.h>
00042 #include "random.h"
00043
00044 #ifndef CHAR_BIT
00045 # define CHAR_BIT 8
00046 #endif
00047
00048
00049 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
00050
00051
00052 #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
00053 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
00054 #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
00055
00056 #ifndef INTMAX_MIN
00057 # define INTMAX_MIN TYPE_MINIMUM (intmax_t)
00058 #endif
00059 #ifndef UINTMAX_MAX
00060 # define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t)
00061 #endif
00062
00063 #ifndef SIZE_MAX
00064 #define SIZE_MAX ((size_t) -1)
00065 #endif
00066
00067
00068 extern char *initstate P((unsigned long seed, char *state, long n));
00069 extern char *setstate P((char *state));
00070 extern long random P((void));
00071 extern void srandom P((unsigned long seed));
00072
00073 extern NODE **fields_arr;
00074 extern int output_is_tty;
00075
00076 static NODE *sub_common P((NODE *tree, long how_many, int backdigs));
00077
00078 #ifdef _CRAY
00079
00080 #include <float.h>
00081 #define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
00082 #define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
00083
00084
00085 extern double exp(double);
00086 double (*Exp)() = exp;
00087 #define exp(x) (*Exp)(x)
00088 extern double log(double);
00089 double (*Log)() = log;
00090 #define log(x) (*Log)(x)
00091 #else
00092 #define Floor(n) floor(n)
00093 #define Ceil(n) ceil(n)
00094 #endif
00095
00096 #define DEFAULT_G_PRECISION 6
00097
00098 #ifdef GFMT_WORKAROUND
00099
00100 static void sgfmt P((char *buf, const char *format, int alt,
00101 int fwidth, int precision, double value));
00102 #endif
00103
00104
00105
00106
00107
00108 #define GAWK_RANDOM_MAX 0x7fffffffL
00109
00110 static void efwrite P((const void *ptr, size_t size, size_t count, FILE *fp,
00111 const char *from, struct redirect *rp, int flush));
00112
00113
00114
00115 static void
00116 efwrite(const void *ptr,
00117 size_t size,
00118 size_t count,
00119 FILE *fp,
00120 const char *from,
00121 struct redirect *rp,
00122 int flush)
00123 {
00124 errno = 0;
00125 if (fwrite(ptr, size, count, fp) != count)
00126 goto wrerror;
00127 if (flush
00128 && ((fp == stdout && output_is_tty)
00129 || (rp != NULL && (rp->flag & RED_NOBUF)))) {
00130 fflush(fp);
00131 if (ferror(fp))
00132 goto wrerror;
00133 }
00134 return;
00135
00136 wrerror:
00137 fatal(_("%s to \"%s\" failed (%s)"), from,
00138 rp ? rp->value : _("standard output"),
00139 errno ? strerror(errno) : _("reason unknown"));
00140 }
00141
00142
00143
00144 NODE *
00145 do_exp(NODE *tree)
00146 {
00147 NODE *tmp;
00148 double d, res;
00149
00150 tmp = tree_eval(tree->lnode);
00151 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
00152 lintwarn(_("exp: received non-numeric argument"));
00153 d = force_number(tmp);
00154 free_temp(tmp);
00155 errno = 0;
00156 res = exp(d);
00157 if (errno == ERANGE)
00158 warning(_("exp: argument %g is out of range"), d);
00159 return tmp_number((AWKNUM) res);
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 static FILE *
00171 stdfile(const char *name, size_t len)
00172 {
00173 if (len == 11) {
00174 if (STREQN(name, "/dev/stderr", 11))
00175 return stderr;
00176 else if (STREQN(name, "/dev/stdout", 11))
00177 return stdout;
00178 }
00179
00180 return NULL;
00181 }
00182
00183
00184
00185 NODE *
00186 do_fflush(NODE *tree)
00187 {
00188 struct redirect *rp;
00189 NODE *tmp;
00190 FILE *fp;
00191 int status = 0;
00192 const char *file;
00193
00194
00195 if (tree == NULL) {
00196 status = fflush(stdout);
00197 return tmp_number((AWKNUM) status);
00198 }
00199
00200 tmp = tree_eval(tree->lnode);
00201 tmp = force_string(tmp);
00202 file = tmp->stptr;
00203
00204
00205 if (tmp->stlen == 0) {
00206 status = flush_io();
00207 free_temp(tmp);
00208 return tmp_number((AWKNUM) status);
00209 }
00210
00211 rp = getredirect(tmp->stptr, tmp->stlen);
00212 status = -1;
00213 if (rp != NULL) {
00214 if ((rp->flag & (RED_WRITE|RED_APPEND)) == 0) {
00215 if (rp->flag & RED_PIPE)
00216 warning(_("fflush: cannot flush: pipe `%s' opened for reading, not writing"),
00217 file);
00218 else
00219 warning(_("fflush: cannot flush: file `%s' opened for reading, not writing"),
00220 file);
00221 free_temp(tmp);
00222 return tmp_number((AWKNUM) status);
00223 }
00224 fp = rp->fp;
00225 if (fp != NULL)
00226 status = fflush(fp);
00227 } else if ((fp = stdfile(tmp->stptr, tmp->stlen)) != NULL) {
00228 status = fflush(fp);
00229 } else {
00230 status = -1;
00231 warning(_("fflush: `%s' is not an open file, pipe or co-process"), file);
00232 }
00233 free_temp(tmp);
00234 return tmp_number((AWKNUM) status);
00235 }
00236
00237 #ifdef MBS_SUPPORT
00238
00239 int
00240 strncasecmpmbs(const char *s1, mbstate_t mbs1, const char *s2,
00241 mbstate_t mbs2, size_t n)
00242 {
00243 int i1, i2, mbclen1, mbclen2, gap;
00244 wchar_t wc1, wc2;
00245 for (i1 = i2 = 0 ; i1 < n && i2 < n ;i1 += mbclen1, i2 += mbclen2) {
00246 mbclen1 = mbrtowc(&wc1, s1 + i1, n - i1, &mbs1);
00247 if (mbclen1 == (size_t) -1 || mbclen1 == (size_t) -2 || mbclen1 == 0) {
00248
00249 mbclen1 = 1;
00250 wc1 = s1[i1];
00251 }
00252 mbclen2 = mbrtowc(&wc2, s2 + i2, n - i2, &mbs2);
00253 if (mbclen2 == (size_t) -1 || mbclen2 == (size_t) -2 || mbclen2 == 0) {
00254
00255 mbclen2 = 1;
00256 wc2 = s2[i2];
00257 }
00258 if ((gap = towlower(wc1) - towlower(wc2)) != 0)
00259
00260 return gap;
00261 }
00262
00263 return 0;
00264 }
00265
00266
00267
00268
00269
00270
00271
00272 static void
00273 index_multibyte_buffer(char* src, char* dest, int len)
00274 {
00275 int idx, prev_idx;
00276 mbstate_t mbs, prevs;
00277 memset(&prevs, 0, sizeof(mbstate_t));
00278
00279 for (idx = prev_idx = 0 ; idx < len ; idx++) {
00280 size_t mbclen;
00281 mbs = prevs;
00282 mbclen = mbrlen(src + prev_idx, idx - prev_idx + 1, &mbs);
00283 if (mbclen == (size_t) -1 || mbclen == 1 || mbclen == 0) {
00284
00285 mbclen = 1;
00286 prev_idx = idx + 1;
00287 } else if (mbclen == (size_t) -2) {
00288
00289 mbclen = idx - prev_idx + 1;
00290 } else if (mbclen > 1) {
00291
00292 prev_idx = idx + 1;
00293 prevs = mbs;
00294 } else {
00295
00296 }
00297 dest[idx] = mbclen;
00298 }
00299 }
00300 #endif
00301
00302
00303
00304 NODE *
00305 do_index(NODE *tree)
00306 {
00307 NODE *s1, *s2;
00308 register const char *p1, *p2;
00309 register size_t l1, l2;
00310 long ret;
00311 #ifdef MBS_SUPPORT
00312 size_t mbclen = 0;
00313 mbstate_t mbs1, mbs2;
00314 if (gawk_mb_cur_max > 1) {
00315 memset(&mbs1, 0, sizeof(mbstate_t));
00316 memset(&mbs2, 0, sizeof(mbstate_t));
00317 }
00318 #endif
00319
00320
00321 s1 = tree_eval(tree->lnode);
00322 s2 = tree_eval(tree->rnode->lnode);
00323 if (do_lint) {
00324 if ((s1->flags & (STRING|STRCUR)) == 0)
00325 lintwarn(_("index: received non-string first argument"));
00326 if ((s2->flags & (STRING|STRCUR)) == 0)
00327 lintwarn(_("index: received non-string second argument"));
00328 }
00329 force_string(s1);
00330 force_string(s2);
00331 p1 = s1->stptr;
00332 p2 = s2->stptr;
00333 l1 = s1->stlen;
00334 l2 = s2->stlen;
00335 ret = 0;
00336
00337
00338
00339
00340
00341
00342 if (l2 == 0) {
00343 ret = 1;
00344 goto out;
00345 }
00346
00347
00348 if (IGNORECASE) {
00349 while (l1 > 0) {
00350 if (l2 > l1)
00351 break;
00352 #ifdef MBS_SUPPORT
00353 if (gawk_mb_cur_max > 1) {
00354 if (strncasecmpmbs(p1, mbs1, p2, mbs2, l2) == 0) {
00355 ret = 1 + s1->stlen - l1;
00356 break;
00357 }
00358
00359 mbclen = mbrlen(p1, l1, &mbs1);
00360 if ((mbclen == 1) || (mbclen == (size_t) -1)
00361 || (mbclen == (size_t) -2) || (mbclen == 0)) {
00362
00363 mbclen = 1;
00364 }
00365 l1 -= mbclen;
00366 p1 += mbclen;
00367 } else {
00368 #endif
00369 if (casetable[(unsigned char)*p1] == casetable[(unsigned char)*p2]
00370 && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
00371 ret = 1 + s1->stlen - l1;
00372 break;
00373 }
00374 l1--;
00375 p1++;
00376 #ifdef MBS_SUPPORT
00377 }
00378 #endif
00379 }
00380 } else {
00381 while (l1 > 0) {
00382 if (l2 > l1)
00383 break;
00384 if (*p1 == *p2
00385 && (l2 == 1 || STREQN(p1, p2, l2))) {
00386 ret = 1 + s1->stlen - l1;
00387 break;
00388 }
00389 #ifdef MBS_SUPPORT
00390 if (gawk_mb_cur_max > 1) {
00391 mbclen = mbrlen(p1, l1, &mbs1);
00392 if ((mbclen == 1) || (mbclen == (size_t) -1) ||
00393 (mbclen == (size_t) -2) || (mbclen == 0)) {
00394
00395 mbclen = 1;
00396 }
00397 l1 -= mbclen;
00398 p1 += mbclen;
00399 } else {
00400 l1--;
00401 p1++;
00402 }
00403 #else
00404 l1--;
00405 p1++;
00406 #endif
00407 }
00408 }
00409 out:
00410 free_temp(s1);
00411 free_temp(s2);
00412 return tmp_number((AWKNUM) ret);
00413 }
00414
00415
00416
00417 double
00418 double_to_int(double d)
00419 {
00420 if (d >= 0)
00421 d = Floor(d);
00422 else
00423 d = Ceil(d);
00424 return d;
00425 }
00426
00427
00428
00429 NODE *
00430 do_int(NODE *tree)
00431 {
00432 NODE *tmp;
00433 double d;
00434
00435 tmp = tree_eval(tree->lnode);
00436 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
00437 lintwarn(_("int: received non-numeric argument"));
00438 d = force_number(tmp);
00439 d = double_to_int(d);
00440 free_temp(tmp);
00441 return tmp_number((AWKNUM) d);
00442 }
00443
00444
00445
00446 NODE *
00447 do_length(NODE *tree)
00448 {
00449 NODE *tmp;
00450 size_t len;
00451
00452 tmp = tree_eval(tree->lnode);
00453 if (do_lint && (tmp->flags & (STRING|STRCUR)) == 0)
00454 lintwarn(_("length: received non-string argument"));
00455 len = force_string(tmp)->stlen;
00456 free_temp(tmp);
00457 return tmp_number((AWKNUM) len);
00458 }
00459
00460
00461
00462 NODE *
00463 do_log(NODE *tree)
00464 {
00465 NODE *tmp;
00466 double d, arg;
00467
00468 tmp = tree_eval(tree->lnode);
00469 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
00470 lintwarn(_("log: received non-numeric argument"));
00471 arg = (double) force_number(tmp);
00472 if (arg < 0.0)
00473 warning(_("log: received negative argument %g"), arg);
00474 d = log(arg);
00475 free_temp(tmp);
00476 return tmp_number((AWKNUM) d);
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 NODE *
00490 format_tree(
00491 const char *fmt_string,
00492 size_t n0,
00493 register NODE *carg,
00494 long num_args)
00495 {
00496
00497
00498 #define bchunk(s, l) if (l) { \
00499 while ((l) > ofre) { \
00500 long olen = obufout - obuf; \
00501 erealloc(obuf, char *, osiz * 2, "format_tree"); \
00502 ofre += osiz; \
00503 osiz *= 2; \
00504 obufout = obuf + olen; \
00505 } \
00506 memcpy(obufout, s, (size_t) (l)); \
00507 obufout += (l); \
00508 ofre -= (l); \
00509 }
00510
00511
00512 #define bchunk_one(s) { \
00513 if (ofre < 1) { \
00514 long olen = obufout - obuf; \
00515 erealloc(obuf, char *, osiz * 2, "format_tree"); \
00516 ofre += osiz; \
00517 osiz *= 2; \
00518 obufout = obuf + olen; \
00519 } \
00520 *obufout++ = *s; \
00521 --ofre; \
00522 }
00523
00524
00525 #define chksize(l) if ((l) > ofre) { \
00526 long olen = obufout - obuf; \
00527 erealloc(obuf, char *, osiz * 2, "format_tree"); \
00528 obufout = obuf + olen; \
00529 ofre += osiz; \
00530 osiz *= 2; \
00531 }
00532
00533 static NODE **the_args = 0;
00534 static size_t args_size = 0;
00535 size_t cur_arg = 0;
00536
00537 auto NODE **save_args = 0;
00538 auto size_t save_args_size = 0;
00539 static int call_level = 0;
00540
00541 NODE *r;
00542 int i;
00543 int toofew = FALSE;
00544 char *obuf, *obufout;
00545 size_t osiz, ofre;
00546 const char *chbuf;
00547 const char *s0, *s1;
00548 int cs1;
00549 NODE *arg;
00550 long fw, prec, argnum;
00551 int used_dollar;
00552 int lj, alt, big, bigbig, small, have_prec, need_format;
00553 long *cur = NULL;
00554 #ifdef sun386
00555 long tmp_uval;
00556 #endif
00557 uintmax_t uval;
00558 int sgn;
00559 int base = 0;
00560 char cpbuf[30];
00561 char *cend = &cpbuf[30];
00562 char *cp;
00563 const char *fill;
00564 double tmpval;
00565 char signchar = FALSE;
00566 size_t len;
00567 int zero_flag = FALSE;
00568 static const char sp[] = " ";
00569 static const char zero_string[] = "0";
00570 static const char lchbuf[] = "0123456789abcdef";
00571 static const char Uchbuf[] = "0123456789ABCDEF";
00572
00573 #define INITIAL_OUT_SIZE 512
00574 emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
00575 obufout = obuf;
00576 osiz = INITIAL_OUT_SIZE;
00577 ofre = osiz - 1;
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587 if (++call_level > 1) {
00588 save_args = the_args;
00589 save_args_size = args_size;
00590
00591 args_size = 0;
00592 }
00593
00594 if (args_size == 0) {
00595
00596 emalloc(the_args, NODE **, (num_args+1) * sizeof(NODE *), "format_tree");
00597 args_size = num_args + 1;
00598 } else if (num_args + 1 > args_size) {
00599
00600 erealloc(the_args, NODE **, (num_args+1) * sizeof(NODE *), "format_tree");
00601 args_size = num_args + 1;
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 memset(the_args, '\0', num_args * sizeof(NODE *));
00613 for (i = 1; carg != NULL; i++, carg = carg->rnode) {
00614 NODE *tmp;
00615
00616
00617 tmp = tree_eval(carg->lnode);
00618 the_args[i] = dupnode(tmp);
00619 free_temp(tmp);
00620 }
00621 assert(i == num_args);
00622 cur_arg = 1;
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632 #define parse_next_arg() { \
00633 if (argnum > 0) { \
00634 if (cur_arg > 1) \
00635 fatal(_("must use `count$' on all formats or none")); \
00636 arg = the_args[argnum]; \
00637 } else if (used_dollar) { \
00638 fatal(_("must use `count$' on all formats or none")); \
00639 arg = 0; \
00640 } else if (cur_arg >= num_args) { \
00641 arg = 0; \
00642 toofew = TRUE; \
00643 break; \
00644 } else { \
00645 arg = the_args[cur_arg]; \
00646 cur_arg++; \
00647 } \
00648 }
00649
00650 need_format = FALSE;
00651 used_dollar = FALSE;
00652
00653 s0 = s1 = fmt_string;
00654 while (n0-- > 0) {
00655 if (*s1 != '%') {
00656 s1++;
00657 continue;
00658 }
00659 need_format = TRUE;
00660 bchunk(s0, s1 - s0);
00661 s0 = s1;
00662 cur = &fw;
00663 fw = 0;
00664 prec = 0;
00665 argnum = 0;
00666 have_prec = FALSE;
00667 signchar = FALSE;
00668 zero_flag = FALSE;
00669 lj = alt = big = bigbig = small = FALSE;
00670 fill = sp;
00671 cp = cend;
00672 chbuf = lchbuf;
00673 s1++;
00674
00675 retry:
00676 if (n0-- == 0)
00677 break;
00678
00679 switch (cs1 = *s1++) {
00680 case (-1):
00681 check_pos:
00682 if (cur != &fw)
00683 break;
00684 goto retry;
00685 case '%':
00686 need_format = FALSE;
00687
00688
00689
00690
00691
00692
00693
00694 bchunk_one("%");
00695 s0 = s1;
00696 break;
00697
00698 case '0':
00699
00700
00701
00702
00703
00704 if (cur == & fw)
00705 zero_flag = TRUE;
00706 if (lj)
00707 goto retry;
00708
00709 case '1':
00710 case '2':
00711 case '3':
00712 case '4':
00713 case '5':
00714 case '6':
00715 case '7':
00716 case '8':
00717 case '9':
00718 if (cur == NULL)
00719 break;
00720 if (prec >= 0)
00721 *cur = cs1 - '0';
00722
00723
00724
00725
00726
00727 while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
00728 --n0;
00729 *cur = *cur * 10 + *s1++ - '0';
00730 }
00731 if (prec < 0)
00732 have_prec = FALSE;
00733 if (cur == &prec)
00734 cur = NULL;
00735 if (n0 == 0)
00736 continue;
00737 goto retry;
00738 case '$':
00739 if (do_traditional)
00740 fatal(_("`$' is not permitted in awk formats"));
00741 if (cur == &fw) {
00742 argnum = fw;
00743 fw = 0;
00744 used_dollar = TRUE;
00745 if (argnum <= 0)
00746 fatal(_("arg count with `$' must be > 0"));
00747 if (argnum >= num_args)
00748 fatal(_("arg count %ld greater than total number of supplied arguments"), argnum);
00749 } else
00750 fatal(_("`$' not permitted after period in format"));
00751 goto retry;
00752 case '*':
00753 if (cur == NULL)
00754 break;
00755 if (! do_traditional && ISDIGIT(*s1)) {
00756 int val = 0;
00757
00758 for (; n0 > 0 && *s1 && ISDIGIT(*s1); s1++, n0--) {
00759 val *= 10;
00760 val += *s1 - '0';
00761 }
00762 if (*s1 != '$') {
00763 fatal(_("no `$' supplied for positional field width or precision"));
00764 } else {
00765 s1++;
00766 n0--;
00767 }
00768
00769 arg = the_args[val];
00770 } else {
00771 parse_next_arg();
00772 }
00773 *cur = force_number(arg);
00774 if (*cur < 0 && cur == &fw) {
00775 *cur = -*cur;
00776 lj++;
00777 }
00778 if (cur == &prec) {
00779 if (*cur >= 0)
00780 have_prec = TRUE;
00781 else
00782 have_prec = FALSE;
00783 cur = NULL;
00784 }
00785 goto retry;
00786 case ' ':
00787
00788
00789 if (signchar != FALSE)
00790 goto check_pos;
00791
00792 case '+':
00793 signchar = cs1;
00794 goto check_pos;
00795 case '-':
00796 if (prec < 0)
00797 break;
00798 if (cur == &prec) {
00799 prec = -1;
00800 goto retry;
00801 }
00802 fill = sp;
00803 lj++;
00804 goto check_pos;
00805 case '.':
00806 if (cur != &fw)
00807 break;
00808 cur = ≺
00809 have_prec = TRUE;
00810 goto retry;
00811 case '#':
00812 alt = TRUE;
00813 goto check_pos;
00814 case 'l':
00815 if (big)
00816 break;
00817 else {
00818 static int warned = FALSE;
00819
00820 if (do_lint && ! warned) {
00821 lintwarn(_("`l' is meaningless in awk formats; ignored"));
00822 warned = TRUE;
00823 }
00824 if (do_posix)
00825 fatal(_("`l' is not permitted in POSIX awk formats"));
00826 }
00827 big = TRUE;
00828 goto retry;
00829 case 'L':
00830 if (bigbig)
00831 break;
00832 else {
00833 static int warned = FALSE;
00834
00835 if (do_lint && ! warned) {
00836 lintwarn(_("`L' is meaningless in awk formats; ignored"));
00837 warned = TRUE;
00838 }
00839 if (do_posix)
00840 fatal(_("`L' is not permitted in POSIX awk formats"));
00841 }
00842 bigbig = TRUE;
00843 goto retry;
00844 case 'h':
00845 if (small)
00846 break;
00847 else {
00848 static int warned = FALSE;
00849
00850 if (do_lint && ! warned) {
00851 lintwarn(_("`h' is meaningless in awk formats; ignored"));
00852 warned = TRUE;
00853 }
00854 if (do_posix)
00855 fatal(_("`h' is not permitted in POSIX awk formats"));
00856 }
00857 small = TRUE;
00858 goto retry;
00859 case 'c':
00860 need_format = FALSE;
00861 if (zero_flag && ! lj)
00862 fill = zero_string;
00863 parse_next_arg();
00864
00865 if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
00866 (void) force_number(arg);
00867 if (arg->flags & NUMBER) {
00868 #ifdef sun386
00869 tmp_uval = arg->numbr;
00870 uval = (unsigned long) tmp_uval;
00871 #else
00872 uval = (uintmax_t) arg->numbr;
00873 #endif
00874 cpbuf[0] = uval;
00875 prec = 1;
00876 cp = cpbuf;
00877 goto pr_tail;
00878 }
00879
00880
00881
00882
00883
00884
00885 prec = 1;
00886 cp = arg->stptr;
00887 goto pr_tail;
00888 case 's':
00889 need_format = FALSE;
00890 if (zero_flag && ! lj)
00891 fill = zero_string;
00892 parse_next_arg();
00893 arg = force_string(arg);
00894 if (! have_prec || prec > arg->stlen)
00895 prec = arg->stlen;
00896 cp = arg->stptr;
00897 goto pr_tail;
00898 case 'd':
00899 case 'i':
00900 need_format = FALSE;
00901 parse_next_arg();
00902 tmpval = force_number(arg);
00903
00904
00905
00906
00907
00908 if (have_prec && prec == 0 && tmpval == 0)
00909 goto pr_tail;
00910
00911 if (tmpval < 0) {
00912 if (tmpval < INTMAX_MIN)
00913 goto out_of_range;
00914 sgn = TRUE;
00915 uval = - (uintmax_t) (intmax_t) tmpval;
00916 } else {
00917
00918 if (! (tmpval <= UINTMAX_MAX))
00919 goto out_of_range;
00920 sgn = FALSE;
00921 uval = (uintmax_t) tmpval;
00922 }
00923 do {
00924 *--cp = (char) ('0' + uval % 10);
00925 uval /= 10;
00926 } while (uval > 0);
00927
00928
00929 if (have_prec) {
00930 while (cend - cp < prec)
00931 *--cp = '0';
00932 }
00933
00934 if (sgn)
00935 *--cp = '-';
00936 else if (signchar)
00937 *--cp = signchar;
00938
00939
00940
00941
00942
00943
00944
00945
00946 if (! lj
00947 && ((zero_flag && ! have_prec)
00948 || (fw == 0 && have_prec)))
00949 fill = zero_string;
00950 if (prec > fw)
00951 fw = prec;
00952 prec = cend - cp;
00953 if (fw > prec && ! lj && fill != sp
00954 && (*cp == '-' || signchar)) {
00955 bchunk_one(cp);
00956 cp++;
00957 prec--;
00958 fw--;
00959 }
00960 goto pr_tail;
00961 case 'X':
00962 chbuf = Uchbuf;
00963 case 'x':
00964 base += 6;
00965 case 'u':
00966 base += 2;
00967 case 'o':
00968 base += 8;
00969 need_format = FALSE;
00970 parse_next_arg();
00971 tmpval = force_number(arg);
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 if (! alt && have_prec && prec == 0 && tmpval == 0)
00986 goto pr_tail;
00987
00988 if (tmpval < 0) {
00989 if (tmpval < INTMAX_MIN)
00990 goto out_of_range;
00991 uval = (uintmax_t) (intmax_t) tmpval;
00992 } else {
00993
00994 if (! (tmpval <= UINTMAX_MAX))
00995 goto out_of_range;
00996 uval = (uintmax_t) tmpval;
00997 }
00998
00999
01000
01001
01002
01003
01004
01005
01006 if (! lj
01007 && ((zero_flag && ! have_prec)
01008 || (fw == 0 && have_prec)))
01009 fill = zero_string;
01010 do {
01011 *--cp = chbuf[uval % base];
01012 uval /= base;
01013 } while (uval > 0);
01014
01015
01016 if (have_prec) {
01017 while (cend - cp < prec)
01018 *--cp = '0';
01019 }
01020
01021 if (alt && tmpval != 0) {
01022 if (base == 16) {
01023 *--cp = cs1;
01024 *--cp = '0';
01025 if (fill != sp) {
01026 bchunk(cp, 2);
01027 cp += 2;
01028 fw -= 2;
01029 }
01030 } else if (base == 8)
01031 *--cp = '0';
01032 }
01033 base = 0;
01034 if (prec > fw)
01035 fw = prec;
01036 prec = cend - cp;
01037 pr_tail:
01038 if (! lj) {
01039 while (fw > prec) {
01040 bchunk_one(fill);
01041 fw--;
01042 }
01043 }
01044 bchunk(cp, (int) prec);
01045 while (fw > prec) {
01046 bchunk_one(fill);
01047 fw--;
01048 }
01049 s0 = s1;
01050 break;
01051
01052 out_of_range:
01053
01054 if (do_lint)
01055 lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"),
01056 tmpval, cs1);
01057 cs1 = 'g';
01058 goto format_float;
01059
01060 case 'g':
01061 case 'G':
01062 case 'e':
01063 case 'f':
01064 case 'E':
01065 need_format = FALSE;
01066 parse_next_arg();
01067 tmpval = force_number(arg);
01068 format_float:
01069 if (! have_prec)
01070 prec = DEFAULT_G_PRECISION;
01071 chksize(fw + prec + 9);
01072
01073 cp = cpbuf;
01074 *cp++ = '%';
01075 if (lj)
01076 *cp++ = '-';
01077 if (signchar)
01078 *cp++ = signchar;
01079 if (alt)
01080 *cp++ = '#';
01081 if (zero_flag)
01082 *cp++ = '0';
01083 strcpy(cp, "*.*");
01084 cp += 3;
01085 *cp++ = cs1;
01086 *cp = '\0';
01087 #ifndef GFMT_WORKAROUND
01088 (void) sprintf(obufout, cpbuf,
01089 (int) fw, (int) prec, (double) tmpval);
01090 #else
01091 if (cs1 == 'g' || cs1 == 'G')
01092 sgfmt(obufout, cpbuf, (int) alt,
01093 (int) fw, (int) prec, (double) tmpval);
01094 else
01095 (void) sprintf(obufout, cpbuf,
01096 (int) fw, (int) prec, (double) tmpval);
01097 #endif
01098 len = strlen(obufout);
01099 ofre -= len;
01100 obufout += len;
01101 s0 = s1;
01102 break;
01103 default:
01104 break;
01105 }
01106 if (toofew)
01107 fatal("%s\n\t`%s'\n\t%*s%s",
01108 _("not enough arguments to satisfy format string"),
01109 fmt_string, (int) (s1 - fmt_string - 1), "",
01110 _("^ ran out for this one"));
01111 }
01112 if (do_lint) {
01113 if (need_format)
01114 lintwarn(
01115 _("[s]printf: format specifier does not have control letter"));
01116 if (cur_arg < num_args)
01117 lintwarn(
01118 _("too many arguments supplied for format string"));
01119 }
01120 bchunk(s0, s1 - s0);
01121 r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
01122 r->flags |= TEMP;
01123
01124 for (i = 1; i < num_args; i++) {
01125 unref(the_args[i]);
01126 }
01127
01128 if (call_level-- > 1) {
01129 free(the_args);
01130 the_args = save_args;
01131 args_size = save_args_size;
01132 }
01133
01134 return r;
01135 }
01136
01137
01138
01139 NODE *
01140 do_sprintf(NODE *tree)
01141 {
01142 NODE *r;
01143 NODE *sfmt = force_string(tree_eval(tree->lnode));
01144
01145 r = format_tree(sfmt->stptr, sfmt->stlen, tree->rnode, tree->printf_count);
01146 free_temp(sfmt);
01147 return r;
01148 }
01149
01150
01151
01152
01153
01154
01155 static inline FILE *
01156 redirect_to_fp(NODE *tree, struct redirect **rpp)
01157 {
01158 int errflg;
01159 struct redirect *rp;
01160
01161 if (tree == NULL)
01162 return stdout;
01163
01164 rp = redirect(tree, &errflg);
01165 if (rp != NULL) {
01166 *rpp = rp;
01167 return rp->fp;
01168 }
01169
01170 return NULL;
01171 }
01172
01173
01174
01175 void
01176 do_printf(NODE *tree)
01177 {
01178 struct redirect *rp = NULL;
01179 register FILE *fp;
01180
01181 if (tree->lnode == NULL) {
01182 if (do_traditional) {
01183 if (do_lint)
01184 lintwarn(_("printf: no arguments"));
01185 return;
01186 }
01187 fatal(_("printf: no arguments"));
01188 }
01189
01190 fp = redirect_to_fp(tree->rnode, & rp);
01191 if (fp == NULL)
01192 return;
01193 tree->lnode->printf_count = tree->printf_count;
01194 tree = do_sprintf(tree->lnode);
01195 efwrite(tree->stptr, sizeof(char), tree->stlen, fp, "printf", rp, TRUE);
01196 if (rp != NULL && (rp->flag & RED_TWOWAY) != 0)
01197 fflush(rp->fp);
01198 free_temp(tree);
01199 }
01200
01201
01202
01203 NODE *
01204 do_sqrt(NODE *tree)
01205 {
01206 NODE *tmp;
01207 double arg;
01208
01209 tmp = tree_eval(tree->lnode);
01210 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
01211 lintwarn(_("sqrt: received non-numeric argument"));
01212 arg = (double) force_number(tmp);
01213 free_temp(tmp);
01214 if (arg < 0.0)
01215 warning(_("sqrt: called with negative argument %g"), arg);
01216 return tmp_number((AWKNUM) sqrt(arg));
01217 }
01218
01219
01220
01221 NODE *
01222 do_substr(NODE *tree)
01223 {
01224 NODE *t1, *t2, *t3;
01225 NODE *r;
01226 register size_t indx;
01227 size_t length;
01228 double d_index, d_length;
01229
01230 t1 = force_string(tree_eval(tree->lnode));
01231 t2 = tree_eval(tree->rnode->lnode);
01232 d_index = force_number(t2);
01233