1/*++
2/* NAME
3/*	off_cvt 3
4/* SUMMARY
5/*	off_t conversions
6/* SYNOPSIS
7/*	#include <off_cvt.h>
8/*
9/*	off_t	off_cvt_string(string)
10/*	const char *string;
11/*
12/*	VSTRING	*off_cvt_number(result, offset)
13/*	VSTRING	*result;
14/*	off_t	offset;
15/* DESCRIPTION
16/*	This module provides conversions between \fIoff_t\fR and string.
17/*
18/*	off_cvt_string() converts a string, containing a non-negative
19/*	offset, to numerical form. The result is -1 in case of problems.
20/*
21/*	off_cvt_number() converts a non-negative offset to string form.
22/*
23/*	Arguments:
24/* .IP string
25/*	String with non-negative number to be converted to off_t.
26/* .IP result
27/*	Buffer for storage of the result of conversion to string.
28/* .IP offset
29/*	Non-negative off_t value to be converted to string.
30/* DIAGNOSTICS
31/*	Panic: negative offset
32/* LICENSE
33/* .ad
34/* .fi
35/*	The Secure Mailer license must be distributed with this software.
36/* AUTHOR(S)
37/*	Wietse Venema
38/*	IBM T.J. Watson Research
39/*	P.O. Box 704
40/*	Yorktown Heights, NY 10598, USA
41/*--*/
42
43/* System library. */
44
45#include <sys_defs.h>
46#include <ctype.h>
47
48/* Utility library. */
49
50#include <msg.h>
51#include <vstring.h>
52
53/* Global library. */
54
55#include "off_cvt.h"
56
57/* Application-specific. */
58
59#define STR	vstring_str
60#define END	vstring_end
61#define SWAP(type, a, b) { type temp; temp = a; a = b; b = temp; }
62
63/* off_cvt_string - string to number */
64
65off_t   off_cvt_string(const char *str)
66{
67    int     ch;
68    off_t   result;
69    off_t   res2;
70    off_t   res4;
71    off_t   res8;
72    off_t   res10;
73
74    /*
75     * Multiplication by numbers > 2 can overflow without producing a smaller
76     * result mod 2^N (where N is the number of bits in the result type).
77     * (Victor Duchovni, Morgan Stanley).
78     */
79    for (result = 0; (ch = *(unsigned char *) str) != 0; str++) {
80	if (!ISDIGIT(ch))
81	    return (-1);
82	if ((res2 = result + result) < result)
83	    return (-1);
84	if ((res4 = res2 + res2) < res2)
85	    return (-1);
86	if ((res8 = res4 + res4) < res4)
87	    return (-1);
88	if ((res10 = res8 + res2) < res8)
89	    return (-1);
90	if ((result = res10 + ch - '0') < res10)
91	    return (-1);
92    }
93    return (result);
94}
95
96/* off_cvt_number - number to string */
97
98VSTRING *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
141int     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 ((offset = off_cvt_string(STR(buf))) < 0) {
148	    msg_warn("bad input %s", STR(buf));
149	} else {
150	    vstream_printf("%s\n", STR(off_cvt_number(buf, offset)));
151	}
152	vstream_fflush(VSTREAM_OUT);
153    }
154    vstring_free(buf);
155    return (0);
156}
157
158#endif
159