1 /*-------------- Telecommunications & Signal Processing Lab ---------------
2                              McGill University
3 
4 Routine:
5   int STdec1val (const char String[], int Type, void *Val)
6 
7 Purpose:
8   Decode a numeric value
9 
10 Description:
11   This routine decodes a string containing a numeric value.  The data type can
12   be specified.  If a decoding error is detected, a warning message is printed
13   and an error status value is returned.
14 
15 Parameters:
16   <-  int STdec1val
17       Error status,
18         0 - no error
19         1 - format error
20         2 - range warning
21    -> const char String[]
22       Input string
23    -> int Type
24       Code for the data type, 'D' for double, 'F' for float, 'I' for int, 'L'
25       for long int.
26   <-  void *Val
27       Returned value of the type indicated by Type.  This value is not changed
28       for a format error.  For a range warning, the returned value is set to
29       the appropriate representable value.
30 
31 Author / revision:
32   P. Kabal  Copyright (C) 2003
33   $Revision: 1.22 $  $Date: 2003/05/09 03:17:00 $
34 
35 -------------------------------------------------------------------------*/
36 
37 #include <assert.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <float.h>
41 #include <limits.h>
42 #include <stdlib.h>	/* strtod */
43 
44 
45 #include <libtsp.h>
46 #include <libtsp/nucleus.h>
47 #include <libtsp/STmsg.h>
48 
49 #define ABSV(x)		(((x) < 0) ? -(x) : (x))
50 
51 #define MAXC	23
52 
53 
54 int
STdec1val(const char String[],int Type,void * Val)55 STdec1val (const char String[], int Type, void *Val)
56 
57 {
58   int BS;
59   double dv;
60   long int lv;
61   char *endstr;
62 
63   /* Trim initial white space */
64   for (; isspace ((int) *String); ++String)
65     ;
66   if (String[0] == '\0') {
67     UTwarn ("STdec1val - %s", STM_EmptyData);
68     return 1;
69   }
70 
71   /* Note: strtol should clamp a large input to INT_MAX, but the SunOS 4
72      version wraps the value around instead, with no ERANGE errcode. (This
73      is documented in the man page: "Overflow conditions are ignored.")
74   */
75 
76   dv = 0.0;	/* stop compiler warnings */
77   lv = 0;
78   errno = 0;
79   BS = 0;
80   switch (Type) {
81   case 'D':
82   case 'F':
83     dv = strtod (String, &endstr);
84     if (errno == ERANGE) {
85       if (dv == 0.0)
86 	BS = -1;
87       else
88 	BS = 1;
89     }
90     break;
91   case 'L':
92   case 'I':
93     lv = strtol (String, &endstr, 10);
94     if (errno == ERANGE)
95       BS = 1;
96     break;
97   default:
98     assert (0);
99     break;
100   }
101 
102   /* Trim white space on endstr */
103   for (; isspace ((int) *endstr); ++endstr)
104     ;
105   if (endstr[0] != '\0') {
106     /* Data format error */
107     UTwarn ("STdec1val - %s: \"%s\"", STM_DataErr, STstrDots (String, MAXC));
108     return 1;
109   }
110 
111   /* Return a value of the correct type */
112   switch (Type) {
113   case 'D':
114     *((double *) Val) = dv;
115     break;
116   case 'F':
117     if (dv > FLT_MAX) {
118       dv = FLT_MAX;
119       BS = 1;
120     }
121     else if (dv < -FLT_MAX) {
122       dv = -FLT_MAX;
123       BS = 1;
124     }
125     else if (dv != 0.0 && ABSV (dv) < FLT_MIN) {
126       dv = 0.0;
127       BS = -1;
128     }
129     *((float *) Val) = (float) dv;
130     break;
131   case 'L':
132     *((long int *) Val) = lv;
133     break;
134   case 'I':
135 #if (INT_MAX != LONG_MAX)
136     if (lv < INT_MIN) {
137       lv = INT_MIN;
138       BS = +1;
139     }
140     else if (lv > INT_MAX) {
141       lv = INT_MAX;
142       BS = +1;
143     }
144 #else
145     *((int *) Val) = lv;
146 #endif
147     break;
148   }
149 
150   if (BS < 0)
151     UTwarn ("STdec1val - %s: \"%s\"", STM_SmallVal, STstrDots (String, MAXC));
152   else if (BS > 0)
153     UTwarn ("STdec1val - %s: \"%s\"", STM_BigVal, STstrDots (String, MAXC));
154 
155 /* Return the status value */
156   if (BS != 0)
157     return 2;
158   else
159     return 0;
160 }
161