1 /********************************************
2 cast.c
3 copyright 2009-2014,2016, Thomas E. Dickey
4 copyright 1991-1995,1996, 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 * $MawkId: cast.c,v 1.21 2016/09/30 11:51:20 tom Exp $
15 */
16
17 /* cast.c */
18
19 #include "mawk.h"
20 #include "field.h"
21 #include "memory.h"
22 #include "scan.h"
23 #include "repl.h"
24
25 const int mpow2[NUM_CELL_TYPES] =
26 {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
27
28 void
cast1_to_d(CELL * cp)29 cast1_to_d(CELL *cp)
30 {
31 switch (cp->type) {
32 case C_NOINIT:
33 cp->dval = 0.0;
34 break;
35
36 case C_DOUBLE:
37 return;
38
39 case C_MBSTRN:
40 case C_STRING:
41 {
42 register STRING *s = (STRING *) cp->ptr;
43
44 errno = 0;
45 #ifdef FPE_TRAPS_ON /* look for overflow error */
46 cp->dval = strtod(s->str, (char **) 0);
47 if (errno && cp->dval != 0.0) /* ignore underflow */
48 rt_error("overflow converting %s to double", s->str);
49 #else
50 cp->dval = strtod(s->str, (char **) 0);
51 #endif
52 free_STRING(s);
53 }
54 break;
55
56 case C_STRNUM:
57 /* don't need to convert, but do need to free the STRING part */
58 free_STRING(string(cp));
59 break;
60
61 default:
62 bozo("cast on bad type");
63 }
64 cp->type = C_DOUBLE;
65 }
66
67 void
cast2_to_d(CELL * cp)68 cast2_to_d(CELL *cp)
69 {
70 register STRING *s;
71
72 switch (cp->type) {
73 case C_NOINIT:
74 cp->dval = 0.0;
75 break;
76
77 case C_DOUBLE:
78 goto two;
79 case C_STRNUM:
80 free_STRING(string(cp));
81 break;
82
83 case C_MBSTRN:
84 case C_STRING:
85 s = (STRING *) cp->ptr;
86
87 errno = 0;
88 #ifdef FPE_TRAPS_ON /* look for overflow error */
89 cp->dval = strtod(s->str, (char **) 0);
90 if (errno && cp->dval != 0.0) /* ignore underflow */
91 rt_error("overflow converting %s to double", s->str);
92 #else
93 cp->dval = strtod(s->str, (char **) 0);
94 #endif
95 free_STRING(s);
96 break;
97
98 default:
99 bozo("cast on bad type");
100 }
101 cp->type = C_DOUBLE;
102
103 two:
104 cp++;
105
106 switch (cp->type) {
107 case C_NOINIT:
108 cp->dval = 0.0;
109 break;
110
111 case C_DOUBLE:
112 return;
113 case C_STRNUM:
114 free_STRING(string(cp));
115 break;
116
117 case C_MBSTRN:
118 case C_STRING:
119 s = (STRING *) cp->ptr;
120
121 errno = 0;
122 #ifdef FPE_TRAPS_ON /* look for overflow error */
123 cp->dval = strtod(s->str, (char **) 0);
124 if (errno && cp->dval != 0.0) /* ignore underflow */
125 rt_error("overflow converting %s to double", s->str);
126 #else
127 cp->dval = strtod(s->str, (char **) 0);
128 #endif
129 free_STRING(s);
130 break;
131
132 default:
133 bozo("cast on bad type");
134 }
135 cp->type = C_DOUBLE;
136 }
137
138 void
cast1_to_s(CELL * cp)139 cast1_to_s(CELL *cp)
140 {
141 register Int lval;
142 char xbuff[260];
143
144 switch (cp->type) {
145 case C_NOINIT:
146 null_str.ref_cnt++;
147 cp->ptr = (PTR) & null_str;
148 break;
149
150 case C_DOUBLE:
151
152 lval = d_to_I(cp->dval);
153 if (lval == cp->dval)
154 sprintf(xbuff, INT_FMT, lval);
155 else
156 sprintf(xbuff, string(CONVFMT)->str, cp->dval);
157
158 cp->ptr = (PTR) new_STRING(xbuff);
159 break;
160
161 case C_STRING:
162 return;
163
164 case C_MBSTRN:
165 case C_STRNUM:
166 break;
167
168 default:
169 bozo("bad type on cast");
170 }
171 cp->type = C_STRING;
172 }
173
174 void
cast2_to_s(CELL * cp)175 cast2_to_s(CELL *cp)
176 {
177 register Int lval;
178 char xbuff[260];
179
180 switch (cp->type) {
181 case C_NOINIT:
182 null_str.ref_cnt++;
183 cp->ptr = (PTR) & null_str;
184 break;
185
186 case C_DOUBLE:
187
188 lval = d_to_I(cp->dval);
189 if (lval == cp->dval)
190 sprintf(xbuff, INT_FMT, lval);
191 else
192 sprintf(xbuff, string(CONVFMT)->str, cp->dval);
193
194 cp->ptr = (PTR) new_STRING(xbuff);
195 break;
196
197 case C_STRING:
198 goto two;
199
200 case C_MBSTRN:
201 case C_STRNUM:
202 break;
203
204 default:
205 bozo("bad type on cast");
206 }
207 cp->type = C_STRING;
208
209 two:
210 cp++;
211
212 switch (cp->type) {
213 case C_NOINIT:
214 null_str.ref_cnt++;
215 cp->ptr = (PTR) & null_str;
216 break;
217
218 case C_DOUBLE:
219
220 lval = d_to_I(cp->dval);
221 if (lval == cp->dval)
222 sprintf(xbuff, INT_FMT, lval);
223 else
224 sprintf(xbuff, string(CONVFMT)->str, cp->dval);
225
226 cp->ptr = (PTR) new_STRING(xbuff);
227 break;
228
229 case C_STRING:
230 return;
231
232 case C_MBSTRN:
233 case C_STRNUM:
234 break;
235
236 default:
237 bozo("bad type on cast");
238 }
239 cp->type = C_STRING;
240 }
241
242 void
cast_to_RE(CELL * cp)243 cast_to_RE(CELL *cp)
244 {
245 register PTR p;
246
247 if (cp->type < C_STRING)
248 cast1_to_s(cp);
249
250 p = re_compile(string(cp));
251 no_leaks_re_ptr(p);
252 free_STRING(string(cp));
253 cp->type = C_RE;
254 cp->ptr = p;
255
256 }
257
258 void
cast_for_split(CELL * cp)259 cast_for_split(CELL *cp)
260 {
261 static const char meta[] = "^$.*+?|[]()";
262 static char xbuff[] = "\\X";
263 int c;
264 size_t len;
265
266 if (cp->type < C_STRING)
267 cast1_to_s(cp);
268
269 if ((len = string(cp)->len) == 1) {
270 if ((c = string(cp)->str[0]) == ' ') {
271 free_STRING(string(cp));
272 cp->type = C_SPACE;
273 return;
274 } else if (c == 0) {
275 #ifdef LOCAL_REGEXP
276 char temp[1];
277 temp[0] = (char) c;
278 free_STRING(string(cp));
279 cp->ptr = (PTR) new_STRING1(temp, (size_t) 1);
280 #else
281 /*
282 * A null is not a meta character, but strchr will match it anyway.
283 * For now, there's no reason to compile a null as a regular
284 * expression - just return a string containing the single
285 * character. That is used in a special case in set_rs_shadow().
286 */
287 char temp[2];
288 temp[0] = (char) c;
289 free_STRING(string(cp));
290 cp->ptr = (PTR) new_STRING1(temp, (size_t) 1);
291 return;
292 #endif
293 } else if ((strchr) (meta, c)) {
294 xbuff[1] = (char) c;
295 free_STRING(string(cp));
296 cp->ptr = (PTR) new_STRING(xbuff);
297 }
298 } else if (len == 0) {
299 free_STRING(string(cp));
300 cp->type = C_SNULL;
301 return;
302 }
303
304 cast_to_RE(cp);
305 }
306
307 /* input: cp-> a CELL of type C_MBSTRN (maybe strnum)
308 test it -- casting it to the appropriate type
309 which is C_STRING or C_STRNUM
310 */
311
312 void
check_strnum(CELL * cp)313 check_strnum(CELL *cp)
314 {
315 char *temp;
316 register unsigned char *s, *q;
317
318 cp->type = C_STRING; /* assume not C_STRNUM */
319 s = (unsigned char *) string(cp)->str;
320 q = s + string(cp)->len;
321 while (scan_code[*s] == SC_SPACE)
322 s++;
323 if (s == q)
324 return;
325
326 while (scan_code[q[-1]] == SC_SPACE)
327 q--;
328 if (scan_code[q[-1]] != SC_DIGIT &&
329 q[-1] != '.')
330 return;
331
332 switch (scan_code[*s]) {
333 case SC_DIGIT:
334 case SC_PLUS:
335 case SC_MINUS:
336 case SC_DOT:
337
338 errno = 0;
339 #ifdef FPE_TRAPS_ON
340 cp->dval = strtod((char *) s, &temp);
341 /* make overflow pure string */
342 if (errno && cp->dval != 0.0)
343 break;
344 #else
345 cp->dval = strtod((char *) s, &temp);
346 #endif
347 #ifdef ERANGE
348 if (errno == ERANGE)
349 break;
350 #endif
351
352 if ((char *) q <= temp) {
353 cp->type = C_STRNUM;
354 /* <= instead of == , for some buggy strtod
355 e.g. Apple Unix */
356 }
357 break;
358 }
359 }
360
361 /* cast a CELL to a replacement cell */
362
363 void
cast_to_REPL(CELL * cp)364 cast_to_REPL(CELL *cp)
365 {
366 register STRING *sval;
367
368 if (cp->type < C_STRING)
369 cast1_to_s(cp);
370 sval = (STRING *) cp->ptr;
371
372 cellcpy(cp, repl_compile(sval));
373 free_STRING(sval);
374 }
375
376 /* convert a double to Int (this is not as simple as a
377 cast because the results are undefined if it won't fit).
378 Truncate large values to +Max_Int or -Max_Int
379 Send nans to -Max_Int
380 */
381
382 Int
d_to_I(double d)383 d_to_I(double d)
384 {
385 if (d >= Max_Int)
386 return Max_Int;
387 if (d > -Max_Int)
388 return (Int) d;
389 return -Max_Int;
390 }
391
392 /* convert a double to UInt (this is not as simple as a
393 cast because the results are undefined if it won't fit).
394 Truncate large values to Max_UInt or 0
395 Send nans to 0
396 */
397
398 UInt
d_to_U(double d)399 d_to_U(double d)
400 {
401 if (d >= Max_UInt)
402 return Max_UInt;
403 if (d > 0)
404 return (UInt) d;
405 return 0;
406 }
407
408 #ifdef NO_LEAKS
409 typedef struct _all_cells {
410 struct _all_cells *next;
411 char ptr;
412 CELL *cp;
413 } ALL_CELLS;
414
415 static ALL_CELLS *all_cells;
416 /*
417 * Some regular expressions are parsed, and the pointer stored in the byte-code
418 * where we cannot distinguish it from other constants. Keep a list here, to
419 * free on exit for auditing.
420 */
421 void
no_leaks_cell(CELL * cp)422 no_leaks_cell(CELL *cp)
423 {
424 ALL_CELLS *p = calloc(1, sizeof(ALL_CELLS));
425 p->next = all_cells;
426 p->cp = cp;
427 p->ptr = 0;
428 all_cells = p;
429 }
430
431 void
no_leaks_cell_ptr(CELL * cp)432 no_leaks_cell_ptr(CELL *cp)
433 {
434 ALL_CELLS *p = calloc(1, sizeof(ALL_CELLS));
435 p->next = all_cells;
436 p->cp = cp;
437 p->ptr = 1;
438 all_cells = p;
439 }
440
441 void
cell_leaks(void)442 cell_leaks(void)
443 {
444 while (all_cells != 0) {
445 ALL_CELLS *next = all_cells->next;
446 if (all_cells->ptr) {
447 zfree(all_cells->cp, sizeof(CELL));
448 } else {
449 free_cell_data(all_cells->cp);
450 }
451 free(all_cells);
452 all_cells = next;
453 }
454 }
455 #endif
456