Leaked source code of windows server 2003
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.

613 lines
12 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: parmio.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //////////////////////////////////////////////////////////////////////////////////
  11. //
  12. // PARMIO.CPP: Parameter file I/O routines
  13. //
  14. //////////////////////////////////////////////////////////////////////////////////
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <algorithm>
  18. #include <iostream>
  19. #include <fstream>
  20. #include <iomanip>
  21. #include <ctype.h>
  22. #include "parmio.h"
  23. PARMOUTSTREAM :: PARMOUTSTREAM ()
  24. {
  25. }
  26. PARMOUTSTREAM :: ~ PARMOUTSTREAM ()
  27. {
  28. close();
  29. }
  30. void PARMOUTSTREAM :: close ()
  31. {
  32. while ( BEndBlock() );
  33. ofstream::close();
  34. }
  35. void PARMOUTSTREAM :: StartChunk (
  36. PARMBLK::EPBLK eBlk,
  37. SZC szc,
  38. int indx )
  39. {
  40. _stkblk.push_back( PARMBLK(eBlk,szc,indx) );
  41. const PARMBLK & prmblk = _stkblk.back();
  42. self.nl();
  43. if ( szc )
  44. {
  45. Stream() << szc;
  46. if ( indx >= 0 )
  47. {
  48. self << CH_INDEX_OPEN << indx << CH_INDEX_CLOSE;
  49. }
  50. }
  51. switch( prmblk._eBlk )
  52. {
  53. case PARMBLK::EPB_VAL:
  54. if ( szc )
  55. self << CH_EQ;
  56. break;
  57. case PARMBLK::EPB_BLK:
  58. self.nl();
  59. self << CH_BLOCK_OPEN;
  60. break;
  61. }
  62. }
  63. void PARMOUTSTREAM :: StartBlock (
  64. SZC szc,
  65. int indx )
  66. {
  67. StartChunk( PARMBLK::EPB_BLK, szc, indx );
  68. }
  69. void PARMOUTSTREAM :: StartItem (
  70. SZC szc,
  71. int indx )
  72. {
  73. StartChunk( PARMBLK::EPB_VAL, szc, indx );
  74. }
  75. bool PARMOUTSTREAM :: BEndBlock ()
  76. {
  77. if ( _stkblk.size() == 0 )
  78. return false;
  79. const PARMBLK & prmblk = _stkblk.back();
  80. switch( prmblk._eBlk )
  81. {
  82. case PARMBLK::EPB_VAL:
  83. self << CH_DELM_ENTRY;
  84. break;
  85. case PARMBLK::EPB_BLK:
  86. nl();
  87. self << CH_BLOCK_CLOSE;
  88. break;
  89. }
  90. _stkblk.pop_back();
  91. return true;
  92. }
  93. void PARMOUTSTREAM :: nl ()
  94. {
  95. self << '\n';
  96. for ( int i = 1 ; i < _stkblk.size(); ++i)
  97. {
  98. self << '\t';
  99. }
  100. }
  101. /*
  102. The general YACC-style form of a parameter file is:
  103. itemlist : // empty
  104. | itemlist itemunit
  105. ;
  106. itemunit : itemdesc itembody
  107. ;
  108. itemdesc : itemname '[' itemindex ']'
  109. | itemname
  110. ;
  111. itembody : itemblock ';'
  112. | itemvalue ';'
  113. ;
  114. itemblock : '{' itemlist '}'
  115. ;
  116. itemvalue : '=' itemclump
  117. ;
  118. An "itemclump" is a self-describing value, comprised of quoted
  119. strings and parenthetically nested blocks.
  120. */
  121. static const char rgchWhite [] =
  122. {
  123. ' ',
  124. '\n',
  125. '\t',
  126. '\r',
  127. 0
  128. };
  129. PARMINSTREAM :: PARMINSTREAM ()
  130. : _iline(0),
  131. _zsWhite(rgchWhite)
  132. {
  133. }
  134. PARMINSTREAM :: ~ PARMINSTREAM ()
  135. {
  136. }
  137. void PARMINSTREAM :: close()
  138. {
  139. _stkblk.clear();
  140. ifstream::close();
  141. }
  142. bool PARMINSTREAM :: BIswhite ( char ch )
  143. {
  144. return _zsWhite.find(ch) < _zsWhite.length() ;
  145. }
  146. int PARMINSTREAM :: IGetc ()
  147. {
  148. char ich;
  149. self >> ich;
  150. if ( ich == '\n' )
  151. _iline++;
  152. return ich;
  153. }
  154. void PARMINSTREAM :: ScanQuote ( char ch )
  155. {
  156. int imeta = 2;
  157. int iline = _iline;
  158. do
  159. {
  160. int chNext = IGetc();
  161. if ( rdstate() & ios::eofbit )
  162. ThrowParseError("EOF in quote", iline, ECPP_UNMATCHED_QUOTE);
  163. switch ( chNext )
  164. {
  165. case '\'':
  166. case '\"':
  167. if ( imeta != 1 && ch == chNext )
  168. imeta = -1;
  169. else
  170. ScanQuote((char)chNext);
  171. break;
  172. case '\\':
  173. imeta = 0;
  174. break;
  175. default:
  176. assert( chNext >= 0 );
  177. break;
  178. }
  179. if ( imeta++ < 0 )
  180. break;
  181. }
  182. while ( true );
  183. }
  184. void PARMINSTREAM :: ScanBlock ( char ch )
  185. {
  186. int iline = _iline;
  187. do
  188. {
  189. int chNext = IGetc();
  190. if ( rdstate() & ios::eofbit )
  191. ThrowParseError("EOF in block", iline, ECPP_UNEXPECTED_EOF);
  192. switch ( chNext )
  193. {
  194. case CH_DELM_OPEN:
  195. ScanBlock((char)chNext);
  196. break;
  197. case CH_DELM_CLOSE:
  198. return;
  199. break;
  200. case '\'':
  201. case '\"':
  202. ScanQuote((char)chNext);
  203. break;
  204. default:
  205. assert( chNext >= 0 );
  206. break;
  207. }
  208. }
  209. while ( true );
  210. }
  211. int PARMINSTREAM :: IScanUnwhite ( bool bEofOk )
  212. {
  213. int chNext;
  214. do
  215. {
  216. chNext = IGetc();
  217. if ( rdstate() & ios::eofbit )
  218. {
  219. if ( bEofOk )
  220. return -1;
  221. ThrowParseError("Unexpected EOF", -1, ECPP_UNEXPECTED_EOF);
  222. }
  223. }
  224. while ( BIswhite((char)chNext) ) ;
  225. return chNext;
  226. }
  227. void PARMINSTREAM :: ScanClump ()
  228. {
  229. int iline = _iline;
  230. char chNext;
  231. do
  232. {
  233. switch ( chNext = (char)IScanUnwhite() )
  234. {
  235. case CH_DELM_ENTRY: // ';'
  236. putback(chNext);
  237. return;
  238. break;
  239. case CH_DELM_OPEN: // '('
  240. ScanBlock( chNext );
  241. break;
  242. case '\'':
  243. case '\"':
  244. ScanQuote( chNext );
  245. break;
  246. }
  247. }
  248. while ( true );
  249. }
  250. void PARMINSTREAM :: ScanName ( ZSTR & zsName )
  251. {
  252. zsName.empty();
  253. /*for ( char chNext = IScanUnwhite();
  254. zsName.length() ? __iscsymf(chNext) : __iscsym(chNext) ;
  255. chNext = IGetc() )
  256. {
  257. zsName += chNext;
  258. } */
  259. // This loop is giving me errors when there is a digit in a name...
  260. // I think that the ? and : are reversed. __iscsymf is false if
  261. // the character is a digit... I assume that the required behavior
  262. // is that a digit cannot be the first character in a name, as opposed
  263. // to a digit can ONLY be the first character:
  264. for ( char chNext = (char)IScanUnwhite(); ; chNext = (char)IGetc() )
  265. {
  266. if (zsName.length() == 0)
  267. {
  268. if (__iscsymf(chNext) == false)
  269. {
  270. // Looking for the first character in a name, and
  271. // the next character is not a letter or an underscore:
  272. // stop parsing the name.
  273. break;
  274. }
  275. }
  276. else
  277. {
  278. // (Max) 2/1/97
  279. //
  280. // I'm using '?' in names to denote booleans... this seems
  281. // to be reasonable, but if someone has objections this
  282. // can change
  283. if (__iscsym(chNext) == false && chNext != '?')
  284. {
  285. // Reached the end of a string of alpha-numeric
  286. // characters: stop parsing the name.
  287. break;
  288. }
  289. }
  290. // The next character is a valid extension of the current
  291. // name: append to the name and continue
  292. zsName += chNext;
  293. }
  294. putback(chNext);
  295. }
  296. void PARMINSTREAM :: ScanItemDesc ( ZSTR & zsName, int & indx )
  297. {
  298. zsName.empty();
  299. indx = -1;
  300. ScanName(zsName);
  301. if ( zsName.length() == 0 )
  302. ThrowParseError("Invalid item or block name", -1, ECPP_INVALID_NAME );
  303. int chNext = IScanUnwhite();
  304. if ( chNext == CH_INDEX_OPEN )
  305. {
  306. self >> indx;
  307. chNext = IScanUnwhite();
  308. if ( chNext != CH_INDEX_CLOSE )
  309. ThrowParseError("Invalid item or block name", -1, ECPP_INVALID_NAME );
  310. }
  311. else
  312. putback((char)chNext);
  313. }
  314. PARMBLK::EPBLK PARMINSTREAM :: EpblkScanItemBody ( streamoff & offsData )
  315. {
  316. int iline = _iline;
  317. int ch = IScanUnwhite();
  318. PARMBLK::EPBLK epblk = PARMBLK::EPB_NONE;
  319. offsData = tellg();
  320. switch ( ch )
  321. {
  322. case CH_EQ:
  323. // 'itemvalue'
  324. ScanClump();
  325. epblk = PARMBLK::EPB_VAL;
  326. ch = IScanUnwhite();
  327. if ( ch != CH_DELM_ENTRY )
  328. ThrowParseError("Invalid item or block body", iline, ECPP_INVALID_BODY );
  329. break;
  330. case CH_BLOCK_OPEN:
  331. // 'itemblock'
  332. ScanItemList();
  333. epblk = PARMBLK::EPB_BLK;
  334. break;
  335. default:
  336. ThrowParseError("Invalid item or block body", iline, ECPP_INVALID_BODY );
  337. break;
  338. }
  339. return epblk;
  340. }
  341. void PARMINSTREAM :: ScanItemUnit ()
  342. {
  343. // Save the index of the current block
  344. int iblk = _stkblk.size() - 1;
  345. {
  346. PARMBLKIN & blkin = _stkblk[iblk];
  347. blkin._iblkEnd = iblk;
  348. blkin._offsEnd = blkin._offsBeg = tellg();
  349. ScanItemDesc( blkin._zsName, blkin._indx );
  350. }
  351. // Because the block stack vector is reallocated within
  352. // this recursively invoked routine, we must be careful
  353. // to reestablish the address of the block.
  354. streamoff offsData;
  355. PARMBLK::EPBLK eblk = EpblkScanItemBody( offsData );
  356. {
  357. PARMBLKIN & blkin = _stkblk[iblk];
  358. blkin._eBlk = eblk ;
  359. blkin._offsEnd = tellg();
  360. --blkin._offsEnd;
  361. blkin._offsData = offsData;
  362. if ( eblk == PARMBLK::EPB_BLK )
  363. blkin._iblkEnd = _stkblk.size();
  364. }
  365. }
  366. void PARMINSTREAM :: ScanItemList ()
  367. {
  368. for ( int ch = IScanUnwhite(true);
  369. ch != CH_BLOCK_CLOSE ;
  370. ch = IScanUnwhite(true) )
  371. {
  372. if ( rdstate() & ios::eofbit )
  373. return;
  374. putback((char)ch);
  375. _stkblk.resize( _stkblk.size() + 1 );
  376. ScanItemUnit();
  377. }
  378. }
  379. void PARMINSTREAM :: ThrowParseError (
  380. SZC szcError,
  381. int iline,
  382. EC_PARM_PARSE ecpp )
  383. {
  384. ZSTR zsErr;
  385. if ( iline < 0 )
  386. iline = _iline;
  387. zsErr.Format( "Parameter file parse error, line %d: %s",
  388. szcError, iline );
  389. throw GMException( ECGM(ecpp), zsErr );
  390. }
  391. // Build the rapid-access table
  392. void PARMINSTREAM :: Scan ()
  393. {
  394. _stkblk.clear();
  395. _iline = 0;
  396. seekg( 0 );
  397. ScanItemList();
  398. clear();
  399. seekg( 0 );
  400. }
  401. // Find a block or item by name (and index). 'iblk' of -1
  402. // means "any block"; zero means at the outermost level.
  403. // Return subscript of block/item or -1 if not found.
  404. int PARMINSTREAM :: IblkFind ( SZC szcName, int index, int iblkOuter )
  405. {
  406. int iblk = 0;
  407. int iblkEnd = _stkblk.size();
  408. if ( iblkOuter >= 0 )
  409. {
  410. // We have outer block scope, validate it
  411. if ( ! BBlkOk( iblkOuter ) )
  412. return -1;
  413. iblk = iblkOuter + 1;
  414. iblkEnd = _stkblk[iblkOuter]._iblkEnd;
  415. }
  416. ZSTR zsName(szcName);
  417. for ( ; iblk < iblkEnd; iblk++ )
  418. {
  419. PARMBLKIN & blkin = _stkblk[iblk];
  420. if ( blkin._zsName != zsName )
  421. continue; // Not the correct name
  422. if ( index >= 0 && blkin._indx != index )
  423. continue; // Not the correct index
  424. return iblk; // This is it
  425. }
  426. return -1;
  427. }
  428. // Return the name, index and type of the next block at this level or
  429. // false if there are no more items.
  430. const PARMBLKIN * PARMINSTREAM :: Pparmblk ( int iblk, int iblkOuter )
  431. {
  432. if ( ! BBlkOk( iblk ) )
  433. return NULL;
  434. int iblkEnd = _stkblk.size();
  435. if ( iblkOuter >= 0 )
  436. {
  437. // We have outer block scope, validate it
  438. if ( ! BBlkOk( iblkOuter ) )
  439. return NULL;
  440. if ( iblk <= iblkOuter )
  441. return NULL;
  442. iblkEnd = _stkblk[iblkOuter]._iblkEnd;
  443. }
  444. if ( iblk >= iblkEnd )
  445. return NULL;
  446. return & _stkblk[iblk];
  447. }
  448. void PARMINSTREAM :: Dump ()
  449. {
  450. int ilevel = 0;
  451. VINT viBlk; // The unclosed block stack
  452. for ( int i = 0 ; i < _stkblk.size(); i++ )
  453. {
  454. // close containing blocks
  455. int iblk = viBlk.size();
  456. while ( --iblk >= 0 )
  457. {
  458. if ( i < viBlk[iblk] )
  459. break; // We're still within this block
  460. }
  461. if ( iblk+1 != viBlk.size() )
  462. viBlk.resize(iblk+1);
  463. PARMBLKIN & blkin = _stkblk[i];
  464. cout << '\n';
  465. for ( int t = 0; t < viBlk.size(); t++ )
  466. {
  467. cout << '\t';
  468. }
  469. cout << "(" << i << ":" << (UINT) viBlk.size() << ",";
  470. if ( blkin._eBlk == PARMBLK::EPB_BLK )
  471. {
  472. cout << "block:" << blkin._iblkEnd << ") " ;
  473. viBlk.push_back(blkin._iblkEnd);
  474. }
  475. else
  476. if ( blkin._eBlk == PARMBLK::EPB_VAL )
  477. {
  478. cout << "value) ";
  479. }
  480. else
  481. {
  482. cout << "?????) ";
  483. }
  484. cout << blkin._zsName;
  485. if ( blkin._indx >= 0 )
  486. cout << '[' << blkin._indx << ']';
  487. cout << " (" << blkin._offsBeg << ',' << blkin._offsData << ',' << blkin._offsEnd << ')';
  488. }
  489. }
  490. bool PARMINSTREAM :: BSeekBlk ( int iblk )
  491. {
  492. if ( iblk < 0 || iblk >= _stkblk.size() )
  493. return false;
  494. clear();
  495. seekg( _stkblk[iblk]._offsData, ios::beg );
  496. return true;
  497. }
  498. // read the parameter into a string
  499. bool PARMINSTREAM :: BSeekBlkString ( int iblk, ZSTR & zsParam )
  500. {
  501. if ( ! BSeekBlk( iblk ) )
  502. return false;
  503. PARMBLKIN & blkin = _stkblk[iblk];
  504. streamsize cb = blkin._offsEnd - blkin._offsData;
  505. zsParam.resize(cb);
  506. read(zsParam.begin(),cb);
  507. return true;
  508. }
  509. PARMINSTREAM::Iterator::Iterator (
  510. PARMINSTREAM & fprm,
  511. SZC szcBlock,
  512. int index,
  513. int iblkOuter )
  514. : _fprm(fprm),
  515. _iblkOuter(iblkOuter),
  516. _iblk(0)
  517. {
  518. if ( szcBlock )
  519. {
  520. _iblk = _fprm.IblkFind( szcBlock, index, _iblkOuter );
  521. if ( ! _fprm.BBlkOk( _iblk ) )
  522. _iblk = fprm.Cblk();
  523. else
  524. ++_iblk;
  525. }
  526. }
  527. const PARMBLKIN * PARMINSTREAM :: Iterator :: PblkNext ()
  528. {
  529. if ( ! _fprm.BBlkOk( _iblk ) )
  530. return NULL;
  531. const PARMBLKIN * presult = _fprm.Pparmblk(_iblk, _iblkOuter);
  532. if ( presult )
  533. ++_iblk;
  534. return presult;
  535. }