istream.cpp

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C++ 代码 · 共 882 行 · 第 1/2 页

CPP
882
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/

#include "variety.h"
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
#include <streambu>
#include <ioutil.h>
#include <lock.h>

#define ERR_CHAR    '\0'

// **************************** ISTREAM **************************************

// Used by getnumber. Multiplication by 8 is done using a left-shift of
// three bits. Multiplication by 16 is done using a left-shift of four
// bits. Multiplication by 10 is done using a left-shift of three bits
// plus a left-shift of one bit. This table is used to determine if a
// shift will overflow. The number of bits to shift is used to index
// into the table. The table entry is anded with the unsigned long
// number and if any bits are on, then the shift will overflow.

static unsigned long const overFlowMasks[] = {
    0x00000000,
    0x80000000,
    0xC0000000,
    0xE0000000,
    0xF0000000
};

namespace std {

  istream::istream() {
    /******************/
    // Protected constructor, making an istream without a streambuf attached.

    __last_read_length = 0;
    setf( ios::skipws );
  }

  istream::istream( streambuf *sb ) : ios( sb ) {
    /*********************************************/
    // Public constructor, making an istream with a streambuf attached.

    setf( ios::skipws );
  }

  istream::istream( istream const &istrm ) {
    /****************************************/
    // Public copy constructor, make an istream with the istrm streambuf attached.

    streambuf *sb;

    __lock_it( istrm.__i_lock );
    sb = istrm.rdbuf();
    ios::init( sb );
    setf( ios::skipws );
  }


  istream::~istream() {
    /*******************/
    // Destructor.
  }

  istream &istream::operator = ( streambuf *sb ) {
    /**********************************************/
    // *this is an istream that has been initialized, and may or may not
    // have a streambuf associated with it. Associate the streambuf "sb"
    // with the stream.

    __lock_it( __i_lock );
    ios::init( sb );
    return( *this );
  }

  istream &istream::operator = ( istream const &istrm ) {
    /*****************************************************/
    // *this is an istream that has been initialized, and may or may not
    // have a streambuf associated with it. Associate the streambuf
    // found in "istrm" with the stream.

    streambuf *sb;

    __lock_it( __lock_first( __i_lock, istrm.__i_lock ) );
    __lock_it( __lock_second( __i_lock, istrm.__i_lock ) );
    sb = istrm.rdbuf();
    ios::init( sb );
    return( *this );
  }

  int istream::ipfx( int noskipws ) {
    /*********************************/
    // Input prefix.

    __lock_it( __i_lock );
    if( !good() ) {
        __WATCOM_ios::setstate( this, ios::failbit );
        return( 0 );
    }
    __last_read_length = 0;

    // Flush any tied streams, if noskipws == 0
    if( tie() != NULL ) {
        tie()->flush();
    }

    // Skip whitespace if ios::skipws is set and noskipws == 0.
    if( !noskipws && ((flags() & ios::skipws) != 0) ) {
        ws( *this );
        if( eof() ) {
            __WATCOM_ios::setstate( this, ios::failbit );
        }
    }

    // Ensure the error state is still 0:
    return( good() );
  }

  istream &istream::operator >> ( char *buf ) {
    /*******************************************/
    // Input a string of non-whitespace characters into the buffer. If
    // the width is set, read a maximum of that many characters, less
    // one for the NULLCHAR on the end. Otherwise, keep reading until
    // EOF or a whitespace character.

    int c;
    int offset;
    int last_offset;

    offset = 0;
    __lock_it( __i_lock );
    if( ipfx() ) {
        last_offset = width() - 2;
        __lock_it( rdbuf()->__b_lock );
        for( ;; ) {
            if( (width() != 0) && (offset > last_offset) ) {
                break;
            }
            c = rdbuf()->sgetchar();
            if( c == EOF ) {
                if( offset == 0 ) {
                    __WATCOM_ios::setstate( this, ios::eofbit );
                }
                break;
            }
            if( isspace( c ) ) {
                rdbuf()->sputbackc( c );
                break;
            }
            buf[offset++] = (unsigned char)c;
        }
        isfx();
    }
#if 1
    // Borland's implementation does not set failbit if no
    // characters are read.
    if( offset == 0 ) {
        __WATCOM_ios::setstate( this, ios::failbit );
    }
#endif
    width( 0 );
    buf[offset] = '\0';
    return( *this );
  }

  istream &istream::operator >> ( char &c ) {
    /*****************************************/
    // Input a character into "c".

    int ch;

    __lock_it( __i_lock );
    if( ipfx() ) {
        ch = rdbuf()->sgetchar();
        if( ch == EOF ) {
            __WATCOM_ios::setstate( this, ios::eofbit|ios::failbit );
            c = ERR_CHAR;
        } else {
            c = (char)ch;
        }
        isfx();
    }
    return( *this );
  }

  istream &istream::operator >> ( signed short &s ) {
    /*************************************************/

    signed long number;

    __lock_it( __i_lock );
    if( good() ) {
        *this >> number;
        if( number >= 0 ) {
            if( number <= (long)SHRT_MAX ) {
                s = (signed short)number;
            } else {
                __WATCOM_ios::setstate( this, ios::failbit );
            }
        } else {
            if( number >= (long)SHRT_MIN ) {
                s = (signed short)number;
            } else {
                __WATCOM_ios::setstate( this, ios::failbit );
            }
        }
    }
    return( *this );
  }

