void cast1_to_s(CELL * cp) { register Int lval; char xbuff[260]; switch (cp->type) { case C_NOINIT: null_str.ref_cnt++; cp->ptr = (PTR) & null_str; break; case C_DOUBLE: lval = d_to_I(cp->dval); if (lval == cp->dval) sprintf(xbuff, INT_FMT, lval); else sprintf(xbuff, string(CONVFMT)->str, cp->dval); cp->ptr = (PTR) new_STRING(xbuff); break; case C_STRING: return; case C_MBSTRN: case C_STRNUM: break; default: bozo("bad type on cast"); } cp->type = C_STRING; }
CELL* array_find( ARRAY A, CELL *cp, int create_flag) { ANODE *ap ; int redid ; if (A->size == 0 && !create_flag) /* eliminating this trivial case early avoids unnecessary conversions later */ return (CELL*) 0 ; switch (cp->type) { case C_DOUBLE: { double d = cp->dval ; Int ival = d_to_I(d) ; if ((double)ival == d) { if (A->type == AY_SPLIT) { if (ival >= 1 && ival <= (int) A->size) return (CELL*)A->ptr+(ival-1) ; if (!create_flag) return (CELL*) 0 ; convert_split_array_to_table(A) ; } else if (A->type == AY_NULL) make_empty_table(A, AY_INT) ; ap = find_by_ival(A, ival, create_flag, &redid) ; } else { /* convert to string */ char buff[260] ; STRING *sval ; sprintf(buff, string(CONVFMT)->str, d) ; sval = new_STRING(buff) ; ap = find_by_sval(A, sval, create_flag, &redid) ; free_STRING(sval) ; } } break ; case C_NOINIT: ap = find_by_sval(A, &null_str, create_flag, &redid) ; break ; default: ap = find_by_sval(A, string(cp), create_flag, &redid) ; break ; } return ap ? &ap->cell : (CELL *) 0 ; }
static void print_cell(CELL *p, FILE *fp) { size_t len; switch (p->type) { case C_NOINIT: break; case C_FIELDWIDTHS: case C_MBSTRN: case C_STRING: case C_STRNUM: switch (len = string(p)->len) { case 0: break; case 1: putc(string(p)->str[0], fp); break; default: fwrite(string(p)->str, (size_t) 1, len, fp); } break; case C_DOUBLE: { Int ival = d_to_I(p->dval); /* integers print as "%[l]d" */ if ((double) ival == p->dval) fprintf(fp, INT_FMT, ival); else fprintf(fp, string(OFMT)->str, p->dval); } break; default: bozo("bad cell passed to print_cell"); } }
static void build_field0(void) { #ifdef DEBUG if (nf < 0) bozo("nf <0 in build_field0"); #endif cell_destroy(field + 0); if (nf == 0) { field[0].type = C_STRING; field[0].ptr = (PTR) & null_str; null_str.ref_cnt++; } else if (nf == 1) { cellcpy(field, field + 1); } else { CELL c; STRING *ofs, *tail; size_t len; register CELL *cp; register char *p, *q; int cnt; CELL **fbp, *cp_limit; cast1_to_s(cellcpy(&c, OFS)); ofs = (STRING *) c.ptr; cast1_to_s(cellcpy(&c, field_ptr(nf))); tail = (STRING *) c.ptr; cnt = nf - 1; len = ((size_t) cnt) * ofs->len + tail->len; fbp = fbank; cp_limit = field + FBANK_SZ; cp = field + 1; while (cnt-- > 0) { if (cp->type < C_STRING) { /* use the string field temporarily */ if (cp->type == C_NOINIT) { cp->ptr = (PTR) & null_str; null_str.ref_cnt++; } else { /* its a double */ Int ival; char xbuff[260]; ival = d_to_I(cp->dval); if (ival == cp->dval) sprintf(xbuff, INT_FMT, ival); else sprintf(xbuff, string(CONVFMT)->str, cp->dval); cp->ptr = (PTR) new_STRING(xbuff); } } len += string(cp)->len; if (++cp == cp_limit) { cp = *++fbp; cp_limit = cp + FBANK_SZ; } } field[0].type = C_STRING; field[0].ptr = (PTR) new_STRING0(len); p = string(field)->str; /* walk it again , putting things together */ cnt = nf - 1; fbp = fbank; cp = field + 1; cp_limit = field + FBANK_SZ; while (cnt-- > 0) { memcpy(p, string(cp)->str, string(cp)->len); p += string(cp)->len; /* if not really string, free temp use of ptr */ if (cp->type < C_STRING) { free_STRING(string(cp)); } if (++cp == cp_limit) { cp = *++fbp; cp_limit = cp + FBANK_SZ; } /* add the separator */ q = ofs->str; while (*q) *p++ = *q++; } /* tack tail on the end */ memcpy(p, tail->str, tail->len); /* cleanup */ free_STRING(tail); free_STRING(ofs); } }
int yylex(void) { register int c; token_lineno = lineno; #ifdef NO_LEAKS memset(&yylval, 0, sizeof(yylval)); #endif reswitch: switch (scan_code[NextUChar(c)]) { case 0: ct_ret(EOF); case SC_SPACE: goto reswitch; case SC_COMMENT: eat_comment(); goto reswitch; case SC_NL: lineno++; eat_nl(); ct_ret(NL); case SC_ESCAPE: while (scan_code[NextUChar(c)] == SC_SPACE) { ; /* empty */ }; if (c == '\n') { token_lineno = ++lineno; goto reswitch; } if (c == 0) ct_ret(EOF); un_next(); yylval.ival = '\\'; ct_ret(UNEXPECTED); case SC_SEMI_COLON: eat_nl(); ct_ret(SEMI_COLON); case SC_LBRACE: eat_nl(); brace_cnt++; ct_ret(LBRACE); case SC_PLUS: switch (next()) { case '+': yylval.ival = '+'; string_buff[0] = string_buff[1] = '+'; string_buff[2] = 0; ct_ret(INC_or_DEC); case '=': ct_ret(ADD_ASG); default: un_next(); ct_ret(PLUS); } case SC_MINUS: switch (next()) { case '-': yylval.ival = '-'; string_buff[0] = string_buff[1] = '-'; string_buff[2] = 0; ct_ret(INC_or_DEC); case '=': ct_ret(SUB_ASG); default: un_next(); ct_ret(MINUS); } case SC_COMMA: eat_nl(); ct_ret(COMMA); case SC_MUL: test1_ret('=', MUL_ASG, MUL); case SC_DIV: { static const int can_precede_div[] = {DOUBLE, STRING_, RPAREN, ID, D_ID, RE, RBOX, FIELD, GETLINE, INC_or_DEC, -1}; const int *p = can_precede_div; do { if (*p == current_token) { if (*p != INC_or_DEC) { test1_ret('=', DIV_ASG, DIV); } if (next() == '=') { un_next(); ct_ret(collect_RE()); } } } while (*++p != -1); ct_ret(collect_RE()); } case SC_MOD: test1_ret('=', MOD_ASG, MOD); case SC_POW: test1_ret('=', POW_ASG, POW); case SC_LPAREN: paren_cnt++; ct_ret(LPAREN); case SC_RPAREN: if (--paren_cnt < 0) { compile_error("extra ')'"); paren_cnt = 0; goto reswitch; } ct_ret(RPAREN); case SC_LBOX: ct_ret(LBOX); case SC_RBOX: ct_ret(RBOX); case SC_MATCH: string_buff[1] = '~'; string_buff[0] = 0; yylval.ival = 1; ct_ret(MATCH); case SC_EQUAL: test1_ret('=', EQ, ASSIGN); case SC_NOT: /* ! */ if ((c = next()) == '~') { string_buff[0] = '!'; string_buff[1] = '~'; string_buff[2] = 0; yylval.ival = 0; ct_ret(MATCH); } else if (c == '=') ct_ret(NEQ); un_next(); ct_ret(NOT); case SC_LT: /* '<' */ if (next() == '=') ct_ret(LTE); else un_next(); if (getline_flag) { getline_flag = 0; ct_ret(IO_IN); } else ct_ret(LT); case SC_GT: /* '>' */ if (print_flag && paren_cnt == 0) { print_flag = 0; /* there are 3 types of IO_OUT -- build the error string in string_buff */ string_buff[0] = '>'; if (next() == '>') { yylval.ival = F_APPEND; string_buff[1] = '>'; string_buff[2] = 0; } else { un_next(); yylval.ival = F_TRUNC; string_buff[1] = 0; } return current_token = IO_OUT; } test1_ret('=', GTE, GT); case SC_OR: if (next() == '|') { eat_nl(); ct_ret(OR); } else { un_next(); if (print_flag && paren_cnt == 0) { print_flag = 0; yylval.ival = PIPE_OUT; string_buff[0] = '|'; string_buff[1] = 0; ct_ret(IO_OUT); } else ct_ret(PIPE); } case SC_AND: if (next() == '&') { eat_nl(); ct_ret(AND); } else { un_next(); yylval.ival = '&'; ct_ret(UNEXPECTED); } case SC_QMARK: ct_ret(QMARK); case SC_COLON: ct_ret(COLON); case SC_RBRACE: if (--brace_cnt < 0) { compile_error("extra '}'"); eat_semi_colon(); brace_cnt = 0; goto reswitch; } if ((c = current_token) == NL || c == SEMI_COLON || c == SC_FAKE_SEMI_COLON || c == RBRACE) { /* if the brace_cnt is zero , we've completed a pattern action block. If the user insists on adding a semi-colon on the same line we will eat it. Note what we do below: physical law -- conservation of semi-colons */ if (brace_cnt == 0) eat_semi_colon(); eat_nl(); ct_ret(RBRACE); } /* supply missing semi-colon to statement that precedes a '}' */ brace_cnt++; un_next(); current_token = SC_FAKE_SEMI_COLON; return SEMI_COLON; case SC_DIGIT: case SC_DOT: { double d; int flag; if ((d = collect_decimal(c, &flag)) == 0.0) { if (flag) ct_ret(flag); else yylval.ptr = (PTR) & double_zero; } else if (d == 1.0) { yylval.ptr = (PTR) & double_one; } else { yylval.ptr = (PTR) ZMALLOC(double); *(double *) yylval.ptr = d; } ct_ret(DOUBLE); } case SC_DOLLAR: /* '$' */ { double d; int flag; while (scan_code[NextUChar(c)] == SC_SPACE) { ; /* empty */ }; if (scan_code[c] != SC_DIGIT && scan_code[c] != SC_DOT) { un_next(); ct_ret(DOLLAR); } /* compute field address at compile time */ if ((d = collect_decimal(c, &flag)) <= 0.0) { if (flag) ct_ret(flag); /* an error */ else yylval.cp = &field[0]; } else { int ival = d_to_I(d); double dval = (double) ival; if (dval != d) { compile_error("$%g is invalid field index", d); } yylval.cp = field_ptr(ival); } ct_ret(FIELD); } case SC_DQUOTE: return current_token = collect_string(); case SC_IDCHAR: /* collect an identifier */ { char *p = string_buff + 1; SYMTAB *stp; string_buff[0] = (char) c; while (1) { CheckStringSize(p); c = scan_code[NextUChar(*p++)]; if (c != SC_IDCHAR && c != SC_DIGIT) break; } un_next(); *--p = 0; switch ((stp = find(string_buff))->type) { case ST_NONE: /* check for function call before defined */ if (next() == '(') { stp->type = ST_FUNCT; stp->stval.fbp = (FBLOCK *) zmalloc(sizeof(FBLOCK)); stp->stval.fbp->name = stp->name; stp->stval.fbp->code = (INST *) 0; stp->stval.fbp->size = 0; yylval.fbp = stp->stval.fbp; current_token = FUNCT_ID; } else { yylval.stp = stp; current_token = current_token == DOLLAR ? D_ID : ID; } un_next(); break; case ST_NR: NR_flag = 1; stp->type = ST_VAR; /* FALLTHRU */ case ST_VAR: case ST_ARRAY: case ST_LOCAL_NONE: case ST_LOCAL_VAR: case ST_LOCAL_ARRAY: yylval.stp = stp; current_token = current_token == DOLLAR ? D_ID : ID; break; case ST_ENV: stp->type = ST_ARRAY; stp->stval.array = new_ARRAY(); load_environ(stp->stval.array); yylval.stp = stp; current_token = current_token == DOLLAR ? D_ID : ID; break; case ST_FUNCT: yylval.fbp = stp->stval.fbp; current_token = FUNCT_ID; break; case ST_KEYWORD: current_token = stp->stval.kw; break; case ST_BUILTIN: yylval.bip = stp->stval.bip; current_token = BUILTIN; break; case ST_LENGTH: yylval.bip = stp->stval.bip; /* check for length alone, this is an ugly hack */ while (scan_code[NextUChar(c)] == SC_SPACE) { ; /* empty */ }; un_next(); current_token = c == '(' ? BUILTIN : LENGTH; break; case ST_FIELD: yylval.cp = stp->stval.cp; current_token = FIELD; break; default: bozo("find returned bad st type"); } return current_token; } case SC_UNEXPECTED: yylval.ival = c & 0xff; ct_ret(UNEXPECTED); } return 0; /* never get here make lint happy */ }
void array_delete( ARRAY A, CELL *cp) { ANODE *ap ; int redid ; if (A->size == 0) return ; switch(cp->type) { case C_DOUBLE : { double d = cp->dval ; Int ival = d_to_I(d) ; if ((double)ival == d) { if (A->type == AY_SPLIT) { if (ival >=1 && ival <= (int) A->size) convert_split_array_to_table(A) ; else return ; /* ival not in range */ } ap = find_by_ival(A, ival, NO_CREATE, &redid) ; if (ap) { /* remove from the front of the ilist */ DUAL_LINK *table = (DUAL_LINK*) A->ptr ; table[(unsigned) ap->ival & A->hmask].ilink = ap->ilink ; if (ap->sval) { ANODE *p, *q = 0 ; unsigned indx = (unsigned) ap->hval & A->hmask ; p = table[indx].slink ; while(p != ap) { q = p ; p = q->slink ; } if (q) q->slink = p->slink ; else table[indx].slink = p->slink ; free_STRING(ap->sval) ; } cell_destroy(&ap->cell) ; ZFREE(ap) ; if (--A->size == 0) array_clear(A) ; } return ; } else { /* get the string value */ char buff[260] ; STRING *sval ; sprintf(buff, string(CONVFMT)->str, d) ; sval = new_STRING(buff) ; ap = find_by_sval(A, sval, NO_CREATE, &redid) ; free_STRING(sval) ; } } break ; case C_NOINIT : ap = find_by_sval(A, &null_str, NO_CREATE, &redid) ; break ; default : ap = find_by_sval(A, string(cp), NO_CREATE, &redid) ; break ; } if (ap) { /* remove from the front of the slist */ DUAL_LINK *table = (DUAL_LINK*) A->ptr ; table[ap->hval & A->hmask].slink = ap->slink ; if (ap->ival != NOT_AN_IVALUE) { ANODE *p, *q = 0 ; unsigned indx = (unsigned) ap->ival & A->hmask ; p = table[indx].ilink ; while(p != ap) { q = p ; p = q->ilink ; } if (q) q->ilink = p->ilink ; else table[indx].ilink = p->ilink ; } free_STRING(ap->sval) ; cell_destroy(&ap->cell) ; ZFREE(ap) ; if (--A->size == 0) array_clear(A) ; } }
/* * Note: caller must do CELL cleanup. * The format parameter is modified, but restored. * * This routine does both printf and sprintf (if fp==0) */ static STRING * do_printf( FILE *fp, char *format, unsigned argcnt, /* number of args on eval stack */ CELL *cp) /* ptr to an array of arguments (on the eval stack) */ { char save; char *p; register char *q = format; register char *target; int l_flag, h_flag; /* seen %ld or %hd */ int ast_cnt; int ast[2]; UInt Uval = 0; Int Ival = 0; int sfmt_width, sfmt_prec, sfmt_flags, s_format; int num_conversion = 0; /* for error messages */ const char *who; /*ditto */ int pf_type = 0; /* conversion type */ PRINTER printer; /* pts at fprintf() or sprintf() */ STRING onechr; #ifdef SHORT_INTS char xbuff[256]; /* splice in l qualifier here */ #endif if (fp == (FILE *) 0) { /* doing sprintf */ target = sprintf_buff; printer = (PRINTER) sprintf; who = "sprintf"; } else { /* doing printf */ target = (char *) fp; /* will never change */ printer = (PRINTER) fprintf; who = "printf"; } while (1) { if (fp) { /* printf */ while (*q != '%') { if (*q == 0) { if (ferror(fp)) write_error(); /* return is ignored */ return (STRING *) 0; } else { putc(*q, fp); q++; } } } else { /* sprintf */ while (*q != '%') { if (*q == 0) { if (target > sprintf_limit) /* damaged */ { /* hope this works */ rt_overflow("sprintf buffer", (unsigned) (sprintf_limit - sprintf_buff)); } else { /* really done */ return new_STRING1(sprintf_buff, (size_t) (target - sprintf_buff)); } } else { *target++ = *q++; } } } /* *q == '%' */ num_conversion++; if (*++q == '%') { /* %% */ if (fp) putc(*q, fp); else *target++ = *q; q++; continue; } /* mark the '%' with p */ p = q - 1; /* eat the flags */ while (*q == '-' || *q == '+' || *q == ' ' || *q == '#' || *q == '0') q++; ast_cnt = 0; ast[0] = 0; if (*q == '*') { if (cp->type != C_DOUBLE) cast1_to_d(cp); ast[ast_cnt++] = d_to_i(cp++->dval); argcnt--; q++; } else while (scan_code[*(unsigned char *) q] == SC_DIGIT) q++; /* width is done */ if (*q == '.') { /* have precision */ q++; if (*q == '*') { if (cp->type != C_DOUBLE) cast1_to_d(cp); ast[ast_cnt++] = d_to_i(cp++->dval); argcnt--; q++; } else { while (scan_code[*(unsigned char *) q] == SC_DIGIT) q++; } } if (argcnt <= 0) rt_error("not enough arguments passed to %s(\"%s\")", who, format); l_flag = h_flag = 0; if (*q == 'l') { q++; l_flag = 1; } else if (*q == 'h') { q++; h_flag = 1; } switch (*q++) { case 's': if (l_flag + h_flag) bad_conversion(num_conversion, who, format); if (cp->type < C_STRING) cast1_to_s(cp); pf_type = PF_S; break; case 'c': if (l_flag + h_flag) bad_conversion(num_conversion, who, format); switch (cp->type) { case C_NOINIT: Ival = 0; break; case C_STRNUM: case C_DOUBLE: Ival = d_to_I(cp->dval); break; case C_STRING: /* fall thru to check for bad number formats */ //Ival = string(cp)->str[0]; //break; /* fall thru */ case C_FIELDWIDTHS: case C_MBSTRN: check_strnum(cp); Ival = ((cp->type == C_STRING) ? string(cp)->str[0] : d_to_I(cp->dval)); break; default: bozo("printf %c"); } onechr.len = 1; onechr.str[0] = (char) Ival; pf_type = PF_C; break; case 'd': case 'i': if (cp->type != C_DOUBLE) cast1_to_d(cp); Ival = d_to_I(cp->dval); pf_type = PF_D; break; case 'o': case 'x': case 'X': case 'u': if (cp->type != C_DOUBLE) cast1_to_d(cp); Uval = d_to_U(cp->dval); pf_type = PF_U; break; case 'e': case 'g': case 'f': case 'E': case 'G': if (h_flag + l_flag) bad_conversion(num_conversion, who, format); if (cp->type != C_DOUBLE) cast1_to_d(cp); pf_type = PF_F; break; default: bad_conversion(num_conversion, who, format); } save = *q; *q = 0; #ifdef SHORT_INTS if (pf_type == PF_D) { /* need to splice in long modifier */ strcpy(xbuff, p); if (l_flag) /* do nothing */ ; else { int k = q - p; if (h_flag) { Ival = (short) Ival; /* replace the 'h' with 'l' (really!) */ xbuff[k - 2] = 'l'; if (xbuff[k - 1] != 'd' && xbuff[k - 1] != 'i') Ival &= 0xffff; } else { /* the usual case */ xbuff[k] = xbuff[k - 1]; xbuff[k - 1] = 'l'; xbuff[k + 1] = 0; } } } #endif #define PUTS_C_ARGS target, fp, 0, &onechr, sfmt_width, sfmt_prec, sfmt_flags #define PUTS_S_ARGS target, fp, cp, 0, sfmt_width, sfmt_prec, sfmt_flags /* ready to call printf() */ s_format = 0; switch (AST(ast_cnt, pf_type)) { case AST(0, PF_C): /* FALLTHRU */ case AST(1, PF_C): /* FALLTHRU */ case AST(2, PF_C): s_format = 1; make_sfmt(p, ast, &sfmt_width, &sfmt_prec, &sfmt_flags); target = puts_sfmt(PUTS_C_ARGS); break; case AST(0, PF_S): /* FALLTHRU */ case AST(1, PF_S): /* FALLTHRU */ case AST(2, PF_S): s_format = 1; make_sfmt(p, ast, &sfmt_width, &sfmt_prec, &sfmt_flags); target = puts_sfmt(PUTS_S_ARGS); break; #ifdef SHORT_INTS #define FMT xbuff /* format in xbuff */ #else #define FMT p /* p -> format */ #endif case AST(0, PF_D): if (cp->dval > Max_Int && l_flag == 0 && h_flag == 0) { STRING *newp; char *np; newp = new_STRING0(strlen(p)+5); np = (char *) newp->str; while (*p != '\0') { if (*p == 'd' || *p == 'i') { *np++ = '.'; *np++ = '0'; *np++ = 'f'; ++p; } else *np++ = *p++; } np = '\0'; (*printer) ((PTR) target, newp->str, cp->dval); free_STRING(newp); } else (*printer) ((PTR) target, FMT, Ival); break; case AST(1, PF_D): (*printer) ((PTR) target, FMT, ast[0], Ival); break; case AST(2, PF_D): (*printer) ((PTR) target, FMT, ast[0], ast[1], Ival); break; case AST(0, PF_U): if (*(p+1) == 'u' && cp->dval > Max_Int ) { STRING *newp; char *np; newp = new_STRING0(strlen(p)+5); np = (char *) newp->str; while (*p != '\0') { if (*p == 'u') { *np++ = '.'; *np++ = '0'; *np++ = 'f'; ++p; } else *np++ = *p++; } np = '\0'; (*printer) ((PTR) target, newp->str, cp->dval); free_STRING(newp); } else (*printer) ((PTR) target, FMT, Uval); break; case AST(1, PF_U): (*printer) ((PTR) target, FMT, ast[0], Uval); break; case AST(2, PF_U): (*printer) ((PTR) target, FMT, ast[0], ast[1], Uval); break; #undef FMT case AST(0, PF_F): (*printer) ((PTR) target, p, cp->dval); break; case AST(1, PF_F): (*printer) ((PTR) target, p, ast[0], cp->dval); break; case AST(2, PF_F): (*printer) ((PTR) target, p, ast[0], ast[1], cp->dval); break; } if (fp == (FILE *) 0 && !s_format) { while (*target) target++; } *q = save; argcnt--; cp++; } }