view src/basic/conv.d @ 207:e0551773a005

Added the correct version.
author Anders Johnsen <skabet@gmail.com>
date Tue, 12 Aug 2008 18:19:34 +0200
parents
children
line wrap: on
line source


// Written in the D programming language.

/*
 *  Copyright (C) 2002-2006 by Digital Mars, www.digitalmars.com
 *  Written by Walter Bright
 *  Some parts contributed by David L. Davis
 *
 *  This software is provided 'as-is', without any express or implied
 *  warranty. In no event will the authors be held liable for any damages
 *  arising from the use of this software.
 *
 *  Permission is granted to anyone to use this software for any purpose,
 *  including commercial applications, and to alter it and redistribute it
 *  freely, subject to the following restrictions:
 *
 *  o  The origin of this software must not be misrepresented; you must not
 *     claim that you wrote the original software. If you use this software
 *     in a product, an acknowledgment in the product documentation would be
 *     appreciated but is not required.
 *  o  Altered source versions must be plainly marked as such, and must not
 *     be misrepresented as being the original software.
 *  o  This notice may not be removed or altered from any source
 *     distribution.
 */

/***********
 * Conversion building blocks. These differ from the C equivalents
 * <tt>atoi()</tt> and <tt>atol()</tt> by
 * checking for overflow and not allowing whitespace.
 *
 * For conversion to signed types, the grammar recognized is:
 * <pre>
$(I Integer):
    $(I Sign UnsignedInteger)
    $(I UnsignedInteger)

$(I Sign):
    $(B +)
    $(B -)
 * </pre>
 * For conversion to signed types, the grammar recognized is:
 * <pre>
$(I UnsignedInteger):
    $(I DecimalDigit)
    $(I DecimalDigit) $(I UnsignedInteger)
 * </pre>
 * Macros:
 *	WIKI=Phobos/StdConv
 */


/*************************
  Changed to be used next to tango.

  Unittests removed.
 *************************/

module basic.conv;

private import tango.text.Util;  // for atof(), toString()
private import tango.stdc.stringz;
private import tango.stdc.ctype;
private import tango.stdc.stdlib;
private import tango.stdc.errno;
//private import std.c.stdlib;
//private import std.math;  // for fabs(), isnan()

private
{
    extern (C) int getErrno();
    extern (C) int setErrno(int);
}

//debug=conv;		// uncomment to turn on debugging printf's

/* ************* Exceptions *************** */

/**
 * Thrown on conversion errors, which happens on deviation from the grammar.
 */
class ConvError : Exception
{
    this(char[] s)
    {
	super("conversion " ~ s);
    }
}

private void conv_error(char[] s)
{
    throw new ConvError(s);
}

/**
 * Thrown on conversion overflow errors.
 */
class ConvOverflowError : Exception
{
    this(char[] s)
    {
	super("Error: overflow " ~ s);
    }
}

private void conv_overflow(char[] s)
{
    throw new ConvOverflowError(s);
}

/***************************************************************
 * Convert character string to the return type.
 */

int toInt(char[] s)
{
    int length = s.length;

    if (!length)
	goto Lerr;

    int sign = 0;
    int v = 0;

    for (int i = 0; i < length; i++)
    {
	char c = s[i];
	if (c >= '0' && c <= '9')
	{
	    if (v < int.max/10 || (v == int.max/10 && c + sign <= '7'))
		v = v * 10 + (c - '0');
	    else
		goto Loverflow;
	}
	else if (c == '-' && i == 0)
	{
	    sign = -1;
	    if (length == 1)
		goto Lerr;
	}
	else if (c == '+' && i == 0)
	{
	    if (length == 1)
		goto Lerr;
	}
	else
	    goto Lerr;
    }
    if (sign == -1)
    {
	if (cast(uint)v > 0x80000000)
	    goto Loverflow;
	v = -v;
    }
    else
    {
	if (cast(uint)v > 0x7FFFFFFF)
	    goto Loverflow;
    }
    return v;

Loverflow:
    conv_overflow(s);

Lerr:
    conv_error(s);
    return 0;
}

/*******************************************************
 * ditto
 */

uint toUint(char[] s)
{
    int length = s.length;

    if (!length)
	goto Lerr;

    uint v = 0;

    for (int i = 0; i < length; i++)
    {
	char c = s[i];
	if (c >= '0' && c <= '9')
	{
	    if (v < uint.max/10 || (v == uint.max/10 && c <= '5'))
		v = v * 10 + (c - '0');
	    else
		goto Loverflow;
	}
	else
	    goto Lerr;
    }
    return v;

Loverflow:
    conv_overflow(s);

Lerr:
    conv_error(s);
    return 0;
}

/*******************************************************
 * ditto
 */

