lengthdemo.C
Click here to get the file
Size
5.9 kB
-
File type
text/plain
File contents
/*ident "@(#)cls4:demo/stream/lengthdemo.C 1.1" */
/*******************************************************************************
C++ source for the C++ Language System, Release 3.0. This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.
Copyright (c) 1991 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T. All Rights Reserved.
THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc. The copyright notice above does not evidence
any actual or intended publication of such source code.
*******************************************************************************/
#include "lengthdemo.h"
int xunit ;
static const int max_unit_name_len = 32 ;
// Used to size an array for extracting units.
const Unit Unit::tbl[] = { // Standard Unit is first element
// Warning: max_unit_name_len must as great as maximum length
// of string used as a unit.
{ "in", 1. }, // inches
{ "feet", 12.}, // feet
{ "mi", 5280. * 12. }, // miles
{ "m", 39.37079 }, // meters
} ;
Length::Length(float v,const Unit* u)
: standard( u ? v * u->scale : v )
{ }
Length::Length() { }
float Length::value(const Unit* u)
{
return u ? standard / u->scale : standard ;
}
const Unit* Unit::lookup(char* u)
{
// Looks up u, returns a pointer to the Unit designated by
// u or 0 if u does not designate a Unit.
if ( !u ) return tbl ;
for ( int x = 0 ; x < sizeof(tbl)/sizeof(*tbl) ; ++x ) {
if ( strcmp(tbl[x].name,u) == 0 ) return &tbl[x] ;
}
return 0 ;
}
ostream& operator<<(ostream& out, Length len)
{
// Inserts the Length len, using the streams default unit.
const Unit* u = (const Unit*)out.pword(xunit) ;
out << (double)len.value(u) ;
if ( u ) out << u->name ;
return out ;
}
istream& operator>>(istream& in, Length& len)
{
float v ; // Floating number in istream
char str[max_unit_name_len] ; // Unit in istream
const Unit* u = (const Unit*)in.pword(xunit) ;
// Default unit
in>>v ;
if ( in && !isspace(in.peek()) ) {
// The next character is not whitespace, so it should
// be a unit.
// Note use of setw to avoid overflow of str in case
// input is bad.
in >> setw(sizeof(str)) >> str ;
u = Unit::lookup(str) ;
// If Unit wasn't legal (u==0), we consider it a formating
// failure. We use "clear" to set the error state of "in".
// "in.rdstate()" is the current value. We or in
// "ios::failbit". The previous state might have been
// set non-zero when we read str.
if ( !u ) in.clear(ios::failbit|in.rdstate()) ;
}
len = Length(v,u) ;
return in ;
}
static ios& setufct(ios& s, const Unit* u) {
// function to set the default unit of s.
s.pword(xunit) = (void*)u ;
return s ;
}
SMANIP(pcUnit) setu(const Unit* u) {
// Convert the function to a "manipulator". setufct can
// be used directly, but a manipulator is often more convenient.
return SMANIP(pcUnit)(setufct,u) ;
}
static Iostream_init* iosi ;
// The iostream library uses the initialization technique
// implemented by Length_init. Namely, construction of
// an Iostream_init causes it to be initialized.
int Length_init::count = 0 ;
Length_init::Length_init()
{
if ( count++ > 0 ) return ;
// do these things only the first time this constructor is
// called.
iosi = new Iostream_init ; // initialize iostream library
xunit = ios::xalloc() ;
// get a unique index for the default unit. Using
// ios::xalloc() to get an index instead of picking
// one arbitrarily allows the Length library to coexist
// with other libraries with user defined state variables.
// Make sure state variable is initialized in predefined streams
cin.pword(xunit) = 0 ;
cout.pword(xunit) = 0 ;
cerr.pword(xunit) = 0 ;
clog.pword(xunit) = 0 ;
}
Length_init::~Length_init()
{
if ( --count > 0 ) return ;
// If we assume that a the Length_init destructor is called
// for every Length_init that is ever constructed then we
// reach here exactly once. Namely when every Length_init
// that is constructed has been unconstructed. This should be
// after any possible use of the library.
delete iosi ;
// don't forget to unconstruct the Iostream_init.
// The predefined streams are closed by the last
// call to the Iostream_init destructor, so we have
// to make sure they balance.
}
/**************
*
* What follows is a sample program. It takes Lengths from its
* command arguments or from cin. It prints each length on its
* cout.
*
**************/
const Unit* feet = Unit::lookup("feet") ;
const Unit* meter = Unit::lookup("m") ;
void outlen(Length len)
{
// Print len in various units.
cout << setu(0);
cout << len;
cout << " = ";
cout << setu(feet);
cout << len;
cout << " = ";
cout << setu(meter);
cout << len;
cout << endl;
// endl both inserts new line and flushes cout.
}
int main(int argc, char** argv )
{
// This main is just a sample of how the above might be
// used. If it has arguments, it prints them. If it
// doesn't, then it reads Lengths from standard input and
// prints them.
Length len ;
cout.precision(4) ;
// Output with low precision to avoid machine dependencies.
for ( int arg = 1 ; arg < argc ; ++arg ) {
// We will use an "in core string stream" to do
// the conversion
istrstream a(argv[arg]) ;
a >> len ;
if ( !a ) {
cerr << "cannot interpret " << argv[arg] << endl ;
return 1 ;
}
outlen(len) ;
} ;
if ( argc <= 1 ) {
// No arguments, so read from cin.
while ( cin >> len ) outlen(len) ;
// Normally we stop at end of file with both ios::eofbit
// and ios::badbit set in the error state of cin.
// The former because we reached eof, the latter because
// the last call to the extractor didn't store a good
// value into len.
if ( cin.fail() && !cin.eof() ) {
cerr << "badly formatted input" << endl ;
return 1 ;
}
}
if ( !cout ) {
cerr << "output error" << endl ;
return 1 ;
}
return 0 ;
}