1 /*	$NetBSD: off_cvt.c,v 1.1.1.1 2009/06/23 10:08:47 tron 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 
45 /* System library. */
46 
47 #include <sys_defs.h>
48 #include <ctype.h>
49 
50 /* Utility library. */
51 
52 #include <msg.h>
53 #include <vstring.h>
54 
55 /* Global library. */
56 
57 #include "off_cvt.h"
58 
59 /* Application-specific. */
60 
61 #define STR	vstring_str
62 #define END	vstring_end
63 #define SWAP(type, a, b) { type temp; temp = a; a = b; b = temp; }
64 
65 /* off_cvt_string - string to number */
66 
67 off_t   off_cvt_string(const char *str)
68 {
69     int     ch;
70     off_t   result;
71     off_t   res2;
72     off_t   res4;
73     off_t   res8;
74     off_t   res10;
75 
76     /*
77      * Multiplication by numbers > 2 can overflow without producing a smaller
78      * result mod 2^N (where N is the number of bits in the result type).
79      * (Victor Duchovni, Morgan Stanley).
80      */
81     for (result = 0; (ch = *(unsigned char *) str) != 0; str++) {
82 	if (!ISDIGIT(ch))
83 	    return (-1);
84 	if ((res2 = result + result) < result)
85 	    return (-1);
86 	if ((res4 = res2 + res2) < res2)
87 	    return (-1);
88 	if ((res8 = res4 + res4) < res4)
89 	    return (-1);
90 	if ((res10 = res8 + res2) < res8)
91 	    return (-1);
92 	if ((result = res10 + ch - '0') < res10)
93 	    return (-1);
94     }
95     return (result);
96 }
97 
98 /* off_cvt_number - number to string */
99 
100 VSTRING *off_cvt_number(VSTRING *buf, off_t offset)
101 {
102     static char digs[] = "0123456789";
103     char   *start;
104     char   *last;
105     int     i;
106 
107     /*
108      * Sanity checks
109      */
110     if (offset < 0)
111 	msg_panic("off_cvt_number: negative offset -%s",
112 		  STR(off_cvt_number(buf, -offset)));
113 
114     /*
115      * First accumulate the result, backwards.
116      */
117     VSTRING_RESET(buf);
118     while (offset != 0) {
119 	VSTRING_ADDCH(buf, digs[offset % 10]);
120 	offset /= 10;
121     }
122     VSTRING_TERMINATE(buf);
123 
124     /*
125      * Then, reverse the result.
126      */
127     start = STR(buf);
128     last = END(buf) - 1;
129     for (i = 0; i < VSTRING_LEN(buf) / 2; i++)
130 	SWAP(int, start[i], last[-i]);
131     return (buf);
132 }
133 
134 #ifdef TEST
135 
136  /*
137   * Proof-of-concept test program. Read a number from stdin, convert to
138   * off_t, back to string, and print the result.
139   */
140 #include <vstream.h>
141 #include <vstring_vstream.h>
142 
143 int     main(int unused_argc, char **unused_argv)
144 {
145     VSTRING *buf = vstring_alloc(100);
146     off_t   offset;
147 
148     while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
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