long toLong(char[] s)
{
    int length = s.length;

    if (!length)
	goto Lerr;

    int sign = 0;
    long v = 0;

    for (int i = 0; i < length; i++)
    {
	char c = s[i];
	if (c >= '0' && c <= '9')
	{
	    if (v < long.max/10 || (v == long.max/10 && c + sign <= '7'))
		v = v * 10 + (c - '0');
	    else
		goto Loverflow;
	}
	else if (c == '-' && i == 0)
	{
	    sign = -1;
	    if (length == 1)
		goto Lerr;
	}
	else if (c == '+' && i == 0)
	{
	    if (length == 1)
		goto Lerr;
	}
	else
	    goto Lerr;
    }
    if (sign == -1)
    {
	if (cast(ulong)v > 0x8000000000000000)
	    goto Loverflow;
	v = -v;
    }
    else
    {
	if (cast(ulong)v > 0x7FFFFFFFFFFFFFFF)
	    goto Loverflow;
    }
    return v;

Loverflow:
    conv_overflow(s);

Lerr:
    conv_error(s);
    return 0;
}

/*******************************************************
 * ditto
 */

ulong toUlong(char[] s)
{
    int length = s.length;

    if (!length)
	goto Lerr;

    ulong v = 0;

    for (int i = 0; i < length; i++)
    {
	char c = s[i];
	if (c >= '0' && c <= '9')
	{
	    if (v < ulong.max/10 || (v == ulong.max/10 && c <= '5'))
		v = v * 10 + (c - '0');
	    else
		goto Loverflow;
	}
	else
	    goto Lerr;
    }
    return v;

Loverflow:
    conv_overflow(s);

Lerr:
    conv_error(s);
    return 0;
}

/*******************************************************
 * ditto
 */

short toShort(char[] s)
{
    int v = toInt(s);

    if (v != cast(short)v)
	goto Loverflow;

    return cast(short)v;

Loverflow:
    conv_overflow(s);
    return 0;
}

/*******************************************************
 * ditto
 */

ushort toUshort(char[] s)
{
    uint v = toUint(s);

    if (v != cast(ushort)v)
	goto Loverflow;

    return cast(ushort)v;

Loverflow:
    conv_overflow(s);
    return 0;
}

/*******************************************************
 * ditto
 */

byte toByte(char[] s)
{
    int v = toInt(s);

    if (v != cast(byte)v)
	goto Loverflow;

    return cast(byte)v;

Loverflow:
    conv_overflow(s);
    return 0;
}

/*******************************************************
 * ditto
 */

ubyte toUbyte(char[] s)
{
    uint v = toUint(s);

    if (v != cast(ubyte)v)
	goto Loverflow;

    return cast(ubyte)v;

Loverflow:
    conv_overflow(s);
    return 0;
}

/*******************************************************
 * ditto
 */

float toFloat(in char[] s)
{
    float f;
    char* endptr;
    char* sz;

    //writefln("toFloat('%s')", s);
    sz = toStringz(s);
    if (tango.stdc.ctype.isspace(*sz))
	goto Lerr;

    // BUG: should set __locale_decpoint to "." for DMC

    setErrno(0);
    f = strtof(sz, &endptr);
    if (getErrno() == ERANGE)
	goto Lerr;
    if (endptr && (endptr == sz || *endptr != 0))
	goto Lerr;

    return f;
        
  Lerr:
    conv_error(s ~ " not representable as a float");
    assert(0);
}

/*******************************************************
 * ditto
 */

double toDouble(in char[] s)
{
    double f;
    char* endptr;
    char* sz;

    //writefln("toDouble('%s')", s);
    sz = toStringz(s);
    if (tango.stdc.ctype.isspace(*sz))
	goto Lerr;

    // BUG: should set __locale_decpoint to "." for DMC

    setErrno(0);
    f = strtod(sz, &endptr);
    if (getErrno() == ERANGE)
	goto Lerr;
    if (endptr && (endptr == sz || *endptr != 0))
	goto Lerr;

    return f;
        
  Lerr:
    conv_error(s ~ " not representable as a double");
    assert(0);
}

/*******************************************************
 * ditto
 */
real toReal(in char[] s)
{
    real f;
    char* endptr;
    char* sz;

    //writefln("toReal('%s')", s);
    sz = toStringz(s);
    if (tango.stdc.ctype.isspace(*sz))
	goto Lerr;

    // BUG: should set __locale_decpoint to "." for DMC

    setErrno(0);
    f = strtold(sz, &endptr);
    if (getErrno() == ERANGE)
	goto Lerr;
    if (endptr && (endptr == sz || *endptr != 0))
	goto Lerr;

    return f;
        
  Lerr:
    conv_error(s ~ " not representable as a real");
    assert(0);
}