1 /*------------------------------------------------------------*
2  | var.c                                                      |
3  | copyright 1999,  Andrew Sumner (andrewsumner@yahoo.com)    |
4  |                                                            |
5  | This is a source file for the awka package, a translator   |
6  | of the AWK programming language to ANSI C.                 |
7  |                                                            |
8  | This library is free software; you can redistribute it     |
9  | and/or modify it under the terms of the GNU General        |
10  | Public License (GPL).                                      |
11  |                                                            |
12  | This library is distributed in the hope that it will be    |
13  | useful, but WITHOUT ANY WARRANTY; without even the implied |
14  | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    |
15  | PURPOSE.                                                   |
16  *------------------------------------------------------------*/
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <limits.h>
22 #include <ctype.h>
23 
24 #define _VAR_C
25 #define _IN_LIBRARY
26 
27 #ifndef TRUE
28 #  define TRUE  1
29 #  define FALSE 0
30 #endif
31 char _awka_arg_change = FALSE;
32 
33 #include "libawka.h"
34 #include "number.h"
35 #include "garbage.h"
36 
37 struct _fnvar {
38   a_VAR **var;
39   char *status;
40   int used;
41   int prevused;
42   int allc;
43 };
44 
45 struct _fn {
46   char *fn;
47   struct _fnvar *fnvar;
48   int push;
49   int allc;
50   int nvar;
51 } *_awka_fn = NULL;
52 
53 int _awka_fn_allc = 0, _awka_fn_used = 0;
54 
55 a_VAR *
awka_argval(int fn_idx,a_VAR * var,int arg_no,int arg_count,a_VARARG * va)56 awka_argval(int fn_idx, a_VAR *var, int arg_no, int arg_count, a_VARARG *va)
57 {
58   a_VAR *ret;
59 
60   arg_no--;
61   if (fn_idx == -1 || arg_no >= arg_count || arg_no < 0)
62   {
63     _awka_tmpvar(ret);
64     awka_killvar(ret);
65     return ret;
66   }
67 
68   if (va->used == 0 || var->type != a_VARARR)
69     return var;
70 
71   if (va->used == 1)
72     return awka_arraysearch1( var,
73                               va->var[0],
74                               a_ARR_CREATE,
75                               TRUE );
76 
77   return awka_arraysearch( var,
78                            va,
79                            a_ARR_CREATE );
80 }
81 
82 int
_awka_registerfn(char * fn,int nvar)83 _awka_registerfn(char *fn, int nvar)
84 {
85   int i, j;
86 
87   for (i=0; i<_awka_fn_used; i++)
88     if (!strcmp(_awka_fn[i].fn, fn))
89       return i;
90 
91   if (i == _awka_fn_used)
92   {
93     if (_awka_fn_allc == 0)
94     {
95       _awka_fn_allc = 10;
96       malloc( &_awka_fn, 10 * sizeof(struct _fn));
97     }
98     else if (_awka_fn_used == _awka_fn_allc)
99     {
100       _awka_fn_allc += 10;
101       realloc( &_awka_fn, _awka_fn_allc * sizeof(struct _fn));
102     }
103 
104     _awka_fn_used++;
105     malloc( &_awka_fn[i].fn, strlen(fn)+1);
106     strcpy(_awka_fn[i].fn, fn);
107     _awka_fn[i].allc = 10;
108     _awka_fn[i].push = 0;
109     _awka_fn[i].nvar = nvar;
110     malloc( &_awka_fn[i].fnvar, 10 * sizeof(struct _fnvar));
111     for (j = 0; j<_awka_fn[i].allc; j++)
112     {
113       _awka_fn[i].fnvar[j].var = NULL;
114       _awka_fn[i].fnvar[j].status = NULL;
115       _awka_fn[i].fnvar[j].used = 0;
116       _awka_fn[i].fnvar[j].prevused = 0;
117       _awka_fn[i].fnvar[j].allc = 0;
118     }
119   }
120 
121   return i;
122 }
123 
124 /*
125  * addfnvar - this nonsense registers local variables
126  *            within user functions.
127  */
128 void
_awka_addfnvar(int i,int var_idx,a_VAR * var,int type)129 _awka_addfnvar(int i, int var_idx, a_VAR *var, int type)
130 {
131   register int j;
132 
133   j = _awka_fn[i].push-1;
134  _awka_fn[i].fnvar[j].used = (_awka_fn[i].fnvar[j].used <= var_idx ?
135                               var_idx + 1 : _awka_fn[i].fnvar[j].used);
136   _awka_fn[i].fnvar[j].var[var_idx] = var;
137   _awka_fn[i].fnvar[j].prevused = _awka_fn[i].fnvar[j].used;
138   _awka_fn[i].fnvar[j].status[var_idx] = type;
139   if (type == 2)
140     var->type = a_VARARR;
141 }
142 
143 a_VAR *
_awka_usefnvar(int i,int var_idx)144 _awka_usefnvar(int i, int var_idx)
145 {
146   register int j = _awka_fn[i].push-1;
147   a_VAR *var;
148 
149   if (_awka_fn[i].fnvar[j].prevused > var_idx)
150   {
151     var = _awka_fn[i].fnvar[j].var[ var_idx ];
152     _awka_fn[i].fnvar[j].used = (_awka_fn[i].fnvar[j].used <= var_idx ?
153                                  var_idx + 1 : _awka_fn[i].fnvar[j].used);
154     return var;
155   }
156   else
157     return NULL;
158 }
159 
160 /*
161  * awka_addfncall - denotes a call to a registered function, allocating
162  *                  space if necessary for its local variables.
163  */
164 a_VAR *
_awka_addfncall(int i)165 _awka_addfncall(int i)
166 {
167   register int j, k;
168   a_VAR *ret;
169 
170   _awka_tmpvar(ret);  /* bugfix for eiso */
171   _awka_gc_deeper();
172 
173   if (_awka_fn[i].push == _awka_fn[i].allc)
174   {
175     _awka_fn[i].allc += 10;
176     realloc( &_awka_fn[i].fnvar, _awka_fn[i].allc * sizeof(struct _fnvar));
177     for (j = _awka_fn[i].push; j<_awka_fn[i].allc; j++)
178     {
179       _awka_fn[i].fnvar[j].var = NULL;
180       _awka_fn[i].fnvar[j].used = 0;
181       _awka_fn[i].fnvar[j].prevused = 0;
182       _awka_fn[i].fnvar[j].allc = 0;
183     }
184   }
185 
186   j = _awka_fn[i].push;
187   _awka_fn[i].push++;
188   if (_awka_fn[i].fnvar[j].allc == 0 && _awka_fn[i].nvar)
189   {
190     _awka_fn[i].fnvar[j].allc = _awka_fn[i].nvar;
191     malloc( &_awka_fn[i].fnvar[j].var, _awka_fn[i].nvar * sizeof(a_VAR *));
192     malloc( &_awka_fn[i].fnvar[j].status, _awka_fn[i].nvar);
193     for (k=0; k<_awka_fn[i].nvar; k++)
194       _awka_fn[i].fnvar[j].var[k] = NULL;
195   }
196   if (ret->ptr)
197   {
198     if (ret->type == a_VARREG)
199       _awka_re2null(ret);
200     else
201     {
202       ret->ptr[0] = '\0';
203       ret->slen = 0;
204     }
205   }
206   else
207     ret->type = a_VARNUL;
208   return ret;
209 }
210 
211 /*
212  * awka_retfn - this frees local variables in user-functions upon
213  *              a return.
214  */
215 void
_awka_retfn(int i)216 _awka_retfn(int i)
217 {
218   register int j, k;
219   a_VAR *var;
220 
221   if (_awka_fn[i].push == 0)
222     return;
223   _awka_fn[i].push--;
224   j = _awka_fn[i].push;
225 
226   for (k=0; k<_awka_fn[i].fnvar[j].used; k++)
227   {
228     var = _awka_fn[i].fnvar[j].var[k];
229     if (!var) continue;
230     if (var->ptr)
231     {
232       /* if this is a local function var, manage its memory */
233       if (!_awka_fn[i].fnvar[j].status[k])
234       {
235         if (!var->allc)
236           var->ptr = NULL;
237         else
238           awka_killvar(var);
239       }
240       else if (var->type == a_VARARR)
241       {
242         awka_arrayclear(var);
243         free(var->ptr);
244         var->ptr = NULL;
245         var->allc = 0;
246       }
247       else
248       {
249         awka_gets1(var);
250         var->ptr[0] = '\0';
251       }
252     }
253     if (var->type == a_VARDBL)
254     {
255       /* if (var->ptr) awka_killvar(var); */
256       var->type = a_VARNUL;
257     }
258     var->slen = 0;
259     var->dval = 0.0;
260     var->type2 = 0;
261   }
262   _a_gc_depth--;
263   _awka_fn[i].fnvar[j].used = 0;
264 }
265 
266 void
awka_killvar(a_VAR * v)267 awka_killvar( a_VAR *v )
268 {
269   if (!v) return;
270 
271   if (v->ptr)
272   {
273     if (v->type == a_VARARR)
274     {
275       awka_arrayclear(v);
276       free(v->ptr);
277     }
278     else if (v->type != a_VARREG)
279       free(v->ptr);
280   }
281 
282   v->ptr = NULL;
283   v->dval = 0.0;
284   v->allc = 0;
285   v->slen = 0;
286   v->type2 = 0;
287   v->type = a_VARNUL;
288 }
289 
290 void
_awka_re2s(a_VAR * v)291 _awka_re2s( a_VAR *v )
292 {
293   awka_regexp *r;
294 
295   if (v->type != a_VARREG) return;
296   r = (awka_regexp *) v->ptr;
297   malloc( &v->ptr, (v->slen = r->strlen) + 1 );
298   memcpy(v->ptr, r->origstr, v->slen+1);
299   v->type = a_VARSTR;
300   v->allc = v->slen+1;
301   v->type2 = 0;
302 }
303 
304 void
_awka_re2null(a_VAR * v)305 _awka_re2null( a_VAR *v )
306 {
307   if (v->type != a_VARREG) return;
308   v->type = a_VARNUL;
309   v->allc = v->slen = 0;
310   v->type2 = 0;
311   v->ptr = NULL;
312 }
313 
314 double
awka_postinc(a_VAR * v)315 awka_postinc( a_VAR *v )
316 {
317   double d = awka_setd(v);
318   v->dval++;
319   return d;
320 }
321 
322 double
awka_postdec(a_VAR * v)323 awka_postdec( a_VAR *v )
324 {
325   double d = awka_setd(v);
326   v->dval--;
327   return d;
328 }
329 
330 a_VAR *
_awka_getdval(a_VAR * v,char * file,int line)331 _awka_getdval( a_VAR *v, char *file, int line )
332 {
333   switch (v->type)
334   {
335     case a_VARREG:
336       _awka_re2s(v);
337       /* fall through */
338     case a_VARSTR:
339     case a_VARUNK:
340       if (v->type2 == (char) -1)
341         v->dval = 0;
342       else if (v->ptr)
343         v->dval = strtod(v->ptr, NULL);
344       else
345         v->dval = 0;
346       break;
347     case a_VARNUL:
348       v->dval = 0.0;
349       break;
350     case a_VARARR:
351       awka_error("runtime error: awka_getd in file %s, line %d - %s\n", file,line,"array used as scalar");
352   }
353 
354   if (v->type2 != (char) -1)
355     v->type2 = a_DBLSET;
356   return v;
357 }
358 
359 a_VAR *
_awka_setdval(a_VAR * v,char * file,int line)360 _awka_setdval( a_VAR *v, char *file, int line )
361 {
362   if (v->type == a_VARREG)
363     _awka_re2null(v);
364 
365   _awka_set_FW(v);
366 
367   v->type2 = 0;
368   if (v->type == a_VARSTR || v->type == a_VARUNK)
369   {
370     if (v->ptr)
371     {
372       v->dval = strtod(v->ptr, NULL);
373       free(v->ptr);
374     }
375     v->ptr = NULL;
376     v->slen = 0;
377     v->allc = 0;
378     v->type = a_VARDBL;
379     return v;
380   }
381   else if (v->type == a_VARNUL)
382   {
383     v->type = a_VARDBL;
384     v->dval = 0.0;
385     /* v->ptr = NULL; */
386     return v;
387   }
388   else
389   {
390     /* array */
391     awka_error("runtime error: awka_setd in file %s, line %d - %s\n", file,line,"array used as scalar");
392   }
393 
394   /* dead code - have to check this... */
395   if (_awka_setdoln == TRUE)
396     _awka_setdol0_len = TRUE;
397   if (v == a_bivar[a_DOL0])
398   {
399     _rebuild0_now = FALSE;
400     _rebuildn = TRUE;
401   }
402   return v;
403 }
404 
405 char *
_awka_getsval(a_VAR * v,char ofmt,char * file,int line)406 _awka_getsval( a_VAR *v, char ofmt, char *file, int line )
407 {
408   char varbuf[256], *ptr = NULL;
409   register int i;
410 
411   switch (v->type)
412   {
413     case a_VARDBL:
414       i = (int) (v->dval);
415       if ((double) i == v->dval)
416       {
417         sprintf(varbuf, "%d", i);
418         v->slen = strlen(varbuf);
419       }
420       else
421       {
422         if (ofmt)
423           sprintf(varbuf, awka_gets1(a_bivar[a_OFMT]), v->dval);
424         else
425           sprintf(varbuf, awka_gets1(a_bivar[a_CONVFMT]), v->dval);
426         v->slen = strlen(varbuf);
427       }
428       if (!v->ptr || (v->temp == 2 && v->allc <= v->slen))
429         v->allc = malloc( &v->ptr, v->slen + 1 );
430       else if (v->allc <= v->slen)
431         v->allc = realloc( &v->ptr, v->slen + 1 );
432 
433       memcpy(v->ptr, varbuf, v->slen+1);
434       v->type2 = (ofmt ? 0 : a_STRSET);
435       return v->ptr;
436 
437     case a_VARSTR:
438     case a_VARUNK:
439       v->allc = malloc( &v->ptr, 8 );
440       ptr = v->ptr;
441       v->slen = 0;
442       v->ptr[0] = '\0';
443       return ptr;
444 
445     case a_VARREG:
446       if (v->ptr)
447       {
448         _awka_re2s(v);
449         v->type = a_VARSTR;
450         return v->ptr;
451       }
452       v->dval = 0.0;
453       v->type = a_VARNUL;
454       /* fall thru */
455     case a_VARNUL:
456       ptr = _awka_tmpstr(1);
457       ptr[0] = '\0';
458       v->slen = 0;
459       return ptr;
460 
461     case a_VARARR:
462       awka_error("runtime error: awka_gets in file %s, line %d - array used as scalar.\n",file,line);
463 
464     default:
465       awka_error("runtime error: awka_gets in file %s, line %d - unexpected type value (%d).\n",file,line,v->type);
466   }
467 
468   return ptr;  /* can't get here anyway */
469 }
470 
471 awka_regexp *
_awka_getreval(a_VAR * v,char * file,int line,char type)472 _awka_getreval( a_VAR *v, char *file, int line, char type )
473 {
474   awka_regexp *r = NULL;
475   switch (v->type)
476   {
477     case a_VARDBL:
478       awka_gets1(v);
479       break;
480 
481     case a_VARNUL:
482       v->allc = malloc( &v->ptr, 1 );
483       v->ptr[0] = '\0';
484       v->slen = 0;
485       break;
486 
487     case a_VARARR:
488       awka_error("runtime error: awka_getre in file %s, line %d - %s\n", file,line,"array used as scalar");
489   }
490 
491   if (!v->ptr)
492   {
493     v->allc = malloc( &v->ptr, 1 );
494     v->slen = 0;
495     v->ptr[0] = '\0';
496   }
497 
498   switch (type)
499   {
500     case _RE_SPLIT:
501       r = _awka_compile_regexp_SPLIT(v->ptr, v->slen); break;
502     case _RE_MATCH:
503       r = _awka_compile_regexp_MATCH(v->ptr, v->slen); break;
504     case _RE_GSUB:
505       r = _awka_compile_regexp_GSUB(v->ptr, v->slen); break;
506   }
507   if (!r)
508     awka_error("runtime error: Regular Expression failed to compile, file %s line %d\n",file,line);
509   free(v->ptr);
510   v->ptr = (char *) r;
511 
512   v->type = a_VARREG;
513   return r;
514 }
515 
516 char **
awka_setsval(a_VAR * v,char * file,int line)517 awka_setsval( a_VAR *v, char *file, int line )
518 {
519   if (v->type == a_VARARR)
520     awka_error("runtime error: awka_sets in file %s, line %d - %s\n", file,line,"array used as scalar");
521   else if (v->type == a_VARREG)
522     _awka_re2null(v);
523   else if (v->ptr)
524   {
525     free(v->ptr);
526     v->ptr = NULL;
527   }
528 
529   v->slen = 0;
530   v->allc = 0;
531   v->type2 = 0;
532   v->type = a_VARSTR;
533   return &(v->ptr);
534 }
535 
536 a_VAR *
awka_strdcpy(a_VAR * v,double d)537 awka_strdcpy( a_VAR *v, double d )
538 {
539   char tmp[256];
540   int i = (int) d;
541 
542   if ((double) i == d)
543     sprintf(tmp, "%d", i);
544   else
545     sprintf(tmp, awka_gets1(a_bivar[a_CONVFMT]), d);
546 
547   i = strlen(tmp);
548 
549   if (v->type == a_VARSTR || v->type == a_VARUNK)
550   {
551     if (!v->ptr)
552       v->allc = malloc( &v->ptr, i+1 );
553     else if (i >= v->allc)
554       v->allc = realloc( &v->ptr, i+1 );
555   }
556   else
557     v->allc = malloc( &v->ptr, i+1 );
558 
559   v->slen = i;
560   memcpy(v->ptr, tmp, i+1);
561   v->type = a_VARSTR;
562   return v;
563 }
564 
565 a_VAR *
awka_strscpy(a_VAR * v,char * s)566 awka_strscpy( a_VAR *v, char *s )
567 {
568   register int i = strlen(s);
569   if (v->type == a_VARSTR || v->type == a_VARUNK)
570   {
571     if (!v->ptr)
572       v->allc = malloc( &v->ptr, i+1 );
573     else if (v->allc < i)
574       v->allc = realloc( &v->ptr, i+1 );
575   }
576   else
577     v->allc = malloc( &v->ptr, i+1 );
578 
579   v->slen = i;
580   memcpy(v->ptr, s, i+1);
581   v->type = a_VARSTR;
582   return v;
583 }
584 
585 a_VAR *
awka_vardup(a_VAR * v)586 awka_vardup( a_VAR *v )
587 {
588   a_VAR *ret;
589   _awka_tmpvar(ret);
590   awka_varcpy(ret, v);
591   return ret;
592 }
593 
594 double
awka_vardblset(a_VAR * v,double d)595 awka_vardblset( a_VAR *v, double d )
596 {
597   if (v->type == a_VARARR)
598     awka_error("runtime error: awka_vardblset - %s\n", "array used as scalar");
599 
600   _awka_set_FW(v);
601   if (v->type == a_VARREG)
602     _awka_re2null(v);
603 
604   _awka_set_FW(v);
605 
606   v->type2 = 0;
607   if (v->type == a_VARSTR || v->type == a_VARUNK)
608   {
609     if (v->ptr)
610       free(v->ptr);
611     v->ptr = NULL;
612     v->slen = 0;
613     v->allc = 0;
614   }
615 
616   v->type = a_VARDBL;
617   v->dval = d;
618 
619   if (_awka_setdoln == TRUE)
620     _awka_setdol0_len = TRUE;
621   if (v == a_bivar[a_DOL0])
622   {
623     _rebuild0_now = FALSE;
624     _rebuildn = TRUE;
625   }
626   return v->dval;
627 }
628 
629 a_VAR *
awka_varcpy(a_VAR * va,a_VAR * vb)630 awka_varcpy( a_VAR *va, a_VAR *vb )
631 {
632   int prev_len = -1;
633   register char *ptr;
634   register unsigned int allc;
635 
636   if (vb->type == a_VARARR || va->type == a_VARARR)
637     awka_error("runtime error: awka_varcpy - %s\n", "array used as scalar");
638 
639   _awka_set_FW(va);
640   if (va == vb) return va;
641 
642   va->dval = vb->dval;
643   va->type2 = vb->type2;
644 
645   switch (vb->type)
646   {
647     case a_VARSTR:
648     case a_VARUNK:
649       prev_len = va->slen;
650       if (vb->temp == 1)
651       { /* don't need vb beyond this statement */
652         /* swap pointers - this is very efficient */
653         if (va->type == a_VARREG)
654           _awka_re2null(va);
655         ptr = va->ptr;
656         allc = va->allc;
657         va->ptr = vb->ptr;
658         va->allc = vb->allc;
659         va->slen = vb->slen;
660         vb->ptr = ptr;
661         if (ptr) ptr[0] = '\0';
662         vb->type2 = 0;
663         vb->slen = 0;
664         vb->allc = allc;
665         vb->dval = 0;
666       }
667       else
668       {
669         /* we need both va & vb, memcpy is necessary */
670         awka_forcestr(va);
671         if (va->ptr && va->allc <= vb->slen)
672           va->allc = realloc( &va->ptr, vb->slen+1 );
673         else if (!va->ptr)
674           va->allc = malloc( &va->ptr, vb->slen+1 );
675         memcpy(va->ptr, vb->ptr, vb->slen+1);
676         va->slen = vb->slen;
677       }
678       va->type = vb->type;
679       va->type2 = vb->type2;
680       break;
681 
682     case a_VARREG:
683       if (va->ptr) awka_killvar(va);
684       va->ptr = vb->ptr;
685       break;
686 
687     case a_VARDBL:
688       if (vb->ptr && vb->type2 == a_STRSET)
689       {
690         if (!va->ptr || !va->allc)
691           va->allc = malloc( &va->ptr, vb->slen+1 );
692         else if (va->ptr && va->allc <= vb->slen)
693           va->allc = realloc( &va->ptr, vb->slen+1 );
694         memcpy(va->ptr, vb->ptr, vb->slen+1);
695         va->slen = vb->slen;
696       }
697   }
698   va->type = vb->type;
699 
700   if (_awka_setdoln == TRUE)
701   {
702     if (prev_len != -1)
703     {
704       _awka_dol0_len -= prev_len;
705       _awka_dol0_len += vb->slen;
706       _awka_setdoln = _awka_setdol0_len = FALSE;
707     }
708     else
709       _awka_setdol0_len = TRUE;
710   }
711   if (va == a_bivar[a_DOL0])
712   {
713     _rebuild0_now = FALSE;
714     _rebuildn = TRUE;
715   }
716   return va;
717 }
718 
719 void
_awka_checkunk(a_VAR * va)720 _awka_checkunk(a_VAR *va)
721 {
722   if (va->type2 == 0 && va->ptr)
723   {
724     if (!isalpha(va->ptr[0]) &&
725         _awka_isnumber(va->ptr) == TRUE)
726     {
727       va->type2 = a_DBLSET;
728       va->dval = strtod(va->ptr, NULL);
729     }
730     /*
731     else
732       va->type2 = -1;
733       */    /* commented in 0.5.10 as causing grief */
734   }
735 }
736 
737 double
awka_varcmp(a_VAR * va,a_VAR * vb)738 awka_varcmp( a_VAR *va, a_VAR *vb )
739 {
740   int i;
741 
742   if (vb->type == a_VARARR || va->type == a_VARARR)
743     awka_error("runtime error: awka_varcmp", "array used as scalar");
744 
745   if (va == vb) return 0;
746   if (va->type == a_VARUNK && va->type2 == 0 && va->ptr)
747     _awka_checkunk(va);
748   if (vb->type == a_VARUNK && vb->type2 == 0 && vb->ptr)
749     _awka_checkunk(vb);
750   if ((va->type <= a_VARDBL ||
751       (va->type == a_VARUNK && va->type2 == a_DBLSET)) &&
752       (vb->type <= a_VARDBL ||
753       (vb->type == a_VARUNK && vb->type2 == a_DBLSET)))
754   {
755     /* double comparison */
756     if (va->dval == vb->dval)
757       return 0;
758     else
759       return ((va->dval < vb->dval) ? -1 : 1);
760   }
761 
762   i = strcmp(awka_gets1(va), awka_gets1(vb));
763   return ((i == 0) ? 0 : ((i < 0) ? -1 : 1));
764 }
765 
766 int
awka_vartrue(a_VAR * v)767 awka_vartrue( a_VAR *v )
768 {
769   if (v->type == a_VARSTR && v->ptr)
770   {
771     if (v->ptr[0] != '\0')
772       return 1;
773     else
774       return 0;
775   }
776   if (v->type == a_VARDBL && v->dval != 0.0)
777     return 1;
778   if (v->type == a_VARUNK)
779   {
780     if (v->ptr && v->ptr[0] != '\0' && strcmp(v->ptr, "0"))
781       return 1;
782     if (v->type2 == a_DBLSET && v->dval != 0.0)
783       return 1;
784   }
785   if (v->type == a_VARREG)
786     return 1;
787   return 0;
788 }
789 
790 double
awka_var2dblcmp(a_VAR * va,double d)791 awka_var2dblcmp( a_VAR *va, double d )
792 {
793   int i;
794 
795   if (va->type == a_VARARR)
796     awka_error("runtime error: awka_var2dblcmp", "array used as scalar");
797 
798   if (va->type == a_VARUNK && va->type2 == 0 && va->ptr)
799     _awka_checkunk(va);
800 
801   if (va->type <= a_VARDBL || (va->type == a_VARUNK && va->type2 == a_DBLSET))
802     return (va->dval == d ? 0 : (va->dval < d ? -1 : 1));
803   if (!(i = strcmp(awka_gets1(va), awka_tmp_dbl2str(d))))
804     return 0;
805   return (i < 0 ? -1 : 1);
806 }
807 
808 double
awka_dbl2varcmp(double d,a_VAR * va)809 awka_dbl2varcmp( double d, a_VAR *va )
810 {
811   int i;
812 
813   if (va->type == a_VARARR)
814     awka_error("runtime error: awka_var2dblcmp", "array used as scalar");
815 
816   if (va->type2 == 0 && va->ptr && va->type == a_VARUNK)
817     _awka_checkunk(va);
818 
819   if (va->type <= a_VARDBL || (va->type == a_VARUNK && va->type2 == a_DBLSET))
820   {
821     i = (d == va->dval ? 0 : (d < va->dval ? -1 : 1));
822     return (double) i;
823   }
824   if (!(i = strcmp(awka_tmp_dbl2str(d), awka_gets1(va))))
825     return 0;
826   return (i < 0 ? -1 : 1);
827 }
828 
829 int
awka_nullval(char * s)830 awka_nullval( char *s )
831 {
832   double d;
833   char *p;
834 
835   d = strtod(s, NULL);
836   if (!d)
837   {
838     p = s + (strlen(s)-1);
839     while ((*p == ' ' || *p == '\t') && p > s) p--;
840     p++;
841     *p = '\0';
842     p = s;
843     while (*p == ' ' || *p == '\t') p++;
844     while (*p)
845     {
846       if (isalpha(*p) ||
847          (ispunct(*p) && *p != '.') ||
848          (isdigit(*p) && *p != '0')) break;
849       p++;
850     }
851     if (*p == '\0')
852       return 1;
853   }
854   return 0;
855 }
856 
857 
858 a_VAR *
awka_tmp_dbl2var(double d)859 awka_tmp_dbl2var(double d)
860 {
861   a_VAR *v;
862 
863   _awka_tmpvar(v);
864   if (v->ptr && v->type == a_VARREG)
865     _awka_re2null(v);
866 
867   /* v->ptr = NULL; */
868   v->type = a_VARDBL;
869   v->slen = 0;
870   /* v->allc = 0; */
871   v->dval = d;
872   v->type2 = 0;
873   return v;
874 }
875 
876 a_VAR *
awka_ro_str2var(char * c)877 awka_ro_str2var(char *c)
878 {
879   a_VAR *v;
880   int i = strlen(c);
881 
882   _awka_tmpvar_ro(v);
883 
884   v->type = a_VARSTR;
885   v->ptr = c;
886   v->slen = i;
887   v->allc = 0;
888   v->dval = 0;
889   v->type2 = 0;
890   return v;
891 }
892 
893 a_VAR *
awka_tmp_str2var(char * c)894 awka_tmp_str2var(char *c)
895 {
896   a_VAR *v;
897   int i = strlen(c);
898 
899   _awka_tmpvar(v);
900 
901   if (v->type == a_VARSTR || v->type == a_VARUNK || v->type == a_VARREG)
902   {
903     if (v->type == a_VARREG) _awka_re2null(v);
904     if (v->allc <= i)
905       v->allc = realloc( &v->ptr, i+1 );
906     else if (!v->ptr)
907       v->allc = malloc( &v->ptr, i+1 );
908   }
909   else
910   {
911     if (v->ptr) free(v->ptr);
912     v->allc = malloc( &v->ptr, i+1 );
913   }
914 
915   v->type = a_VARSTR;
916   memcpy(v->ptr, c, i+1);
917   v->slen = i;
918   v->dval = 0;
919   v->type2 = 0;
920 
921   return v;
922 }
923 
924 a_VAR *
awka_tmp_re2var(awka_regexp * r)925 awka_tmp_re2var(awka_regexp *r)
926 {
927   a_VAR *v;
928 
929   _awka_tmpvar(v);
930 
931   if (v->ptr)
932     awka_killvar(v);
933 
934   v->ptr = (char *) r;
935   v->type = a_VARREG;
936   v->slen = 0;
937   v->allc = 0;
938   v->dval = 0;
939   v->type2 = 0;
940 
941   return v;
942 }
943 
944 char *
awka_tmp_dbl2str(double d)945 awka_tmp_dbl2str(double d)
946 {
947   char *s, tmp[256];
948   int i = (int) d, len;
949 
950   if ((double) i == d)
951     sprintf(tmp, "%d", i);
952   else
953     sprintf(tmp, awka_gets1(a_bivar[a_CONVFMT]), d);
954 
955   i = strlen(tmp)+1;
956   len = i + (32 - (i % 32));
957 
958   _awka_tmpvar_c(s, len);
959   memcpy(s, tmp, i);
960   return s;
961 }
962 
963 #ifdef MEM_DEBUG
964 char *
awka_strcpy(a_VAR * v,char * s)965 awka_strcpy(a_VAR *v, char *s)
966 {
967   register int _slen = strlen(s)+1, allc_len;
968   _awka_set_FW(v);
969   if (v->type == a_VARREG)
970     _awka_re2s(v);
971   if (v->type != a_VARSTR && v->type != a_VARUNK)
972     awka_setsval(v, __FILE__, __LINE__);
973   if (v->ptr && v->allc <= _slen)
974     v->allc = realloc( (void **) &v->ptr, _slen );
975   else if (!v->ptr)
976     v->allc = malloc( (void **) &v->ptr, _slen );
977   v->slen = _slen-1;
978   memcpy(v->ptr, s, _slen);
979   v->type = a_VARSTR;
980   v->type2 = 0;
981   if (v == a_bivar[a_DOL0])
982   {
983     _rebuild0_now = FALSE;
984     _rebuildn = TRUE;
985   }
986   return v->ptr;
987 }
988 #endif
989 
990