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 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 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 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