1 /*
2 * getnum.c -- Get number in a given interval, get length with units
3 *
4 * Copyright (c) 1988-1993 Miguel Santana
5 * Copyright (c) 1995-1999 Akim Demaille, Miguel Santana
6 */
7
8 /*
9 * This file is part of a2ps.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; see the file COPYING. If not, write to
23 * the Free Software Foundation, 59 Temple Place - Suite 330,
24 * Boston, MA 02111-1307, USA.
25 */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h> /* abort() is wanted */
33
34 #ifndef EXIT_FAILURE
35 # define EXIT_FAILURE 1
36 #endif
37
38 #include "argmatch.h"
39 #include "error.h"
40 #include "getnum.h"
41 #include "quotearg.h"
42
43 /* Take care of NLS matters. */
44
45 #if ENABLE_NLS
46 # include <libintl.h>
47 # define _(Text) gettext (Text)
48 #else
49 # define _(Text) Text
50 #endif
51
52 /************************************************************************
53 * Get a length/integer in an interval *
54 ************************************************************************/
55 int
get_integer_in_range(const char * option,const char * arg,int min,int max,enum range_type_e range_type)56 get_integer_in_range (const char * option, const char * arg,
57 int min, int max, enum range_type_e range_type)
58 {
59 char buf [256];
60 int res;
61
62 if ((sscanf (arg, "%d%255s", &res, buf) != 1))
63 error (EXIT_FAILURE, 0, _("invalid argument `%s' for `%s'"),
64 quotearg (arg), option);
65
66 buf [0] = '\0'; /* means no error */
67
68 switch (range_type)
69 {
70 case range_min:
71 if (res < min)
72 sprintf (buf, "%d <= n", min);
73 break;
74
75 case range_min_strict:
76 if (res <= min)
77 sprintf (buf, "%d < n", min);
78 break;
79
80 case range_max:
81 if (res > max)
82 sprintf (buf, "n <= %d", max);
83 break;
84
85 case range_max_strict:
86 if (res >= max)
87 sprintf (buf, "n <= %d", max);
88 break;
89
90 case range_min_max:
91 if ((res < min) || (res > max))
92 sprintf (buf, "%d <= n <= %d", min, max);
93 break;
94
95 case range_min_strict_max:
96 if ((res <= min) || (res > max))
97 sprintf (buf, "%d < n <= %d", min, max);
98 break;
99
100 case range_min_max_strict:
101 if ((res < min) || (res >= max))
102 sprintf (buf, "%d <= n < %d", min, max);
103 break;
104
105 case range_min_strict_max_strict:
106 if ((res < min) || (res >= max))
107 sprintf (buf, "%d < n < %d", min, max);
108 break;
109
110 case range_no_limit:
111 break;
112
113 default:
114 abort ();
115 break;
116 }
117
118 if (buf [0])
119 {
120 error (0, 0,
121 _("invalid argument `%s' for `%s'"), quotearg (arg), option);
122 fprintf (stderr,
123 _("Valid arguments are integers n such that: %s\n"), buf);
124 exit (EXIT_FAILURE);
125 }
126 return res;
127 }
128
129 /*
130 * Return a float in a given range, with a specified unit
131 */
132 static float
get_float_in_range(const char * option,const char * arg,const char * const * args_list,float * types_list,float min,float max,const char * unit,enum range_type_e range_type)133 get_float_in_range (const char * option, const char * arg,
134 const char * const * args_list,
135 float * types_list,
136 float min, float max,
137 const char * unit, enum range_type_e range_type)
138 {
139 float res;
140 char buf[256];
141
142 switch (sscanf (arg, "%f%255s", &res, buf))
143 {
144 case 2:
145 /* Multiply by the given unit */
146 res *= XARGCASEMATCH (option, buf, args_list, types_list);
147 break;
148
149 case 1:
150 break;
151
152 default:
153 error (EXIT_FAILURE, 0, _("invalid argument `%s' for `%s'"),
154 quotearg (arg), option);
155 break;
156 }
157
158 /* Divide by the desired unit */
159 res /= types_list [__xargmatch_internal ("internal conversion", unit,
160 args_list,
161 (const char *) types_list,
162 sizeof (*types_list),
163 1, (argmatch_exit_fn) abort)];
164
165 buf [0] = '\0'; /* means no error */
166
167 /* Check that it is in the expected range */
168 switch (range_type)
169 {
170 case range_min:
171 if (res < min)
172 sprintf (buf, "%.1f%s <= f", min, unit);
173 break;
174
175 case range_min_strict:
176 if (res <= min)
177 sprintf (buf, "%.1f%s < f", min, unit);
178 break;
179
180 case range_max:
181 if (res > max)
182 sprintf (buf, "f <= %.1f%s", max, unit);
183 break;
184
185 case range_max_strict:
186 if (res >= max)
187 sprintf (buf, "f <= %.1f%s", max, unit);
188 break;
189
190 case range_min_max:
191 if ((res < min) || (res > max))
192 sprintf (buf, "%.1f%s <= f <= %.1f%s", min, unit, max, unit);
193 break;
194
195 case range_min_strict_max:
196 if ((res <= min) || (res > max))
197 sprintf (buf, "%.1f%s < f <= %.1f%s", min, unit, max, unit);
198 break;
199
200 case range_min_max_strict:
201 if ((res < min) || (res >= max))
202 sprintf (buf, "%.1f%s <= f < %.1f%s", min, unit, max, unit);
203 break;
204
205 case range_min_strict_max_strict:
206 if ((res <= min) || (res >= max))
207 sprintf (buf, "%.1f%s < f < %.1f%s", min, unit, max, unit);
208 break;
209
210 case range_no_limit:
211 break;
212
213 default:
214 abort ();
215 break;
216 }
217
218 if (buf [0])
219 {
220 error (0, 0,
221 _("invalid argument `%s' for `%s'"), quotearg (arg), option);
222 fprintf (stderr,
223 _("Valid arguments are floats f such that: %s\n"), buf);
224 exit (EXIT_FAILURE);
225 }
226
227 return res;
228 }
229
230 /*
231 * Return the ratio to inch
232 */
233 static const char *const length_args[] =
234 {
235 "points", "pts",
236 "inchs",
237 "cm", "centimeters",
238 0
239 };
240
241 static float length_types[] =
242 {
243 1.0, 1.0,
244 72.0,
245 (72 / 2.54), (72 / 2.54)
246 };
247
248 /*
249 * Return a length in the desired unit
250 */
251 float
get_length(const char * option,const char * arg,float min,float max,const char * unit,enum range_type_e range_type)252 get_length (const char * option, const char * arg, float min, float max,
253 const char * unit, enum range_type_e range_type)
254 {
255 return get_float_in_range (option, arg, length_args, length_types,
256 min, max, unit, range_type);
257 }
258