📄 builtin.c
字号:
/* * builtin.c - Builtin functions and various utility procedures *//* * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Progamming Language. * * GAWK is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * GAWK is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GAWK; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "awk.h"#ifndef SRANDOM_PROTOextern void srandom P((int seed));#endif#ifndef linuxextern char *initstate P((unsigned seed, char *state, int n));extern char *setstate P((char *state));extern long random P((void));#endifextern NODE **fields_arr;extern int output_is_tty;static NODE *sub_common P((NODE *tree, int global));#ifdef GFMT_WORKAROUNDchar *gfmt P((double g, int prec, char *buf));#endif#ifdef _CRAY/* Work around a problem in conversion of doubles to exact integers. */#include <float.h>#define Floor(n) floor((n) * (1.0 + DBL_EPSILON))#define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))/* Force the standard C compiler to use the library math functions. */extern double exp(double);double (*Exp)() = exp;#define exp(x) (*Exp)(x)extern double log(double);double (*Log)() = log;#define log(x) (*Log)(x)#else#define Floor(n) floor(n)#define Ceil(n) ceil(n)#endifstatic voidefwrite(ptr, size, count, fp, from, rp, flush)void *ptr;unsigned size, count;FILE *fp;char *from;struct redirect *rp;int flush;{ errno = 0; if (fwrite(ptr, size, count, fp) != count) goto wrerror; if (flush && ((fp == stdout && output_is_tty) || (rp && (rp->flag & RED_NOBUF)))) { fflush(fp); if (ferror(fp)) goto wrerror; } return; wrerror: fatal("%s to \"%s\" failed (%s)", from, rp ? rp->value : "standard output", errno ? strerror(errno) : "reason unknown");}/* Builtin functions */NODE *do_exp(tree)NODE *tree;{ NODE *tmp; double d, res;#ifndef exp double exp P((double));#endif tmp= tree_eval(tree->lnode); d = force_number(tmp); free_temp(tmp); errno = 0; res = exp(d); if (errno == ERANGE) warning("exp argument %g is out of range", d); return tmp_number((AWKNUM) res);}NODE *do_index(tree)NODE *tree;{ NODE *s1, *s2; register char *p1, *p2; register int l1, l2; long ret; s1 = tree_eval(tree->lnode); s2 = tree_eval(tree->rnode->lnode); force_string(s1); force_string(s2); p1 = s1->stptr; p2 = s2->stptr; l1 = s1->stlen; l2 = s2->stlen; ret = 0; if (IGNORECASE) { while (l1) { if (l2 > l1) break; if (casetable[(int)*p1] == casetable[(int)*p2] && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) { ret = 1 + s1->stlen - l1; break; } l1--; p1++; } } else { while (l1) { if (l2 > l1) break; if (*p1 == *p2 && (l2 == 1 || STREQN(p1, p2, l2))) { ret = 1 + s1->stlen - l1; break; } l1--; p1++; } } free_temp(s1); free_temp(s2); return tmp_number((AWKNUM) ret);}NODE *do_int(tree)NODE *tree;{ NODE *tmp; double floor P((double)); double ceil P((double)); double d; tmp = tree_eval(tree->lnode); d = force_number(tmp); if (d >= 0) d = Floor(d); else d = Ceil(d); free_temp(tmp); return tmp_number((AWKNUM) d);}NODE *do_length(tree)NODE *tree;{ NODE *tmp; int len; tmp = tree_eval(tree->lnode); len = force_string(tmp)->stlen; free_temp(tmp); return tmp_number((AWKNUM) len);}NODE *do_log(tree)NODE *tree;{ NODE *tmp;#ifndef log double log P((double));#endif double d, arg; tmp = tree_eval(tree->lnode); arg = (double) force_number(tmp); if (arg < 0.0) warning("log called with negative argument %g", arg); d = log(arg); free_temp(tmp); return tmp_number((AWKNUM) d);}/* %e and %f formats are not properly implemented. Someone should fix them *//* Actually, this whole thing should be reimplemented. */NODE *do_sprintf(tree)NODE *tree;{#define bchunk(s,l) if(l) {\ while((l)>ofre) {\ erealloc(obuf, char *, osiz*2, "do_sprintf");\ ofre+=osiz;\ osiz*=2;\ }\ memcpy(obuf+olen,s,(l));\ olen+=(l);\ ofre-=(l);\ } /* Is there space for something L big in the buffer? */#define chksize(l) if((l)>ofre) {\ erealloc(obuf, char *, osiz*2, "do_sprintf");\ ofre+=osiz;\ osiz*=2;\ } /* * Get the next arg to be formatted. If we've run out of args, * return "" (Null string) */#define parse_next_arg() {\ if(!carg) { toofew = 1; break; }\ else {\ arg=tree_eval(carg->lnode);\ carg=carg->rnode;\ }\ } NODE *r; int toofew = 0; char *obuf; int osiz, ofre, olen; static char chbuf[] = "0123456789abcdef"; static char sp[] = " "; char *s0, *s1; int n0; NODE *sfmt, *arg; register NODE *carg; long fw, prec, lj, alt, big; long *cur; long val;#ifdef sun386 /* Can't cast unsigned (int/long) from ptr->value */ long tmp_uval; /* on 386i 4.0.1 C compiler -- it just hangs */#endif unsigned long uval; int sgn; int base; char cpbuf[30]; /* if we have numbers bigger than 30 */ char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */ char *cp; char *fill; double tmpval; char *pr_str; int ucasehex = 0; char signchar = 0; int len; emalloc(obuf, char *, 120, "do_sprintf"); osiz = 120; ofre = osiz - 1; olen = 0; sfmt = tree_eval(tree->lnode); sfmt = force_string(sfmt); carg = tree->rnode; for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) { if (*s1 != '%') { s1++; continue; } bchunk(s0, s1 - s0); s0 = s1; cur = &fw; fw = 0; prec = 0; lj = alt = big = 0; fill = sp; cp = cend; s1++;retry: --n0; switch (*s1++) { case '%': bchunk("%", 1); s0 = s1; break; case '0': if (fill != sp || lj) goto lose; if (cur == &fw) fill = "0"; /* FALL through */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (cur == 0) goto lose; *cur = s1[-1] - '0'; while (n0 > 0 && *s1 >= '0' && *s1 <= '9') { --n0; *cur = *cur * 10 + *s1++ - '0'; } goto retry; case '*': if (cur == 0) goto lose; parse_next_arg(); *cur = force_number(arg); free_temp(arg); goto retry; case ' ': /* print ' ' or '-' */ case '+': /* print '+' or '-' */ signchar = *(s1-1); goto retry; case '-': if (lj || fill != sp) goto lose; lj++; goto retry; case '.': if (cur != &fw) goto lose; cur = ≺ goto retry; case '#': if (alt) goto lose; alt++; goto retry; case 'l': if (big) goto lose; big++; goto retry; case 'c': parse_next_arg(); if (arg->flags & NUMBER) {#ifdef sun386 tmp_uval = arg->numbr; uval= (unsigned long) tmp_uval;#else uval = (unsigned long) arg->numbr;#endif cpbuf[0] = uval; prec = 1; pr_str = cpbuf; goto dopr_string; } if (! prec) prec = 1; else if (prec > arg->stlen) prec = arg->stlen; pr_str = arg->stptr; goto dopr_string; case 's': parse_next_arg(); arg = force_string(arg); if (!prec || prec > arg->stlen) prec = arg->stlen; pr_str = arg->stptr; dopr_string: if (fw > prec && !lj) { while (fw > prec) { bchunk(sp, 1); fw--; } } bchunk(pr_str, (int) prec); if (fw > prec) { while (fw > prec) { bchunk(sp, 1); fw--; } } s0 = s1; free_temp(arg); break; case 'd': case 'i': parse_next_arg(); val = (long) force_number(arg); free_temp(arg); if (val < 0) { sgn = 1; val = -val; } else sgn = 0; do { *--cp = '0' + val % 10; val /= 10; } while (val); if (sgn) *--cp = '-'; else if (signchar) *--cp = signchar; if (prec > fw) fw = prec; prec = cend - cp; if (fw > prec && !lj) { if (fill != sp && (*cp == '-' || signchar)) { bchunk(cp, 1); cp++; prec--; fw--; } while (fw > prec) { bchunk(fill, 1); fw--; } } bchunk(cp, (int) prec); if (fw > prec) { while (fw > prec) { bchunk(fill, 1); fw--; } } s0 = s1; break; case 'u': base = 10; goto pr_unsigned; case 'o': base = 8; goto pr_unsigned; case 'X': ucasehex = 1; case 'x': base = 16; goto pr_unsigned; pr_unsigned: parse_next_arg(); uval = (unsigned long) force_number(arg); free_temp(arg); do { *--cp = chbuf[uval % base]; if (ucasehex && isalpha(*cp)) *cp = toupper(*cp); uval /= base; } while (uval); if (alt && (base == 8 || base == 16)) { if (base == 16) { if (ucasehex) *--cp = 'X'; else *--cp = 'x'; } *--cp = '0'; } prec = cend - cp; if (fw > prec && !lj) { while (fw > prec) { bchunk(fill, 1); fw--; } } bchunk(cp, (int) prec); if (fw > prec) { while (fw > prec) { bchunk(fill, 1); fw--; } } s0 = s1; break; case 'g': parse_next_arg(); tmpval = force_number(arg); free_temp(arg); chksize(fw + prec + 9); /* 9==slop */ cp = cpbuf; *cp++ = '%'; if (lj) *cp++ = '-'; if (fill != sp) *cp++ = '0';#ifndef GFMT_WORKAROUND if (cur != &fw) { (void) strcpy(cp, "*.*g"); (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval); } else { (void) strcpy(cp, "*g"); (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval); }#else /* GFMT_WORKAROUND */ { char *gptr, gbuf[120];#define DEFAULT_G_PRECISION 6 if (fw + prec + 9 > sizeof gbuf) { /* 9==slop */ emalloc(gptr, char *, fw+prec+9, "do_sprintf(gfmt)"); } else gptr = gbuf; (void) gfmt((double) tmpval, cur != &fw ? (int) prec : DEFAULT_G_PRECISION, gptr); *cp++ = '*', *cp++ = 's', *cp = '\0'; (void) sprintf(obuf + olen, cpbuf, (int) fw, gptr); if (fill != sp && *gptr == ' ') { char *p = gptr; do { *p++ = '0'; } while (*p == ' '); } if (gptr != gbuf) free(gptr); }#endif /* GFMT_WORKAROUND */ len = strlen(obuf + olen); ofre -= len; olen += len; s0 = s1; break; case 'f': parse_next_arg(); tmpval = force_number(arg); free_temp(arg); chksize(fw + prec + 9); /* 9==slop */ cp = cpbuf; *cp++ = '%'; if (lj) *cp++ = '-'; if (fill != sp) *cp++ = '0'; if (cur != &fw) { (void) strcpy(cp, "*.*f"); (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval); } else { (void) strcpy(cp, "*f"); (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval); } len = strlen(obuf + olen); ofre -= len; olen += len; s0 = s1; break; case 'e': parse_next_arg(); tmpval = force_number(arg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -