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