Home | History | Annotate | Line # | Download | only in global
      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