Line data Source code
1 : /* uconvert - convert string representations of decimal numbers into whole 2 : number/fractional value pairs. */ 3 : 4 : /* Copyright (C) 2008,2009 Free Software Foundation, Inc. 5 : 6 : This file is part of GNU Bash, the Bourne Again SHell. 7 : 8 : Bash is free software: you can redistribute it and/or modify 9 : it under the terms of the GNU General Public License as published by 10 : the Free Software Foundation, either version 3 of the License, or 11 : (at your option) any later version. 12 : 13 : Bash is distributed in the hope that it will be useful, 14 : but WITHOUT ANY WARRANTY; without even the implied warranty of 15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 : GNU General Public License for more details. 17 : 18 : You should have received a copy of the GNU General Public License 19 : along with Bash. If not, see <http://www.gnu.org/licenses/>. 20 : */ 21 : 22 : #include "config.h" 23 : 24 : #include "bashtypes.h" 25 : 26 : #if defined (TIME_WITH_SYS_TIME) 27 : # include <sys/time.h> 28 : # include <time.h> 29 : #else 30 : # if defined (HAVE_SYS_TIME_H) 31 : # include <sys/time.h> 32 : # else 33 : # include <time.h> 34 : # endif 35 : #endif 36 : 37 : #if defined (HAVE_UNISTD_H) 38 : #include <unistd.h> 39 : #endif 40 : 41 : #include <stdio.h> 42 : #include "chartypes.h" 43 : 44 : #include "shell.h" 45 : #include "builtins.h" 46 : 47 : #define DECIMAL '.' /* XXX - should use locale */ 48 : 49 : #define RETURN(x) \ 50 : do { \ 51 : if (ip) *ip = ipart * mult; \ 52 : if (up) *up = upart; \ 53 : return (x); \ 54 : } while (0) 55 : 56 : /* 57 : * An incredibly simplistic floating point converter. 58 : */ 59 : static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 }; 60 : 61 : /* Take a decimal number int-part[.[micro-part]] and convert it to the whole 62 : and fractional portions. The fractional portion is returned in 63 : millionths (micro); callers are responsible for multiplying appropriately. 64 : Return 1 if value converted; 0 if invalid integer for either whole or 65 : fractional parts. */ 66 : int 67 0 : uconvert(s, ip, up) 68 : char *s; 69 : long *ip, *up; 70 : { 71 0 : int n, mult; 72 0 : long ipart, upart; 73 0 : char *p; 74 : 75 0 : ipart = upart = 0; 76 0 : mult = 1; 77 : 78 0 : if (s && (*s == '-' || *s == '+')) 79 : { 80 0 : mult = (*s == '-') ? -1 : 1; 81 0 : p = s + 1; 82 : } 83 : else 84 : p = s; 85 : 86 0 : for ( ; p && *p; p++) 87 : { 88 0 : if (*p == DECIMAL) /* decimal point */ 89 : break; 90 0 : if (DIGIT(*p) == 0) 91 0 : RETURN(0); 92 0 : ipart = (ipart * 10) + (*p - '0'); 93 : } 94 : 95 0 : if (p == 0 || *p == 0) /* callers ensure p can never be 0; this is to shut up clang */ 96 0 : RETURN(1); 97 : 98 0 : if (*p == DECIMAL) 99 0 : p++; 100 : 101 : /* Look for up to six digits past a decimal point. */ 102 0 : for (n = 0; n < 6 && p[n]; n++) 103 : { 104 0 : if (DIGIT(p[n]) == 0) 105 0 : RETURN(0); 106 0 : upart = (upart * 10) + (p[n] - '0'); 107 : } 108 : 109 : /* Now convert to millionths */ 110 0 : upart *= multiplier[n]; 111 : 112 0 : if (n == 6 && p[6] >= '5' && p[6] <= '9') 113 0 : upart++; /* round up 1 */ 114 : 115 0 : RETURN(1); 116 : }