1 /* $NetBSD: type_numeric.c,v 1.4 2001/06/13 10:45:59 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1998-1999 Brett Lymn 5 * (blymn@baea.com.au, brett_lymn@yahoo.com.au) 6 * All rights reserved. 7 * 8 * This code has been donated to The NetBSD Foundation by the Author. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * 30 */ 31 32 #include <stdlib.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include "form.h" 36 #include "internals.h" 37 38 /* 39 * The numeric type handling. 40 */ 41 42 typedef struct 43 { 44 unsigned precision; 45 double min; 46 double max; 47 } numeric_args; 48 49 /* 50 * Create the numeric arguments structure from the given args. Return NULL 51 * if the call fails, otherwise return a pointer to the structure allocated. 52 */ 53 static char * 54 create_numeric_args(va_list *args) 55 { 56 numeric_args *new; 57 58 new = (numeric_args *) malloc(sizeof(numeric_args)); 59 60 if (new != NULL) { 61 new->precision = va_arg(*args, unsigned); 62 new->min = va_arg(*args, double); 63 new->max = va_arg(*args, double); 64 } 65 66 return (void *) new; 67 } 68 69 /* 70 * Copy the the numeric argument structure. 71 */ 72 static char * 73 copy_numeric_args(char *args) 74 { 75 numeric_args *new; 76 77 new = (numeric_args *) malloc(sizeof(numeric_args)); 78 79 if (new != NULL) 80 bcopy(args, new, sizeof(numeric_args)); 81 82 return (void *) new; 83 } 84 85 /* 86 * Free the allocated storage associated with the type arguments. 87 */ 88 static void 89 free_numeric_args(char *args) 90 { 91 if (args != NULL) 92 free(args); 93 } 94 95 /* 96 * Check the contents of the field buffer are numeric only. A valid 97 * number is of the form nnnn[.mmmmm][Ee[+-]ddd] 98 */ 99 static int 100 numeric_check_field(FIELD *field, char *args) 101 { 102 int cur; 103 double number, max, min; 104 int precision; 105 char *buf, *new_buf; 106 107 if (args == NULL) 108 return FALSE; 109 110 precision = ((numeric_args *) (void *) field->args)->precision; 111 min = ((numeric_args *) (void *) field->args)->min; 112 max = ((numeric_args *) (void *) field->args)->max; 113 114 buf = args; 115 cur = 0; 116 117 /* skip leading white space */ 118 while ((buf[cur] != '\0') 119 && ((buf[cur] == ' ') || (buf[cur] == '\t'))) 120 cur++; 121 122 /* no good if we have hit the end */ 123 if (buf[cur] == '\0') 124 return FALSE; 125 126 /* find the end of the digits but allow a leading + or - sign, and 127 * a decimal point. 128 */ 129 if ((buf[cur] == '-') || (buf[cur] == '+')) 130 cur++; 131 132 while((buf[cur] != '\0') && isdigit(buf[cur])) 133 cur++; 134 135 /* if not at end of string then check for decimal... */ 136 if ((buf[cur] != '\0') && (buf[cur] == '.')) { 137 cur++; 138 /* check for more digits now.... */ 139 while((buf[cur] != '\0') && isdigit(buf[cur])) 140 cur++; 141 } 142 143 /* check for an exponent */ 144 if ((buf[cur] != '\0') && 145 ((buf[cur] == 'E') || (buf[cur] == 'e'))) { 146 cur++; 147 if (buf[cur] == '\0') 148 return FALSE; 149 150 /* allow a + or a - for exponent */ 151 if ((buf[cur] == '+') || (buf[cur] == '-')) 152 cur++; 153 154 if (buf[cur] == '\0') 155 return FALSE; 156 157 /* we expect a digit now */ 158 if (!isdigit(buf[cur])) 159 return FALSE; 160 161 /* skip digits for the final time */ 162 while((buf[cur] != '\0') && isdigit(buf[cur])) 163 cur++; 164 } 165 166 /* check there is only trailing whitespace */ 167 while ((buf[cur] != '\0') 168 && ((buf[cur] == ' ') || (buf[cur] == '\t'))) 169 cur++; 170 171 /* no good if we are not at the end of the string */ 172 if (buf[cur] != '\0') 173 return FALSE; 174 175 /* convert and range check the number...*/ 176 number = atof(buf); 177 if ((min < max) && ((number < min) || (number > max))) 178 return FALSE; 179 180 if (asprintf(&new_buf, "%.*f", precision, number) < 0) 181 return FALSE; 182 183 /* re-set the field buffer to be the reformatted numeric */ 184 set_field_buffer(field, 0, new_buf); 185 186 free(new_buf); 187 188 /* otherwise all was ok */ 189 return TRUE; 190 } 191 192 /* 193 * Check the given character is numeric, return TRUE if it is. 194 */ 195 static int 196 numeric_check_char(/* ARGSUSED1 */ int c, char *args) 197 { 198 return ((isdigit(c) || (c == '-') || (c == '+') 199 || (c == '.') || (c == 'e') || (c == 'E')) ? TRUE : FALSE); 200 } 201 202 static FIELDTYPE builtin_numeric = { 203 _TYPE_HAS_ARGS | _TYPE_IS_BUILTIN, /* flags */ 204 0, /* refcount */ 205 NULL, /* link */ 206 create_numeric_args, /* make_args */ 207 copy_numeric_args, /* copy_args */ 208 free_numeric_args, /* free_args */ 209 numeric_check_field, /* field_check */ 210 numeric_check_char, /* char_check */ 211 NULL, /* next_choice */ 212 NULL /* prev_choice */ 213 }; 214 215 FIELDTYPE *TYPE_NUMERIC = &builtin_numeric; 216 217 218