  istream &istream::operator >> ( unsigned short &s ) {
    /***************************************************/

    unsigned long number;

    __lock_it( __i_lock );
    *this >> number;
    if( good() ) {
        if( number <= USHRT_MAX ) {
            s = (unsigned short)number;
        } else {
            __WATCOM_ios::setstate( this, ios::failbit );
        }
    }
    return( *this );
  }
  
  istream &istream::operator >> ( signed int &i ) {
    /***********************************************/
#if UINT_MAX == USHRT_MAX
    return( *this >> (signed short &) i );
#else
    return( *this >> (signed long &) i );
#endif
  }

  istream &istream::operator >> ( unsigned int &i ) {
    /*************************************************/
#if UINT_MAX == USHRT_MAX
    return( *this >> (unsigned short &) i );
#else
    return( *this >> (unsigned long &) i );
#endif
  }

}

static ios::iostate getsign( streambuf *sb, char &sign, int &base ) {
/*******************************************************************/
// Examine the input for a + or - sign character.

    int ch;

    __lock_it( sb->__b_lock );
    ch = sb->speekc();
    if( ch == EOF ) {
        return( ios::eofbit );
    }
    sign = (char)ch;
    if( (sign == '-') || (sign == '+') ) {
        if( base ) {
            if( base != 10 ) {
                return( ios::failbit );
            }
        } else {
            base = 10;
        }
    } else {
        sign = 0;
    }
    return( ios::goodbit );
}

static ios::iostate getbase( streambuf *sb, int &base, int &offset ) {
/********************************************************************/

    int ch;

    __lock_it( sb->__b_lock );
    ch = sb->speekc();
    if( ch == EOF ) {
        if( offset == 0 ) {
            return( ios::eofbit );
        }
        return( ios::failbit );
    }
    if( ch != '0' ) {
        base = 10;
    } else {
        offset++;
        ch = sb->snextc();
        if( tolower( ch ) == 'x' ) {
            base = 16;
            sb->sbumpc();
            offset++;
        } else {
            base = 8;
            sb->sputbackc( '0' );
            offset--;
        }
    }
    return( ios::goodbit );
}

static ios::iostate getnumber( streambuf *sb, unsigned long &number,
/******************************************************************/
    int base, int &offset ) {
// Extract digits from the stream.
// Stop when a non-digit is found, leaving the non-digit in the stream.
// As digits are read, convert to an "unsigned long".

    unsigned long  result;
    unsigned long  overflow;
    ios::iostate   state;
    int            ch;
    int            is_digit;
    int            digit_value;
    int            shift1;
    int            shift2;

    if( base == 8 ) {
        shift1 = 3;     // *8
        shift2 = 0;
    } else if( base == 16 ) {
        shift1 = 4;     // *16
        shift2 = 0;
    } else {
        shift1 = 3;     // *8
        shift2 = 1;     // *2
    }
    state    = ios::goodbit;
    result   = 0;
    overflow = 0;
    is_digit = TRUE;
    __lock_it( sb->__b_lock );
    while( is_digit ) {
        ch = sb->speekc();
        if( ch == EOF ) {
            if( offset == 0 ) {
                state |= ios::eofbit;
            }
        }
        digit_value = ch - '0';
        if( base == 8 ) {
            is_digit = (ch >= '0'  &&  ch <= '7');
        } else {
            is_digit = isdigit( ch );
            if( base == 16 && !is_digit ) {
                char low_char;
                low_char = (char)tolower( ch );
                if( low_char >= 'a'  &&  low_char <= 'f' ) {
                    digit_value = low_char - 'a' + 10;
                    is_digit    = TRUE;
                }
            }
        }
        if( is_digit ) {
            unsigned long tmp_result = result;
            overflow  |= (result & overFlowMasks[shift1]);
            result   <<= shift1;
            if( shift2 > 0 ) {
                tmp_result <<= shift2;
                if( result > (ULONG_MAX - tmp_result) ) overflow = 1;
                result += tmp_result;
            }
            if( result > ULONG_MAX - digit_value ) overflow = 1;
            result += digit_value;
            sb->sbumpc();
            offset++;
        }
    }
    if( overflow != 0 ) {
        state |= ios::failbit;
    }
    number = result;
    return( state );
}

namespace std {

  istream &istream::operator >> ( signed long &l ) {
    /************************************************/

    char          sign;
    int           base;
    int           offset;
    ios::iostate  state;
    ios::fmtflags format;
    unsigned long number;

    state = ios::goodbit;
    offset = 0;
    __lock_it( __i_lock );
    if( ipfx() ) {
        __lock_it( rdbuf()->__b_lock );
        format = flags() & ios::basefield;
        if( format ) {
            base = __FlagsToBase( format );
        } else {
            base = 0;
        }
        state = getsign( rdbuf(), sign, base );
        if( !state ) {
            if( sign ) {
                rdbuf()->sbumpc();
                offset++;
            }
            if( !base ) {
                state = getbase( rdbuf(), base, offset );

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?