Git init
[external/mawk.git] / cast.c
1
2 /********************************************
3 cast.c
4 copyright 1991, Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13
14 /*   $Log: cast.c,v $
15  *   Revision 1.6  1996/08/11 22:07:50  mike
16  *   Fix small bozo in rt_error("overflow converting ...")
17  *
18  * Revision 1.5  1995/06/18  19:17:45  mike
19  * Create a type Int which on most machines is an int, but on machines
20  * with 16bit ints, i.e., the PC is a long.  This fixes implicit assumption
21  * that int==long.
22  *
23  * Revision 1.4  1995/06/06  00:02:02  mike
24  * fix cast in d_to_l()
25  *
26  * Revision 1.3  1993/07/17  13:22:45  mike
27  * indent and general code cleanup
28  *
29  * Revision 1.2  1993/07/04  12:51:41  mike
30  * start on autoconfig changes
31  *
32  * Revision 5.5  1993/03/06  18:49:45  mike
33  * rm rt_overflow from check_strnum
34  *
35  * Revision 5.4  1993/02/13  21:57:20  mike
36  * merge patch3
37  *
38  * Revision 5.3.1.4  1993/01/22  15:05:19  mike
39  * pow2->mpow2 for linux
40  *
41  * Revision 5.3.1.3  1993/01/22  14:18:33  mike
42  * const for strtod and ansi picky compilers
43  *
44  * Revision 5.3.1.2  1993/01/20  12:53:06  mike
45  * d_to_l()
46  *
47  * Revision 5.3.1.1  1993/01/15  03:33:37  mike
48  * patch3: safer double to int conversion
49  *
50  * Revision 5.3  1992/11/28  23:48:42  mike
51  * For internal conversion numeric->string, when testing
52  * if integer, use longs instead of ints so 16 and 32 bit
53  * systems behave the same
54  *
55  * Revision 5.2  1992/08/17  14:19:45  brennan
56  * patch2: After parsing, only bi_sprintf() uses string_buff.
57  *
58  * Revision 5.1  1991/12/05  07:55:41  brennan
59  * 1.1 pre-release
60  *
61 */
62
63
64 /*  cast.c  */
65
66 #include "mawk.h"
67 #include "field.h"
68 #include "memory.h"
69 #include "scan.h"
70 #include "repl.h"
71
72 int mpow2[NUM_CELL_TYPES] =
73 {1, 2, 4, 8, 16, 32, 64, 128, 256, 512} ;
74
75 void
76 cast1_to_d(cp)
77    register CELL *cp ;
78 {
79    switch (cp->type)
80    {
81       case C_NOINIT:
82          cp->dval = 0.0 ;
83          break ;
84
85       case C_DOUBLE:
86          return ;
87
88       case C_MBSTRN:
89       case C_STRING:
90          {
91             register STRING *s = (STRING *) cp->ptr ;
92
93 #if FPE_TRAPS_ON                /* look for overflow error */
94             errno = 0 ;
95             cp->dval = strtod(s->str, (char **) 0) ;
96             if (errno && cp->dval != 0.0)       /* ignore underflow */
97                rt_error("overflow converting %s to double", s->str) ;
98 #else
99             cp->dval = strtod(s->str, (char **) 0) ;
100 #endif
101             free_STRING(s) ;
102          }
103          break ;
104
105       case C_STRNUM:
106          /* don't need to convert, but do need to free the STRING part */
107          free_STRING(string(cp)) ;
108          break ;
109
110
111       default:
112          bozo("cast on bad type") ;
113    }
114    cp->type = C_DOUBLE ;
115 }
116
117 void
118 cast2_to_d(cp)
119    register CELL *cp ;
120 {
121    register STRING *s ;
122
123    switch (cp->type)
124    {
125       case C_NOINIT:
126          cp->dval = 0.0 ;
127          break ;
128
129       case C_DOUBLE:
130          goto two ;
131       case C_STRNUM:
132          free_STRING(string(cp)) ;
133          break ;
134
135       case C_MBSTRN:
136       case C_STRING:
137          s = (STRING *) cp->ptr ;
138
139 #if FPE_TRAPS_ON                /* look for overflow error */
140          errno = 0 ;
141          cp->dval = strtod(s->str, (char **) 0) ;
142          if (errno && cp->dval != 0.0)  /* ignore underflow */
143             rt_error("overflow converting %s to double", s->str) ;
144 #else
145          cp->dval = strtod(s->str, (char **) 0) ;
146 #endif
147          free_STRING(s) ;
148          break ;
149
150       default:
151          bozo("cast on bad type") ;
152    }
153    cp->type = C_DOUBLE ;
154
155  two:cp++ ;
156
157    switch (cp->type)
158    {
159       case C_NOINIT:
160          cp->dval = 0.0 ;
161          break ;
162
163       case C_DOUBLE:
164          return ;
165       case C_STRNUM:
166          free_STRING(string(cp)) ;
167          break ;
168
169       case C_MBSTRN:
170       case C_STRING:
171          s = (STRING *) cp->ptr ;
172
173 #if FPE_TRAPS_ON                /* look for overflow error */
174          errno = 0 ;
175          cp->dval = strtod(s->str, (char **) 0) ;
176          if (errno && cp->dval != 0.0)  /* ignore underflow */
177             rt_error("overflow converting %s to double", s->str) ;
178 #else
179          cp->dval = strtod(s->str, (char **) 0) ;
180 #endif
181          free_STRING(s) ;
182          break ;
183
184       default:
185          bozo("cast on bad type") ;
186    }
187    cp->type = C_DOUBLE ;
188 }
189
190 void
191 cast1_to_s(cp)
192    register CELL *cp ;
193 {
194    register Int lval ;
195    char xbuff[260] ;
196
197    switch (cp->type)
198    {
199       case C_NOINIT:
200          null_str.ref_cnt++ ;
201          cp->ptr = (PTR) & null_str ;
202          break ;
203
204       case C_DOUBLE:
205
206          lval = d_to_I(cp->dval) ;
207          if (lval == cp->dval)  sprintf(xbuff, INT_FMT, lval) ;
208          else  sprintf(xbuff, string(CONVFMT)->str, cp->dval) ;
209
210          cp->ptr = (PTR) new_STRING(xbuff) ;
211          break ;
212
213       case C_STRING:
214          return ;
215
216       case C_MBSTRN:
217       case C_STRNUM:
218          break ;
219
220       default:
221          bozo("bad type on cast") ;
222    }
223    cp->type = C_STRING ;
224 }
225
226 void
227 cast2_to_s(cp)
228    register CELL *cp ;
229 {
230    register Int lval ;
231    char xbuff[260] ;
232
233    switch (cp->type)
234    {
235       case C_NOINIT:
236          null_str.ref_cnt++ ;
237          cp->ptr = (PTR) & null_str ;
238          break ;
239
240       case C_DOUBLE:
241
242          lval = d_to_I(cp->dval) ;
243          if (lval == cp->dval)  sprintf(xbuff, INT_FMT, lval) ;
244          else  sprintf(xbuff, string(CONVFMT)->str, cp->dval) ;
245
246          cp->ptr = (PTR) new_STRING(xbuff) ;
247          break ;
248
249       case C_STRING:
250          goto two ;
251
252       case C_MBSTRN:
253       case C_STRNUM:
254          break ;
255
256       default:
257          bozo("bad type on cast") ;
258    }
259    cp->type = C_STRING ;
260
261 two:
262    cp++ ;
263
264    switch (cp->type)
265    {
266       case C_NOINIT:
267          null_str.ref_cnt++ ;
268          cp->ptr = (PTR) & null_str ;
269          break ;
270
271       case C_DOUBLE:
272
273          lval = d_to_I(cp->dval) ;
274          if (lval == cp->dval)  sprintf(xbuff, INT_FMT, lval) ;
275          else  sprintf(xbuff, string(CONVFMT)->str, cp->dval) ;
276
277          cp->ptr = (PTR) new_STRING(xbuff) ;
278          break ;
279
280       case C_STRING:
281          return ;
282
283       case C_MBSTRN:
284       case C_STRNUM:
285          break ;
286
287       default:
288          bozo("bad type on cast") ;
289    }
290    cp->type = C_STRING ;
291 }
292
293 void
294 cast_to_RE(cp)
295    register CELL *cp ;
296 {
297    register PTR p ;
298
299    if (cp->type < C_STRING)  cast1_to_s(cp) ;
300
301    p = re_compile(string(cp)) ;
302    free_STRING(string(cp)) ;
303    cp->type = C_RE ;
304    cp->ptr = p ;
305
306 }
307
308 void
309 cast_for_split(cp)
310    register CELL *cp ;
311 {
312    static char meta[] = "^$.*+?|[]()" ;
313    static char xbuff[] = "\\X" ;
314    int c ;
315    unsigned len ;
316
317    if (cp->type < C_STRING)  cast1_to_s(cp) ;
318
319    if ((len = string(cp)->len) == 1)
320    {
321       if ((c = string(cp)->str[0]) == ' ')
322       {
323          free_STRING(string(cp)) ;
324          cp->type = C_SPACE ;
325          return ;
326       }
327       else if (strchr(meta, c))
328       {
329          xbuff[1] = c ;
330          free_STRING(string(cp)) ;
331          cp->ptr = (PTR) new_STRING(xbuff) ;
332       }
333    }
334    else if (len == 0)
335    {
336       free_STRING(string(cp)) ;
337       cp->type = C_SNULL ;
338       return ;
339    }
340
341    cast_to_RE(cp) ;
342 }
343
344 /* input: cp-> a CELL of type C_MBSTRN (maybe strnum)
345    test it -- casting it to the appropriate type
346    which is C_STRING or C_STRNUM
347 */
348
349 void
350 check_strnum(cp)
351    CELL *cp ;
352 {
353    char *test ;
354    register unsigned char *s, *q ;
355
356    cp->type = C_STRING ;         /* assume not C_STRNUM */
357    s = (unsigned char *) string(cp)->str ;
358    q = s + string(cp)->len ;
359    while (scan_code[*s] == SC_SPACE)  s++ ;
360    if (s == q)  return ;
361
362    while (scan_code[q[-1]] == SC_SPACE)  q-- ;
363    if (scan_code[q[-1]] != SC_DIGIT &&
364        q[-1] != '.')
365       return ;
366
367    switch (scan_code[*s])
368    {
369       case SC_DIGIT:
370       case SC_PLUS:
371       case SC_MINUS:
372       case SC_DOT:
373
374 #if FPE_TRAPS_ON
375          errno = 0 ;
376          cp->dval = strtod((char *) s, &test) ;
377          /* make overflow pure string */
378          if (errno && cp->dval != 0.0)  return ;
379 #else
380          cp->dval = strtod((char *) s, &test) ;
381 #endif
382
383          if ((char *) q <= test)  cp->type = C_STRNUM ;
384          /*  <= instead of == , for some buggy strtod
385                  e.g. Apple Unix */
386    }
387 }
388
389 /* cast a CELL to a replacement cell */
390
391 void
392 cast_to_REPL(cp)
393    register CELL *cp ;
394 {
395    register STRING *sval ;
396
397    if (cp->type < C_STRING)  cast1_to_s(cp) ;
398    sval = (STRING *) cp->ptr ;
399
400    cellcpy(cp, repl_compile(sval)) ;
401    free_STRING(sval) ;
402 }
403
404
405 /* convert a double to Int (this is not as simple as a
406    cast because the results are undefined if it won't fit).
407    Truncate large values to +Max_Int or -Max_Int
408    Send nans to -Max_Int
409 */
410
411 Int
412 d_to_I(d)
413    double d;
414 {
415    if (d >= Max_Int)    return Max_Int ;
416    if (d > -Max_Int)    return (Int) d ;
417    return -Max_Int ;
418 }