1 /*--------------------------------------------------*
2  | var.h                                            |
3  | Header file for var.c, part of the Awka          |
4  | Library, Copyright 1999, Andrew Sumner.          |
5  | This file is covered by the GNU General Public   |
6  | License (GPL).                                   |
7  *--------------------------------------------------*/
8 
9 #ifndef _VAR_H
10 #define _VAR_H
11 
12 #define a_VARNUL 0  /* vars not set to anything yet */
13 #define a_VARDBL 1  /* vars set to double */
14 #define a_VARSTR 2  /* vars set to string */
15 #define a_VARARR 4  /* array variables */
16 #define a_VARREG 5  /* regular expressions */
17 #define a_VARUNK 6  /* contents of a split array & return from getline */
18 
19 #define a_DBLSET 7  /* indicates string var with double value set */
20 #define a_STRSET 8  /* indicates double var with string value set */
21 
22 /* builtin variables */
23 #define a_ARGC        0
24 #define a_ARGIND      1
25 #define a_ARGV        2
26 #define a_CONVFMT     3
27 #define a_ENVIRON     4
28 #define a_FILENAME    5
29 #define a_FNR         6
30 #define a_FS          7
31 #define a_NF          8
32 #define a_NR          9
33 #define a_OFMT        10
34 #define a_OFS         11
35 #define a_ORS         12
36 #define a_RLENGTH     13
37 #define a_RS          14
38 #define a_RSTART      15
39 #define a_RT          16
40 #define a_SUBSEP      17
41 #define a_DOL0        18
42 #define a_DOLN        19
43 #define a_FIELDWIDTHS 20
44 #define a_SAVEWIDTHS  21
45 #define a_SORTTYPE    22
46 #define a_PROCINFO    23
47 
48 #define a_BIVARS      24
49 
50 #define _RE_SPLIT   0
51 #define _RE_MATCH   1
52 #define _RE_GSUB    2
53 
54 typedef struct {
55   double dval;          /* double value, set when type & a_DBLVAR */
56   char * ptr;           /* string value, except with array vars */
57   unsigned int slen;    /* length of ptr as returned by strlen */
58   unsigned int allc;    /* space mallocated for ptr */
59   char type;            /* records current cast of variable */
60   char type2;           /* for string vars, TRUE if dval is set */
61   char temp;            /* TRUE if a temporary variable */
62 } a_VAR;
63 
64 typedef struct {
65   a_VAR *var[256];
66   int used;
67 } a_VARARG;
68 
69 void          awka_killvar( a_VAR * );
70 a_VAR *       _awka_getdval( a_VAR *, char *, int );
71 a_VAR *       _awka_setdval( a_VAR *, char *, int );
72 char *        _awka_getsval( a_VAR *, char, char *, int );
73 char **       awka_setsval( a_VAR *, char *, int );
74 awka_regexp * _awka_getreval( a_VAR *, char *, int, char );
75 awka_regexp * _awka_compile_regexp_SPLIT(char *str, unsigned len);
76 awka_regexp * _awka_compile_regexp_MATCH(char *str, unsigned len);
77 awka_regexp * _awka_compile_regexp_GSUB(char *str, unsigned len);
78 a_VAR *       awka_strdcpy( a_VAR *, double d );
79 a_VAR *       awka_strscpy( a_VAR *, char *s );
80 double        awka_vardblset( a_VAR *, double d );
81 a_VAR *       awka_varcpy( a_VAR *, a_VAR * );
82 int           awka_vartrue( a_VAR *v );
83 double        awka_varcmp( a_VAR *, a_VAR * );
84 double        awka_dbl2varcmp( double, a_VAR * );
85 double        awka_var2dblcmp( a_VAR *, double );
86 int           awka_nullval( char * );
87 double        awka_str2pow( char * );
88 void          awka_parsecmdline(int first);
89 a_VAR *       awka_tmp_dbl2var(double);
90 char *        awka_tmp_dbl2str(double);
91 a_VAR *       awka_tmp_str2var(char *);
92 a_VAR *       awka_ro_str2var(char *);
93 a_VAR *       awka_tmp_str2revar(char *);
94 a_VAR *       awka_tmp_re2var(awka_regexp *r);
95 void          _awka_re2s(a_VAR *);
96 void          _awka_re2null(a_VAR *);
97 a_VAR *       awka_vardup(a_VAR *);
98 double        awka_postinc(a_VAR *);
99 double        awka_postdec(a_VAR *);
100 
101 #ifndef _INIT_C
102 extern a_VAR *a_bivar[a_BIVARS];
103 #else
104 a_VAR *a_bivar[a_BIVARS];
105 #endif
106 
107 #ifndef _VAR_C
108 extern char _awka_arg_change;
109 #endif
110 
111 #ifndef _ARRAY_C
112 extern char fs_or_fw, _awka_setdol0_len;
113 extern char _rebuild0, _rebuildn, _rebuild0_now;
114 #endif
115 
116 #define _awka_set_FW(v) \
117   if ((v) == a_bivar[a_FS]) \
118     fs_or_fw = 0; \
119   else if ((v) == a_bivar[a_FIELDWIDTHS]) \
120     fs_or_fw = 1;
121 
122 static int
awka_isadbl(char * s,int len)123 awka_isadbl( char *s, int len )
124 {
125   register char *p = s, dot = FALSE;
126 
127   /* while (*p == ' ') p++; */
128   for ( ;*p; p++)
129   {
130     if (*p == '.')
131     {
132       if (dot == TRUE)
133         return FALSE;
134       dot = TRUE;
135       continue;
136     }
137     if (*p == ' ') break;
138     if (!isdigit(*p)) return FALSE;
139   }
140 
141   if (!*p) return TRUE;
142 
143   /* while (*p == ' ') p++; */
144   if (*p) return FALSE;
145   return TRUE;
146 }
147 
148 static a_VAR *
awka_getdval(a_VAR * v,char * file,int line)149 awka_getdval( a_VAR *v, char *file, int line )
150 {
151   if (v->type == a_VARDBL || v->type2 == a_DBLSET)
152     return v;
153   return _awka_getdval(v, file, line);
154 }
155 
156 static a_VAR *
awka_setdval(a_VAR * v,char * file,int line)157 awka_setdval( a_VAR *v, char *file, int line )
158 {
159   v->type2 = 0;
160   if (v->type == a_VARDBL)
161     return v;
162 
163   return _awka_setdval(v, file, line);
164 }
165 
166 static char *
awka_getsval(a_VAR * v,char ofmt,char * file,int line)167 awka_getsval( a_VAR *v, char ofmt, char *file, int line )
168 {
169   if (v->type == a_VARSTR || v->type == a_VARUNK ||
170      (v->type == a_VARDBL && v->type2 == a_STRSET))
171     return v->ptr;
172   return _awka_getsval(v, ofmt, file, line );
173 }
174 
175 static char *
awka_getsvalP(a_VAR * v,char ofmt,char * file,int line)176 awka_getsvalP( a_VAR *v, char ofmt, char *file, int line )
177 {
178   if (v->type == a_VARSTR || v->type == a_VARUNK)
179     return v->ptr;
180   return _awka_getsval(v, ofmt, file, line );
181 }
182 
183 static awka_regexp *
awka_getreval(a_VAR * v,char * file,int line)184 awka_getreval( a_VAR *v, char *file, int line )
185 {
186   v->type2 = 0;
187   if (v->type == a_VARREG && v->ptr)
188     return (awka_regexp *) v->ptr;
189   return _awka_getreval(v, file, line, _RE_MATCH);
190 }
191 
192 static void
awka_forcestr(a_VAR * v)193 awka_forcestr( a_VAR *v )
194 {
195   v->type2 = 0;
196   if (v->type != a_VARSTR && v->type != a_VARUNK)
197     awka_setsval(v, __FILE__, __LINE__);
198   v->type = a_VARSTR;
199 }
200 
201 static a_VAR *
awka_argv()202 awka_argv()
203 {
204   _awka_arg_change = TRUE;
205   return a_bivar[a_ARGV];
206 }
207 
208 static a_VAR *
awka_argc()209 awka_argc()
210 {
211   _awka_arg_change = TRUE;
212   return a_bivar[a_ARGC];
213 }
214 
215 static void
awka_lcopy(a_VAR * va,a_VAR * vb)216 awka_lcopy(a_VAR *va, a_VAR *vb)
217 {
218   va->ptr = vb->ptr;
219   va->slen = vb->slen;
220   va->allc = 0;
221   va->dval = vb->dval;
222   va->type = vb->type;
223   va->type2 = vb->type2;
224 }
225 
226 #define awka_getd(v)  (awka_getdval((v),__FILE__,__LINE__)->dval)
227 #define awka_setd(v)  (awka_setdval((v),__FILE__,__LINE__)->dval)
228 #define awka_gets(v)  (awka_getsval((v),0,__FILE__,__LINE__))
229 #define awka_getsP(v) (awka_getsvalP((v),1,__FILE__,__LINE__))
230 #define awka_sets(v)  (*(awka_setsval((v),__FILE__,__LINE__)))
231 #define awka_getre(v) (awka_getreval((v),__FILE__,__LINE__))
232 
233 #define awka_gets1(v) ((v)->ptr && ((v)->type == a_VARSTR || (v)->type == a_VARUNK) ? (v)->ptr : _awka_getsval((v),0,__FILE__,__LINE__))
234 #define awka_gets1P(v) ((v)->ptr && ((v)->type == a_VARSTR || (v)->type == a_VARUNK) ? (v)->ptr : _awka_getsval((v),1,__FILE__,__LINE__))
235 #define awka_getd1(v) ((v)->type == a_VARDBL || (v)->type2 == a_DBLSET ? (v)->dval : _awka_getdval((v),__FILE__,__LINE__)->dval)
236 
237 #define awka_poi(v) (((v)->type == a_VARDBL && (v)->type2 != a_STRSET) ? ((v)->dval)++ : awka_postinc(v))
238 #define awka_pri(v) (((v)->type == a_VARDBL && (v)->type2 != a_STRSET) ? ++(v)->dval : ++awka_setd(v))
239 #define awka_pod(v) (((v)->type == a_VARDBL && (v)->type2 != a_STRSET) ? ((v)->dval)-- : awka_postdec(v))
240 #define awka_prd(v) (((v)->type == a_VARDBL && (v)->type2 != a_STRSET) ? --(v)->dval : --awka_setd(v))
241 
242 #define awka_varinit(v) { \
243        malloc( (void **) &(v), sizeof(a_VAR) ); \
244        (v)->dval = 0.0; \
245        (v)->temp = (v)->type2 = 0; \
246        (v)->type = a_VARNUL; \
247        (v)->slen = (v)->allc = 0; \
248        (v)->ptr = NULL; }
249 
250 a_VAR *  awka_argval(int, a_VAR *, int, int, a_VARARG *);
251 void    _awka_addfnvar(int, int, a_VAR *, int);
252 a_VAR * _awka_usefnvar(int, int);
253 a_VAR * _awka_addfncall(int);
254 void    _awka_retfn(int);
255 int     _awka_registerfn(char *, int);
256 
257 static a_VAR *
awka_fn_varinit(int fn_idx,int var_idx,int type)258 awka_fn_varinit(int fn_idx, int var_idx, int type)
259 {
260   a_VAR *var;
261 
262   if (!(var = _awka_usefnvar(fn_idx, var_idx)))
263   {
264     awka_varinit(var);
265     var->temp = 2;
266     _awka_addfnvar(fn_idx, var_idx, var, type);
267   }
268   return var;
269 }
270 
271 #ifdef MEM_DEBUG
272 char *awka_strcpy(a_VAR *v, char *s);
273 #else
274 static char *
awka_strcpy(a_VAR * v,char * s)275 awka_strcpy(a_VAR *v, char *s)
276 {
277   register int _slen = strlen(s)+1;
278   _awka_set_FW(v);
279   if (v->type == a_VARREG)
280     _awka_re2s(v);
281   if (v->type != a_VARSTR && v->type != a_VARUNK)
282     awka_setsval(v, __FILE__, __LINE__);
283   if (v->ptr && v->allc <= _slen)
284     v->allc = realloc( (void **) &v->ptr, _slen );
285   else if (!v->ptr)
286     v->allc = malloc( (void **) &v->ptr, _slen );
287   v->slen = _slen-1;
288   memcpy(v->ptr, s, _slen);
289   v->type = a_VARSTR;
290   v->type2 = 0;
291   if (v == a_bivar[a_DOL0])
292   {
293     _rebuild0_now = _rebuild0 = FALSE;
294     _rebuildn = _awka_setdol0_len = TRUE;
295   }
296   return v->ptr;
297 }
298 #endif
299 
300 static char *
awka_strncpy(a_VAR * v,char * s,int _slen)301 awka_strncpy(a_VAR *v, char *s, int _slen)
302 {
303   _awka_set_FW(v);
304   if (v->type == a_VARREG)
305     _awka_re2s(v);
306   if (v->type != a_VARSTR && v->type != a_VARUNK)
307     awka_setsval(v, __FILE__, __LINE__);
308   if (v->ptr && v->allc <= _slen+1)
309     v->allc = realloc( (void **) &v->ptr, _slen+1 );
310   else if (!v->ptr)
311     v->allc = malloc( (void **) &v->ptr, _slen+1 );
312   v->slen = _slen;
313   memcpy(v->ptr, s, _slen);
314   v->ptr[_slen] = '\0';
315   v->type = a_VARSTR;
316   v->type2 = 0;
317   return v->ptr;
318 }
319 
320 static void
awka_setstrlen(a_VAR * v,register int slen)321 awka_setstrlen(a_VAR *v, register int slen)
322 {
323   _awka_set_FW(v);
324   slen++;
325   if (v->type == a_VARREG)
326     _awka_re2s(v);
327   if (v->type != a_VARSTR && v->type != a_VARUNK)
328     awka_setsval(v, __FILE__, __LINE__);
329   if (v->ptr && v->allc < slen)
330     v->allc = realloc( (void **) &v->ptr, slen );
331   else if (!(v)->ptr)
332     v->allc = malloc( (void **) &v->ptr, slen );
333   v->slen = slen - 1;
334   v->type2 = 0;
335 }
336 
337 #define awka_strtrue(s) ((s)[0] != '\0' ? 1 : 0)
338 
339 static double
_awka_dnotzero(double d,char * file,int line)340 _awka_dnotzero(double d, char *file, int line)
341 {
342   if (d == 0.0)
343     awka_error("Math Error: Divide By Zero, file %s line %d.\n",file,line);
344   return d;
345 }
346 
347 #define awka_dnotzero(d) _awka_dnotzero(d, __FILE__, __LINE__)
348 
349 static double
awka_div(double d1,double d2)350 awka_div(double d1, double d2)
351 {
352   if (d2 == 0.0)
353     awka_error("Math Error: Divide By Zero");
354   return d1 / d2;
355 }
356 
357 #endif
358