blob: 01a5ccf423bde32c1683415e724d3b94f2e1b3fd [file] [log] [blame]
/*
* awk.h -- Definitions for gawk.
*/
/*
* Copyright (C) 1986, 1988, 1989 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ------------------------------ Includes ------------------------------ */
#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
//#include <varargs.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "regex.h"
/* ------------------- System Functions, Variables, etc ------------------- */
/* nasty nasty SunOS-ism */
#ifdef sparc
#include <alloca.h>
#else
extern char *alloca();
#endif
/*
* if you don't have vprintf, but you are BSD, the version defined in
* vprintf.c should do the trick. Otherwise, use this and cross your fingers.
*/
#if defined(VPRINTF_MISSING) && !defined(DOPRNT_MISSING) && !defined(BSDSTDIO)
#define vfprintf(fp,fmt,arg) _doprnt((fmt), (arg), (fp))
#endif
#if 0
#ifdef __STDC__
extern void *malloc(unsigned), *realloc(void *, unsigned);
/* LLVM - Changed this to match Linux/Solaris free() */
extern void free(void *);
/* LLVM - Fixed prototype */
extern char *getenv(const char *);
extern char *strcpy(char *, char *), *strcat(char *, char *), *strncpy(char *, char *, int);
extern int strcmp(char *, char *);
extern int strncmp(char *, char *, int);
extern int strncasecmp(char *, char *, int);
extern char *strerror(int);
extern char *strchr(char *, int);
extern int strlen(char *);
extern char *memcpy(char *, char *, int);
extern int memcmp(char *, char *, int);
extern char *memset(char *, int, int);
/* extern int fprintf(FILE *, char *, ...); */
extern int fprintf();
extern int vfprintf();
#ifndef MSDOS
extern unsigned int fwrite(const void *, unsigned int, unsigned int, FILE *);
#endif
extern int fflush(FILE *);
extern int fclose(FILE *);
extern int pclose(FILE *);
#ifndef MSDOS
extern int fputs(const char *, FILE *);
#endif
extern void abort();
extern int isatty(int);
extern void exit(int);
/* LLVM - Fixed prototype */
extern int system(const char *);
extern int sscanf(/* char *, char *, ... */);
/* LLVM - Fixed prototype */
extern double atof(const char *);
extern int fstat(int, struct stat *);
extern off_t lseek(int, off_t, int);
extern int fseek(FILE *, long, int);
extern int close(int);
#endif
/* LLVM - Get rid of these prototypes */
#if 0
extern int open();
extern int pipe(int *);
extern int dup2(int, int);
#endif
#if 0
#ifndef MSDOS
extern int unlink(char *);
#endif
extern int fork();
extern int execl(/* char *, char *, ... */);
extern int read(int, char *, int);
extern int wait(int *);
extern void _exit(int);
#else
extern void _exit();
extern int wait();
extern int read();
extern int execl();
extern int fork();
extern int unlink();
extern int dup2();
extern int pipe();
extern int open();
extern int close();
extern int fseek();
extern off_t lseek();
extern int fstat();
extern void exit();
extern int system();
extern int isatty();
extern void abort();
extern int fputs();
extern int fclose();
extern int pclose();
extern int fflush();
extern int fwrite();
extern int fprintf();
extern int vfprintf();
extern int sscanf();
extern char *malloc(), *realloc();
extern void free();
extern char *getenv();
extern int strcmp();
extern int strncmp();
extern int strncasecmp();
extern int strlen();
extern char *strcpy(), *strcat(), *strncpy();
extern char *memset();
extern int memcmp();
extern char *memcpy();
extern char *strerror();
extern char *strchr();
extern double atof();
#endif
#endif
#ifndef MSDOS
extern int errno;
#endif /* MSDOS */
/* ------------------ Constants, Structures, Typedefs ------------------ */
#define AWKNUM double
typedef enum {
/* illegal entry == 0 */
Node_illegal,
/* binary operators lnode and rnode are the expressions to work on */
Node_times,
Node_quotient,
Node_mod,
Node_plus,
Node_minus,
Node_cond_pair, /* conditional pair (see Node_line_range) */
Node_subscript,
Node_concat,
Node_exp,
/* unary operators subnode is the expression to work on */
/*10*/ Node_preincrement,
Node_predecrement,
Node_postincrement,
Node_postdecrement,
Node_unary_minus,
Node_field_spec,
/* assignments lnode is the var to assign to, rnode is the exp */
Node_assign,
Node_assign_times,
Node_assign_quotient,
Node_assign_mod,
/*20*/ Node_assign_plus,
Node_assign_minus,
Node_assign_exp,
/* boolean binaries lnode and rnode are expressions */
Node_and,
Node_or,
/* binary relationals compares lnode and rnode */
Node_equal,
Node_notequal,
Node_less,
Node_greater,
Node_leq,
/*30*/ Node_geq,
Node_match,
Node_nomatch,
/* unary relationals works on subnode */
Node_not,
/* program structures */
Node_rule_list, /* lnode is a rule, rnode is rest of list */
Node_rule_node, /* lnode is pattern, rnode is statement */
Node_statement_list, /* lnode is statement, rnode is more list */
Node_if_branches, /* lnode is to run on true, rnode on false */
Node_expression_list, /* lnode is an exp, rnode is more list */
Node_param_list, /* lnode is a variable, rnode is more list */
/* keywords */
/*40*/ Node_K_if, /* lnode is conditonal, rnode is if_branches */
Node_K_while, /* lnode is condtional, rnode is stuff to run */
Node_K_for, /* lnode is for_struct, rnode is stuff to run */
Node_K_arrayfor, /* lnode is for_struct, rnode is stuff to run */
Node_K_break, /* no subs */
Node_K_continue, /* no stuff */
Node_K_print, /* lnode is exp_list, rnode is redirect */
Node_K_printf, /* lnode is exp_list, rnode is redirect */
Node_K_next, /* no subs */
Node_K_exit, /* subnode is return value, or NULL */
Node_K_do, /* lnode is conditional, rnode stuff to run */
Node_K_return,
Node_K_delete,
Node_K_getline,
Node_K_function, /* lnode is statement list, rnode is params */
/* I/O redirection for print statements */
Node_redirect_output, /* subnode is where to redirect */
Node_redirect_append, /* subnode is where to redirect */
Node_redirect_pipe, /* subnode is where to redirect */
Node_redirect_pipein, /* subnode is where to redirect */
Node_redirect_input, /* subnode is where to redirect */
/* Variables */
Node_var, /* rnode is value, lnode is array stuff */
Node_var_array, /* array is ptr to elements, asize num of
* eles */
Node_val, /* node is a value - type in flags */
/* Builtins subnode is explist to work on, proc is func to call */
Node_builtin,
/*
* pattern: conditional ',' conditional ; lnode of Node_line_range
* is the two conditionals (Node_cond_pair), other word (rnode place)
* is a flag indicating whether or not this range has been entered.
*/
Node_line_range,
/*
* boolean test of membership in array lnode is string-valued
* expression rnode is array name
*/
Node_in_array,
Node_func, /* lnode is param. list, rnode is body */
Node_func_call, /* lnode is name, rnode is argument list */
Node_cond_exp, /* lnode is conditonal, rnode is if_branches */
Node_regex,
Node_hashnode,
Node_ahash,
} NODETYPE;
/*
* NOTE - this struct is a rather kludgey -- it is packed to minimize
* space usage, at the expense of cleanliness. Alter at own risk.
*/
typedef struct exp_node {
union {
struct {
union {
struct exp_node *lptr;
char *param_name;
char *retext;
struct exp_node *nextnode;
} l;
union {
struct exp_node *rptr;
struct exp_node *(*pptr) ();
struct re_pattern_buffer *preg;
struct for_loop_header *hd;
struct exp_node **av;
int r_ent; /* range entered */
} r;
char *name;
short number;
unsigned char recase;
} nodep;
struct {
AWKNUM fltnum; /* this is here for optimal packing of
* the structure on many machines
*/
char *sp;
short slen;
unsigned char sref;
} val;
struct {
struct exp_node *next;
char *name;
int length;
struct exp_node *value;
} hash;
#define hnext sub.hash.next
#define hname sub.hash.name
#define hlength sub.hash.length
#define hvalue sub.hash.value
struct {
struct exp_node *next;
struct exp_node *name;
struct exp_node *value;
} ahash;
#define ahnext sub.ahash.next
#define ahname sub.ahash.name
#define ahvalue sub.ahash.value
} sub;
NODETYPE type;
unsigned char flags;
# define MEM 0x7
# define MALLOC 1 /* can be free'd */
# define TEMP 2 /* should be free'd */
# define PERM 4 /* can't be free'd */
# define VAL 0x18
# define NUM 8 /* numeric value is valid */
# define STR 16 /* string value is valid */
# define NUMERIC 32 /* entire field is numeric */
} NODE;
#define lnode sub.nodep.l.lptr
#define nextp sub.nodep.l.nextnode
#define rnode sub.nodep.r.rptr
#define source_file sub.nodep.name
#define source_line sub.nodep.number
#define param_cnt sub.nodep.number
#define param sub.nodep.l.param_name
#define subnode lnode
#define proc sub.nodep.r.pptr
#define reexp lnode
#define rereg sub.nodep.r.preg
#define re_case sub.nodep.recase
#define re_text sub.nodep.l.retext
#define forsub lnode
#define forloop rnode->sub.nodep.r.hd
#define stptr sub.val.sp
#define stlen sub.val.slen
#define stref sub.val.sref
#define valstat flags
#define numbr sub.val.fltnum
#define var_value lnode
#define var_array sub.nodep.r.av
#define condpair lnode
#define triggered sub.nodep.r.r_ent
#define HASHSIZE 101
typedef struct for_loop_header {
NODE *init;
NODE *cond;
NODE *incr;
} FOR_LOOP_HEADER;
/* for "for(iggy in foo) {" */
struct search {
int numleft;
NODE **arr_ptr;
NODE *bucket;
NODE *retval;
};
/* for faster input, bypass stdio */
typedef struct iobuf {
int fd;
char *buf;
char *off;
int size; /* this will be determined by an fstat() call */
int cnt;
char *secbuf;
int secsiz;
int flag;
# define IOP_IS_TTY 1
} IOBUF;
/*
* structure used to dynamically maintain a linked-list of open files/pipes
*/
struct redirect {
int flag;
# define RED_FILE 1
# define RED_PIPE 2
# define RED_READ 4
# define RED_WRITE 8
# define RED_APPEND 16
# define RED_NOBUF 32
char *value;
FILE *fp;
IOBUF *iop;
int pid;
int status;
long offset; /* used for dynamic management of open files */
struct redirect *prev;
struct redirect *next;
};
/* longjmp return codes, must be nonzero */
/* Continue means either for loop/while continue, or next input record */
#define TAG_CONTINUE 1
/* Break means either for/while break, or stop reading input */
#define TAG_BREAK 2
/* Return means return from a function call; leave value in ret_node */
#define TAG_RETURN 3
#ifdef MSDOS
#define HUGE 0x7fff
#else
#define HUGE 0x7fffffff
#endif
/* -------------------------- External variables -------------------------- */
/* gawk builtin variables */
extern NODE *FS_node, *NF_node, *RS_node, *NR_node;
extern NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
extern NODE *FNR_node, *RLENGTH_node, *RSTART_node, *SUBSEP_node;
extern NODE *IGNORECASE_node;
extern NODE **stack_ptr;
extern NODE *Nnull_string;
extern NODE *deref;
extern NODE **fields_arr;
extern int sourceline;
extern char *source;
extern NODE *expression_value;
extern NODE *variables[];
extern NODE *_t; /* used as temporary in tree_eval */
extern char *myname;
extern int node0_valid;
extern int field_num;
extern int strict;
/* ------------------------- Pseudo-functions ------------------------- */
#define is_identchar(c) (isalnum(c) || (c) == '_')
#define free_temp(n) if ((n)->flags&TEMP) { deref = (n); do_deref(); } else
#define tree_eval(t) (_t = (t),(_t) == NULL ? Nnull_string : \
((_t)->type == Node_val ? (_t) : r_tree_eval((_t))))
#define make_string(s,l) make_str_node((s),(l),0)
#define cant_happen() fatal("line %d, file: %s; bailing out", \
__LINE__, __FILE__);
#ifdef MEMDEBUG
#define memmsg(x,y,z,zz) fprintf(stderr, "malloc: %s: %s: %d %0x\n", z, x, y, zz)
#define free(s) fprintf(stderr, "free: s: %0x\n", s), do_free(s)
#else
#define memmsg(x,y,z,zz)
#endif
#ifdef BWGC
#define emalloc(var,ty,x,str) if ((var = (ty) GC_malloc((unsigned)((x)==0?1:(x)))) == NULL)\
fatal("%s: %s: can't allocate memory (%s)",\
(str), "var", strerror(errno)); else\
memmsg("var", x, str, var)
#define erealloc(var,ty,x,str) if((var=(ty)GC_realloc((char *)var,\
(unsigned)(x)))==NULL)\
fatal("%s: %s: can't allocate memory (%s)",\
(str), "var", strerror(errno)); else\
memmsg("re: var", x, str, var)
#else
#define emalloc(var,ty,x,str) if ((var = (ty) malloc((unsigned)(x))) == NULL)\
fatal("%s: %s: can't allocate memory (%s)",\
(str), "var", strerror(errno)); else\
memmsg("var", x, str, var)
#define erealloc(var,ty,x,str) if((var=(ty)realloc((char *)var,\
(unsigned)(x)))==NULL)\
fatal("%s: %s: can't allocate memory (%s)",\
(str), "var", strerror(errno)); else\
memmsg("re: var", x, str, var)
#endif BWGC
#ifdef DEBUG
#define force_number r_force_number
#define force_string r_force_string
#else
#ifdef lint
extern AWKNUM force_number();
#endif
#ifdef MSDOS
extern double _msc51bug;
#define force_number(n) (_msc51bug=(_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t)))
#else
#define force_number(n) (_t = (n),(_t->flags & NUM) ? _t->numbr : r_force_number(_t))
#endif
#define force_string(s) (_t = (s),(_t->flags & STR) ? _t : r_force_string(_t))
#endif
#define STREQ(a,b) (*(a) == *(b) && strcmp((a), (b)) == 0)
#define STREQN(a,b,n) ((n) && *(a) == *(b) && strncmp((a), (b), (n)) == 0)
#define WHOLELINE (node0_valid ? fields_arr[0] : *get_field(0,0))
/* ------------- Function prototypes or defs (as appropriate) ------------- */
#ifdef __STDC__
extern int parse_escape(char **);
extern int devopen(char *, char *);
extern struct re_pattern_buffer *make_regexp(NODE *, int);
extern struct re_pattern_buffer *mk_re_parse(char *, int);
extern NODE *variable(char *);
extern NODE *install(NODE **, char *, NODE *);
extern NODE *lookup(NODE **, char *);
extern NODE *make_name(char *, NODETYPE);
extern int interpret(NODE *);
extern NODE *r_tree_eval(NODE *);
extern void assign_number(NODE **, double);
extern int cmp_nodes(NODE *, NODE *);
extern struct redirect *redirect(NODE *, int *);
extern int flush_io(void);
extern void print_simple(NODE *, FILE *);
extern void warning(char *,...);
/* extern void warning(); */
extern void fatal(char *,...);
/* extern void fatal(); */
extern void set_record(char *, int);
extern NODE **get_field(int, int);
extern NODE **get_lhs(NODE *, int);
extern void do_deref(void );
extern struct search *assoc_scan(NODE *);
extern struct search *assoc_next(struct search *);
extern NODE **assoc_lookup(NODE *, NODE *);
extern double r_force_number(NODE *);
extern NODE *r_force_string(NODE *);
extern NODE *newnode(NODETYPE);
extern NODE *dupnode(NODE *);
extern NODE *make_number(double);
extern NODE *tmp_number(double);
extern NODE *make_str_node(char *, int, int);
extern NODE *tmp_string(char *, int);
extern char *re_compile_pattern(char *, int, struct re_pattern_buffer *);
extern int re_search(struct re_pattern_buffer *, char *, int, int, int, struct re_registers *);
extern void freenode(NODE *);
#else
extern int parse_escape();
extern void freenode();
extern int devopen();
extern struct re_pattern_buffer *make_regexp();
extern struct re_pattern_buffer *mk_re_parse();
extern NODE *variable();
extern NODE *install();
extern NODE *lookup();
extern int interpret();
extern NODE *r_tree_eval();
extern void assign_number();
extern int cmp_nodes();
extern struct redirect *redirect();
extern int flush_io();
extern void print_simple();
extern void warning();
extern void fatal();
extern void set_record();
extern NODE **get_field();
extern NODE **get_lhs();
extern void do_deref();
extern struct search *assoc_scan();
extern struct search *assoc_next();
extern NODE **assoc_lookup();
extern double r_force_number();
extern NODE *r_force_string();
extern NODE *newnode();
extern NODE *dupnode();
extern NODE *make_number();
extern NODE *tmp_number();
extern NODE *make_str_node();
extern NODE *tmp_string();
extern char *re_compile_pattern();
extern int re_search();
#endif
#if !defined(__STDC__) || __STDC__ <= 0
#define volatile
#endif
/* Figure out what '\a' really is. */
#ifdef __STDC__
#define BELL '\a' /* sure makes life easy, don't it? */
#else
# if 'z' - 'a' == 25 /* ascii */
# if 'a' != 97 /* machine is dumb enough to use mark parity */
# define BELL '\207'
# else
# define BELL '\07'
# endif
# else
# define BELL '\057'
# endif
#endif
#ifndef SIGTYPE
#define SIGTYPE void
#endif
extern char casetable[]; /* for case-independent regexp matching */
#ifdef BWGC
#define malloc(n) GC_malloc((n)==0?1:(n))
#endif
#ifdef IGNOREFREE
#define free(ptr) {};
#endif