Postfix3.3.1
safe_ultostr.c
[詳解]
1 /*++
2 /* NAME
3 /* safe_ultostr 3
4 /* SUMMARY
5 /* convert unsigned long to safe string
6 /* SYNOPSIS
7 /* #include <safe_ultostr.h>
8 /*
9 /* char *safe_ultostr(result, ulval, base, padlen, padchar)
10 /* VSTRING *result;
11 /* unsigned long ulval;
12 /* int base;
13 /* int padlen;
14 /* int padchar;
15 /*
16 /* unsigned long safe_strtoul(start, end, base)
17 /* const char *start;
18 /* char **end;
19 /* int base;
20 /* DESCRIPTION
21 /* The functions in this module perform conversions between
22 /* unsigned long values and "safe" alphanumerical strings
23 /* (strings with digits, uppercase letters and lowercase
24 /* letters, but without the vowels AEIOUaeiou). Specifically,
25 /* the characters B-Z represent the numbers 10-30, and b-z
26 /* represent 31-51.
27 /*
28 /* safe_ultostr() converts an unsigned long value to a safe
29 /* alphanumerical string. This is the reverse of safe_strtoul().
30 /*
31 /* safe_strtoul() implements similar functionality as strtoul()
32 /* except that it uses a safe alphanumerical string as input,
33 /* and that it supports no signs or 0/0x prefixes.
34 /*
35 /* Arguments:
36 /* .IP result
37 /* Buffer for storage of the result of conversion to string.
38 /* .IP ulval
39 /* Unsigned long value.
40 /* .IP base
41 /* Value between 2 and 52 inclusive.
42 /* .IP padlen
43 /* .IP padchar
44 /* Left-pad a short result with padchar characters to the
45 /* specified length. Specify padlen=0 to disable padding.
46 /* .IP start
47 /* Pointer to the first character of the string to be converted.
48 /* .IP end
49 /* On return, pointer to the first character not in the input
50 /* alphabet, or to the string terminator.
51 /* DIAGNOSTICS
52 /* Fatal: out of memory.
53 /*
54 /* safe_strtoul() returns (0, EINVAL) when no conversion could
55 /* be performed, and (ULONG_MAX, ERANGE) in case of overflow.
56 /* LICENSE
57 /* .ad
58 /* .fi
59 /* The Secure Mailer license must be distributed with this software.
60 /* AUTHOR(S)
61 /* Wietse Venema
62 /* IBM T.J. Watson Research
63 /* P.O. Box 704
64 /* Yorktown Heights, NY 10598, USA
65 /*--*/
66 
67 /* System library. */
68 
69 #include <sys_defs.h>
70 #include <stdlib.h>
71 #include <limits.h>
72 #include <errno.h>
73 #include <ctype.h>
74 
75 /* Utility library. */
76 
77 #include <msg.h>
78 #include <vstring.h>
79 #include <mymalloc.h>
80 
81 /* Global library. */
82 
83 #include <safe_ultostr.h>
84 
85 /* Application-specific. */
86 
87 #define STR vstring_str
88 #define END vstring_end
89 #define SWAP(type, a, b) { type temp; temp = a; a = b; b = temp; }
90 
91 static unsigned char safe_chars[] =
92 "0123456789BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
93 
94 #define SAFE_MAX_BASE (sizeof(safe_chars) - 1)
95 #define SAFE_MIN_BASE (2)
96 
97 /* safe_ultostr - convert unsigned long to safe alphanumerical string */
98 
99 char *safe_ultostr(VSTRING *buf, unsigned long ulval, int base,
100  int padlen, int padchar)
101 {
102  const char *myname = "safe_ultostr";
103  char *start;
104  char *last;
105  int i;
106 
107  /*
108  * Sanity check.
109  */
110  if (base < SAFE_MIN_BASE || base > SAFE_MAX_BASE)
111  msg_panic("%s: bad base: %d", myname, base);
112 
113  /*
114  * First accumulate the result, backwards.
115  */
116  VSTRING_RESET(buf);
117  while (ulval != 0) {
118  VSTRING_ADDCH(buf, safe_chars[ulval % base]);
119  ulval /= base;
120  }
121  while (VSTRING_LEN(buf) < padlen)
122  VSTRING_ADDCH(buf, padchar);
123  VSTRING_TERMINATE(buf);
124 
125  /*
126  * Then, reverse the result.
127  */
128  start = STR(buf);
129  last = END(buf) - 1;
130  for (i = 0; i < VSTRING_LEN(buf) / 2; i++)
131  SWAP(int, start[i], last[-i]);
132  return (STR(buf));
133 }
134 
135 /* safe_strtoul - convert safe alphanumerical string to unsigned long */
136 
137 unsigned long safe_strtoul(const char *start, char **end, int base)
138 {
139  const char *myname = "safe_strtoul";
140  static unsigned char *char_map = 0;
141  unsigned char *cp;
142  unsigned long sum;
143  unsigned long div_limit;
144  unsigned long mod_limit;
145  int char_val;
146 
147  /*
148  * Sanity check.
149  */
150  if (base < SAFE_MIN_BASE || base > SAFE_MAX_BASE)
151  msg_panic("%s: bad base: %d", myname, base);
152 
153  /*
154  * One-time initialization. Assume 8-bit bytes.
155  */
156  if (char_map == 0) {
157  char_map = (unsigned char *) mymalloc(256);
158  for (char_val = 0; char_val < 256; char_val++)
159  char_map[char_val] = SAFE_MAX_BASE;
160  for (char_val = 0; char_val < SAFE_MAX_BASE; char_val++)
161  char_map[safe_chars[char_val]] = char_val;
162  }
163 
164  /*
165  * Per-call initialization.
166  */
167  sum = 0;
168  div_limit = ULONG_MAX / base;
169  mod_limit = ULONG_MAX % base;
170 
171  /*
172  * Skip leading whitespace. We don't implement sign/base prefixes.
173  */
174  if (end)
175  *end = (char *) start;
176  while (ISSPACE(*start))
177  ++start;
178 
179  /*
180  * Start the conversion.
181  */
182  errno = 0;
183  for (cp = (unsigned char *) start; (char_val = char_map[*cp]) < base; cp++) {
184  /* Return (ULONG_MAX, ERANGE) if the result is too large. */
185  if (sum > div_limit
186  || (sum == div_limit && char_val > mod_limit)) {
187  sum = ULONG_MAX;
188  errno = ERANGE;
189  /* Skip "valid" characters, per the strtoul() spec. */
190  while (char_map[*++cp] < base)
191  /* void */ ;
192  break;
193  }
194  sum = sum * base + char_val;
195  }
196  /* Return (0, EINVAL) after no conversion. Test moved here 20131209. */
197  if (cp == (unsigned char *) start)
198  errno = EINVAL;
199  else if (end)
200  *end = (char *) cp;
201  return (sum);
202 }
203 
204 #ifdef TEST
205 
206  /*
207  * Proof-of-concept test program. Read a number from stdin, convert to
208  * string, and print the result.
209  */
210 #include <stdio.h> /* sscanf */
211 #include <vstream.h>
212 #include <vstring_vstream.h>
213 
214 int main(int unused_argc, char **unused_argv)
215 {
216  VSTRING *buf = vstring_alloc(100);
217  char *junk;
218  unsigned long ulval;
219  int base;
220  char ch;
221  unsigned long ulval2;
222 
223 #ifdef MISSING_STRTOUL
224 #define strtoul strtol
225 #endif
226 
227  /*
228  * Hard-coded string-to-number test.
229  */
230  ulval2 = safe_strtoul(" ", &junk, 10);
231  if (*junk == 0 || errno != EINVAL)
232  msg_warn("input=' ' result=%lu errno=%m", ulval2);
233 
234  /*
235  * Configurable number-to-string-to-number test.
236  */
237  while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
238  ch = 0;
239  if (sscanf(STR(buf), "%lu %d%c", &ulval, &base, &ch) != 2 || ch) {
240  msg_warn("bad input %s", STR(buf));
241  } else {
242  (void) safe_ultostr(buf, ulval, base, 5, '0');
243  vstream_printf("%lu = %s\n", ulval, STR(buf));
244  ulval2 = safe_strtoul(STR(buf), &junk, base);
245  if (*junk || (ulval2 == ULONG_MAX && errno == ERANGE))
246  msg_warn("%s: %m", STR(buf));
247  if (ulval2 != ulval)
248  msg_warn("%lu != %lu", ulval2, ulval);
249  }
251  }
252  vstring_free(buf);
253  return (0);
254 }
255 
256 #endif
#define VSTREAM_EOF
Definition: vstream.h:110
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
#define SAFE_MAX_BASE
Definition: safe_ultostr.c:94
#define VSTREAM_IN
Definition: vstream.h:66
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VSTRING_RESET(vp)
Definition: vstring.h:77
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define SWAP(type, a, b)
Definition: safe_ultostr.c:89
unsigned long safe_strtoul(const char *start, char **end, int base)
Definition: safe_ultostr.c:137
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
char * safe_ultostr(VSTRING *buf, unsigned long ulval, int base, int padlen, int padchar)
Definition: safe_ultostr.c:99
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define STR
Definition: safe_ultostr.c:87
#define ISSPACE(c)
Definition: sys_defs.h:1753
#define END
Definition: safe_ultostr.c:88
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150