windows-nt/Source/XPSP1/NT/enduser/troubleshoot/bn/parmio.h
2020-09-26 16:20:57 +08:00

347 lines
9.7 KiB
C++

//+-------------------------------------------------------------------------
//
// 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