You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
346 lines
10 KiB
346 lines
10 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1997
|
|
//
|
|
// File: parmio.h
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
// PARMIO.H: Parameter file I/O routines
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
#ifndef _PARMIO_H_
|
|
#define _PARMIO_H_
|
|
|
|
#include "stlstream.h"
|
|
|
|
// Parameter defining a named, nestable and iteratable item in a
|
|
// parameter file. There are currently two type: blocks and values.
|
|
// A block is a grouping of values and other blocks. A value is
|
|
// a name = value pair. Blocks are bounded by {}, values are terminated
|
|
// by ';'.
|
|
struct PARMBLK
|
|
{
|
|
enum EPBLK
|
|
{
|
|
EPB_NONE, // nothing
|
|
EPB_VAL, // simple name = value syntax
|
|
EPB_BLK, // named block
|
|
EPB_MAX
|
|
};
|
|
ZSTR _zsName; // Name of value or block
|
|
int _indx; // index (-1 for "not present")
|
|
EPBLK _eBlk; // type of block
|
|
|
|
PARMBLK ( EPBLK eBlk = EPB_NONE, SZC szc = NULL, int indx = -1 )
|
|
: _eBlk( eBlk ),
|
|
_indx(indx)
|
|
{
|
|
if ( szc )
|
|
_zsName = szc;
|
|
}
|
|
bool operator == ( const PARMBLK & pblk ) const;
|
|
bool operator != ( const PARMBLK & pblk ) const;
|
|
bool operator > ( const PARMBLK & pblk ) const;
|
|
bool operator < ( const PARMBLK & pblk ) const;
|
|
};
|
|
|
|
// Define a stack of PARMBLKs; used for output parameter file writing
|
|
class STKPARMBLK : public vector<PARMBLK> {};
|
|
|
|
// Extended descriptor for a block read in from a parameter file.
|
|
// Contains starting and ending offsets within the positionable stream.
|
|
struct PARMBLKIN : PARMBLK
|
|
{
|
|
int _iblkEnd; // index of last+1 item/block in scope of this block
|
|
streamoff _offsBeg; // Starting offset in the stream
|
|
streamoff _offsEnd; // Ending offset in the stream
|
|
streamoff _offsData; // Starting offset of the data in the block
|
|
|
|
PARMBLKIN ( EPBLK eBlk = EPB_NONE, SZC szc = NULL, int indx = -1 )
|
|
: PARMBLK(eBlk,szc,indx),
|
|
_iblkEnd(-1),
|
|
_offsBeg(-1),
|
|
_offsEnd(-1),
|
|
_offsData(-1)
|
|
{
|
|
}
|
|
bool operator == ( const PARMBLKIN & pblkin ) const;
|
|
bool operator != ( const PARMBLKIN & pblkin ) const;
|
|
bool operator > ( const PARMBLKIN & pblkin ) const;
|
|
bool operator < ( const PARMBLKIN & pblkin ) const;
|
|
};
|
|
|
|
// Define a stack of input parameter blocks for parameter file reading
|
|
class STKPARMBLKIN : public vector<PARMBLKIN> {};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Class PARMOUTSTREAM. An output stream of parameters.
|
|
//
|
|
// Blocks and values are written out in sequence. Blocks
|
|
// are opened, filled and closed using member functions
|
|
// and function templates. All unclosed blocks are are
|
|
// closed automatically during close().
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
class PARMOUTSTREAM : public ofstream
|
|
{
|
|
public:
|
|
PARMOUTSTREAM ();
|
|
~ PARMOUTSTREAM ();
|
|
|
|
void close ();
|
|
void StartBlock ( SZC szc = NULL, int indx = -1 );
|
|
void StartItem ( SZC szc = NULL, int indx = -1 );
|
|
bool BEndBlock ();
|
|
bool BEndItem () { return BEndBlock(); }
|
|
void nl ();
|
|
ofstream & Stream ()
|
|
{ return (ofstream&) self; }
|
|
|
|
protected:
|
|
STKPARMBLK _stkblk;
|
|
void StartChunk ( PARMBLK::EPBLK eBlk, SZC szc = NULL, int indx = -1 );
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Class PARMINSTREAM. An input stream of parameters.
|
|
//
|
|
// The input text stream is read once during scan(), and a table of
|
|
// all blocks and values is built. The scan creates an outermost block
|
|
// defining the entire file. Then other blocks are added as discovered,
|
|
// and their starting and ending points are recorded.
|
|
//
|
|
// To use, construct, open() and scan(). Then, find the named section
|
|
// (or value) in question using ifind(), which returns the scoping level.
|
|
// Then, either construct an Iterator (nested class) to walk through the
|
|
// values at that level or use ifind() to locate specific items by name.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
enum EC_PARM_PARSE
|
|
{
|
|
ECPP_PARSE_ERROR = EC_ERR_MIN,
|
|
ECPP_UNMATCHED_QUOTE,
|
|
ECPP_UNEXPECTED_EOF,
|
|
ECPP_INVALID_CLUMP,
|
|
ECPP_INVALID_NAME,
|
|
ECPP_INVALID_BODY,
|
|
};
|
|
|
|
class PARMINSTREAM : public ifstream
|
|
{
|
|
public:
|
|
PARMINSTREAM ();
|
|
~ PARMINSTREAM ();
|
|
|
|
void close();
|
|
// Build the rapid-access table
|
|
void Scan ();
|
|
// Find a block or item at the given level; -1 means "current level",
|
|
// zero means outermost level. Returns index of block or -1 if
|
|
// not found.
|
|
int IblkFind ( SZC szcName, int index = -1, int iblkOuter = -1 );
|
|
// Return the next data block in the array or
|
|
// false if there are no more items.
|
|
const PARMBLKIN * Pparmblk ( int iblk, int iblkOuter = -1 );
|
|
// position the stream to process the parameter
|
|
bool BSeekBlk ( int iblk );
|
|
// read the parameter into a string
|
|
bool BSeekBlkString ( int iblk, ZSTR & zsParam );
|
|
// Pretty-print the block stack with nesting information
|
|
void Dump ();
|
|
// Return true if the block index is legal
|
|
bool BBlkOk ( int iblk ) const
|
|
{ return iblk >= 0 || iblk < _stkblk.size(); }
|
|
int Cblk () const
|
|
{ return _stkblk.size() ; }
|
|
|
|
ifstream & Stream ()
|
|
{ return (ifstream&) self; }
|
|
|
|
class Iterator
|
|
{
|
|
public:
|
|
Iterator( PARMINSTREAM & fprm,
|
|
SZC szcBlock = NULL,
|
|
int index = -1,
|
|
int iblkOuter = -1 );
|
|
const PARMBLKIN * PblkNext ();
|
|
|
|
protected:
|
|
PARMINSTREAM & _fprm;
|
|
int _iblkOuter;
|
|
int _iblk;
|
|
};
|
|
|
|
friend class Iterator;
|
|
|
|
protected:
|
|
STKPARMBLKIN _stkblk; // The block array
|
|
int _iline; // The current line number (parsing)
|
|
ZSTR _zsWhite; // White space character set
|
|
|
|
void ThrowParseError ( SZC szcError,
|
|
int iline = -1,
|
|
EC_PARM_PARSE ecpp = ECPP_PARSE_ERROR );
|
|
int IGetc ();
|
|
bool BIswhite ( char ch );
|
|
void ScanQuote ( char ch );
|
|
void ScanClump ();
|
|
void ScanBlock ( char ch );
|
|
PARMBLK::EPBLK EpblkScanItemBody ( streamoff & offsData );
|
|
int IScanUnwhite ( bool bEofOk = false );
|
|
void ScanItemList ();
|
|
void ScanItemUnit ();
|
|
void ScanItemDesc ( ZSTR & zsName, int & indx ) ;
|
|
void ScanName ( ZSTR & szName );
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Inline functions
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
inline
|
|
PARMINSTREAM & operator >> (PARMINSTREAM & is, ZSTR & zs)
|
|
{
|
|
ios_base::iostate _St = ios_base::goodbit;
|
|
zs.erase();
|
|
const ifstream::sentry _Ok(is);
|
|
if (_Ok)
|
|
{
|
|
_TRY_IO_BEGIN
|
|
size_t _N = 0 < is.width() && is.width() < zs.max_size()
|
|
? is.width()
|
|
: zs.max_size();
|
|
int _C = is.rdbuf()->sgetc();
|
|
bool bmeta = false;
|
|
bool bfirst = true;
|
|
for (; 0 < --_N; _C = is.rdbuf()->snextc())
|
|
{
|
|
if(char_traits<char>::eq_int_type(char_traits<char>::eof(), _C))
|
|
{
|
|
_St |= ios_base::eofbit;
|
|
break;
|
|
}
|
|
else
|
|
if ( ! bmeta && _C == CH_DELM_STR )
|
|
{
|
|
if ( ! bfirst )
|
|
{
|
|
is.rdbuf()->snextc();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if ( _C == CH_META && ! bmeta )
|
|
{
|
|
bmeta = true;
|
|
}
|
|
else
|
|
{
|
|
bmeta = false;
|
|
zs.append(1, char_traits<char>::to_char_type(_C));
|
|
}
|
|
bfirst = false;
|
|
}
|
|
_CATCH_IO_(is);
|
|
}
|
|
else
|
|
{
|
|
_THROW1(runtime_error("file exhausted extracting string"));
|
|
}
|
|
is.width(0);
|
|
is.setstate(_St);
|
|
return is;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Template functions for parameter streams
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Write SZC: no corresponding read, since no buffer exists
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
inline
|
|
PARMOUTSTREAM & operator << (PARMOUTSTREAM & ofs, SZC szc)
|
|
{
|
|
ofs << CH_DELM_STR;
|
|
|
|
for ( ; *szc ; )
|
|
{
|
|
char ch = *szc++;
|
|
if ( ch == CH_DELM_STR || ch == CH_META )
|
|
{
|
|
if (char_traits<char>::eq_int_type(char_traits<char>::eof(),
|
|
ofs.rdbuf()->sputc(CH_META)))
|
|
break;
|
|
}
|
|
if (char_traits<char>::eq_int_type(char_traits<char>::eof(),
|
|
ofs.rdbuf()->sputc(ch)))
|
|
break;
|
|
}
|
|
ofs << CH_DELM_STR;
|
|
return ofs;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Read and write ZSTRs
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
inline
|
|
PARMOUTSTREAM & operator << (PARMOUTSTREAM & ofs, const ZSTR & zs)
|
|
{
|
|
ofs << CH_DELM_STR;
|
|
|
|
for ( int ich = 0; ich < zs.size(); ++ich)
|
|
{
|
|
char ch = zs.at(ich);
|
|
if ( ch == CH_DELM_STR || ch == CH_META )
|
|
{
|
|
if (char_traits<char>::eq_int_type(char_traits<char>::eof(),
|
|
ofs.rdbuf()->sputc(CH_META)))
|
|
break;
|
|
}
|
|
if (char_traits<char>::eq_int_type(char_traits<char>::eof(),
|
|
ofs.rdbuf()->sputc(ch)))
|
|
break;
|
|
}
|
|
if ( ich < zs.size() )
|
|
_THROW1(runtime_error("file exhausted inserting string"));
|
|
|
|
ofs << CH_DELM_STR;
|
|
return ofs;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Simple parameter output routines using insertion
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
template<class T> inline
|
|
PARMOUTSTREAM & AddParamValue ( PARMOUTSTREAM & fprm, const T & t, SZC szc, int indx = -1 )
|
|
{
|
|
fprm.StartItem( szc, indx );
|
|
fprm << (const T &) t;
|
|
fprm.BEndItem();
|
|
return fprm;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Simple parameter input routines using extraction
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
template<class T> inline
|
|
bool BGetParamValue ( PARMINSTREAM & fprm, T & t, SZC szc, int index = -1, int iblkOuter = -1 )
|
|
{
|
|
int iblk = fprm.IblkFind(szc, index, iblkOuter);
|
|
if ( iblk < 0 )
|
|
return false;
|
|
fprm.BSeekBlk(iblk);
|
|
fprm >> t;
|
|
return true;
|
|
}
|
|
|
|
#endif
|