xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/off_cvt.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
1 /*	$NetBSD: off_cvt.c,v 1.2 2020/03/18 19:05:16 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	off_cvt 3
6 /* SUMMARY
7 /*	off_t conversions
8 /* SYNOPSIS
9 /*	#include <off_cvt.h>
10 /*
11 /*	off_t	off_cvt_string(string)
12 /*	const char *string;
13 /*
14 /*	VSTRING	*off_cvt_number(result, offset)
15 /*	VSTRING	*result;
16 /*	off_t	offset;
17 /* DESCRIPTION
18 /*	This module provides conversions between \fIoff_t\fR and string.
19 /*
20 /*	off_cvt_string() converts a string, containing a non-negative
21 /*	offset, to numerical form. The result is -1 in case of problems.
22 /*
23 /*	off_cvt_number() converts a non-negative offset to string form.
24 /*
25 /*	Arguments:
26 /* .IP string
27 /*	String with non-negative number to be converted to off_t.
28 /* .IP result
29 /*	Buffer for storage of the result of conversion to string.
30 /* .IP offset
31 /*	Non-negative off_t value to be converted to string.
32 /* DIAGNOSTICS
33 /*	Panic: negative offset
34 /* LICENSE
35 /* .ad
36 /* .fi
37 /*	The Secure Mailer license must be distributed with this software.
38 /* AUTHOR(S)
39 /*	Wietse Venema
40 /*	IBM T.J. Watson Research
41 /*	P.O. Box 704
42 /*	Yorktown Heights, NY 10598, USA
43 /*
44 /*	Wietse Venema
45 /*	Google, Inc.
46 /*	111 8th Avenue
47 /*	New York, NY 10011, USA
48 /*--*/
49 
50 /* System library. */
51 
52 #include <sys_defs.h>
53 #include <sys/types.h>
54 #include <ctype.h>
55 
56 /* Utility library. */
57 
58 #include <msg.h>
59 #include <vstring.h>
60 
61 /* Global library. */
62 
63 #include "off_cvt.h"
64 
65 /* Application-specific. */
66 
67 #define STR	vstring_str
68 #define END	vstring_end
69 #define SWAP(type, a, b) { type temp; temp = a; a = b; b = temp; }
70 
71 /* off_cvt_string - string to number */
72 
off_cvt_string(const char * str)73 off_t   off_cvt_string(const char *str)
74 {
75     int     ch;
76     off_t   result;
77     off_t   digit_value;
78 
79     /*
80      * Detect overflow before it happens. Code that attempts to detect
81      * overflow after-the-fact makes assumptions about undefined behavior.
82      * Compilers may invalidate such assumptions.
83      */
84     for (result = 0; (ch = *(unsigned char *) str) != 0; str++) {
85 	if (!ISDIGIT(ch))
86 	    return (-1);
87 	digit_value = ch - '0';
88 	if (result > OFF_T_MAX / 10
89 	    || (result *= 10) > OFF_T_MAX - digit_value)
90 	    return (-1);
91 	result += digit_value;
92     }
93     return (result);
94 }
95 
96 /* off_cvt_number - number to string */
97 
off_cvt_number(VSTRING * buf,off_t offset)98 VSTRING *off_cvt_number(VSTRING *buf, off_t offset)
99 {
100     static char digs[] = "0123456789";
101     char   *start;
102     char   *last;
103     int     i;
104 
105     /*
106      * Sanity checks
107      */
108     if (offset < 0)
109 	msg_panic("off_cvt_number: negative offset -%s",
110 		  STR(off_cvt_number(buf, -offset)));
111 
112     /*
113      * First accumulate the result, backwards.
114      */
115     VSTRING_RESET(buf);
116     while (offset != 0) {
117 	VSTRING_ADDCH(buf, digs[offset % 10]);
118 	offset /= 10;
119     }
120     VSTRING_TERMINATE(buf);
121 
122     /*
123      * Then, reverse the result.
124      */
125     start = STR(buf);
126     last = END(buf) - 1;
127     for (i = 0; i < VSTRING_LEN(buf) / 2; i++)
128 	SWAP(int, start[i], last[-i]);
129     return (buf);
130 }
131 
132 #ifdef TEST
133 
134  /*
135   * Proof-of-concept test program. Read a number from stdin, convert to
136   * off_t, back to string, and print the result.
137   */
138 #include <vstream.h>
139 #include <vstring_vstream.h>
140 
main(int unused_argc,char ** unused_argv)141 int     main(int unused_argc, char **unused_argv)
142 {
143     VSTRING *buf = vstring_alloc(100);
144     off_t   offset;
145 
146     while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
147 	if (STR(buf)[0] == '#' || STR(buf)[0] == 0)
148 	    continue;
149 	if ((offset = off_cvt_string(STR(buf))) < 0) {
150 	    msg_warn("bad input %s", STR(buf));
151 	} else {
152 	    vstream_printf("%s\n", STR(off_cvt_number(buf, offset)));
153 	}
154 	vstream_fflush(VSTREAM_OUT);
155     }
156     vstring_free(buf);
157     return (0);
158 }
159 
160 #endif
161