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.

1325 lines
43 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // ShowResults.c
  8. //
  9. // Abstract:
  10. //
  11. // This modules has functions which are to shoow formatted Results on screen.
  12. //
  13. // Author:
  14. //
  15. // Sunil G.V.N. Murali ([email protected]) 24-Sep-2000
  16. //
  17. // Revision History:
  18. //
  19. // Sunil G.V.N. Murali ([email protected]) 01-Sep-2000 : Created It.
  20. //
  21. // *********************************************************************************
  22. #include "pch.h"
  23. #include "cmdline.h"
  24. #include "cmdlineres.h"
  25. /******************************************/
  26. /*** CONSTANTS / DEFINES / ENUMERATIONS ***/
  27. /******************************************/
  28. // VAL1 = Buffer length ; VAL2 = Number of characters to copy.
  29. #define MIN_VALUE( VAL1, VAL2 ) ( ( VAL1 > VAL2 ) ? VAL2 : VAL1 )
  30. // Indexes for buffers to store strings
  31. #define INDEX_TEMP_FORMAT_STRING 0
  32. #define INDEX_TEMP_DYNARRAY_STRING 1
  33. #define INDEX_TEMP_BUFFER 2
  34. #define INDEX_TEMP_BUFFER_LEN4096 3
  35. /********************************************************/
  36. /*** Private functions ... used only within this file ***/
  37. /********************************************************/
  38. __inline
  39. LPWSTR
  40. GetSRTempBuffer( IN DWORD dwIndexNumber,
  41. IN LPCWSTR pwszText,
  42. IN DWORD dwLength,
  43. IN BOOL bNullify )
  44. /*++
  45. Routine Description:
  46. Since every file will need the temporary buffers -- in order to see
  47. that their buffers wont be override with other functions, seperate
  48. buffer space are created for each file.
  49. This function will provide an access to internal buffers and also
  50. safe guards the file buffer boundaries.
  51. Arguments:
  52. [ IN ] dwIndexNumber - File specific index number.
  53. [ IN ] pwszText - Default text that needs to be copied into
  54. temporary buffer.
  55. [ IN ] dwLength - Length of the temporary buffer that is required.
  56. Ignored when 'pwszText' is specified.
  57. [ IN ] bNullify - Informs whether to clear the buffer or not
  58. before giving the temporary buffer.
  59. Set to 'TRUE' to clear buffer else FALSE.
  60. Return Value:
  61. NULL - When any failure occurs.
  62. NOTE: do not rely on GetLastError to know the reason
  63. for the failure.
  64. success - Return memory address of the requested size.
  65. NOTE:
  66. ----
  67. If 'pwszText' and 'dwLength' both are NULL, then we treat that the caller
  68. is asking for the reference of the buffer and we return the buffer address.
  69. In this call, there wont be any memory allocations -- if the requested index
  70. doesn't exist, failure is returned.
  71. Also, the buffer returned by this function need not released by the caller.
  72. While exiting from the tool, all the memory will be freed automatically by
  73. the 'ReleaseGlobals' function.
  74. Value contained by 'dwLength' parameter should be number of characters to
  75. store. EX: Buffer requested is "abcd\0" then 'dwLength' should be 5 instead
  76. of 10 ( 5 * sizeof( WCHAR ) ).
  77. To get the size of a buffer, get a buffer pointer and pass it as argument to
  78. 'GetBufferSize' function.
  79. --*/
  80. {
  81. if( TEMP_SHOWRESULTS_C_COUNT <= dwIndexNumber )
  82. {
  83. return NULL;
  84. }
  85. // Check if caller is requesting existing buffer contents
  86. if( ( NULL == pwszText ) &&
  87. ( 0 == dwLength ) &&
  88. ( FALSE == bNullify ) )
  89. {
  90. // yes -- we need to pass the existing buffer contents
  91. return GetInternalTemporaryBufferRef(
  92. dwIndexNumber + INDEX_TEMP_SHOWRESULTS_C );
  93. }
  94. // ...
  95. return GetInternalTemporaryBuffer(
  96. dwIndexNumber + INDEX_TEMP_SHOWRESULTS_C, pwszText, dwLength, bNullify );
  97. }
  98. VOID
  99. PrepareString(
  100. TARRAY arrValues,
  101. DWORD dwLength,
  102. LPCWSTR szFormat,
  103. LPCWSTR szSeperator
  104. )
  105. /*++
  106. Routine Description:
  107. Prepares the pszBuffer string by taking values from arrValues and
  108. formate these values as per szFormat string.
  109. Arguments:
  110. [ in ] arrValues : values to be formated.
  111. [ out ] pszBuffer : output string
  112. [ in ] dwLength : string length.
  113. [ in ] szFormat : format
  114. [ in ] szSeperator : Seperator string
  115. Return Value:
  116. NONE
  117. --*/
  118. {
  119. // local variables
  120. DWORD dw = 0;
  121. DWORD dwCount = 0;
  122. DWORD dwTemp = 0;
  123. LPWSTR pszTemp = NULL;
  124. LPWSTR pszValue = NULL;
  125. LPWSTR pszBuffer = NULL;
  126. // Get temporary memory.
  127. pszBuffer = GetSRTempBuffer( INDEX_TEMP_BUFFER_LEN4096, NULL, 0 , FALSE );
  128. //
  129. // kick off
  130. if( ( NULL == pszBuffer ) || ( NULL == szFormat ) )
  131. {
  132. return;
  133. }
  134. // init
  135. StringCopy( pszBuffer, NULL_STRING, ( GetBufferSize( pszBuffer )/ sizeof( WCHAR ) ) );
  136. dwCount = DynArrayGetCount( arrValues );
  137. // allocate memory for buffers
  138. pszTemp = GetSRTempBuffer( INDEX_TEMP_FORMAT_STRING, NULL, ( dwLength + 5 ) , TRUE );
  139. pszValue = GetSRTempBuffer( INDEX_TEMP_DYNARRAY_STRING, NULL, ( dwLength + 5 ), TRUE );
  140. if ( NULL == pszTemp || NULL == pszValue )
  141. {
  142. // release memories
  143. return;
  144. }
  145. dwTemp = ( DWORD ) StringLengthInBytes( szSeperator );
  146. //
  147. // traverse thru the list of the values and concatenate them
  148. // to the destination buffer
  149. for( dw = 0; dw < dwCount; dw++ )
  150. {
  151. // get the current value into the temporary string buffer
  152. DynArrayItemAsStringEx( arrValues, dw, pszValue, dwLength );
  153. // concatenate the temporary string to the original buffer
  154. StringCchPrintfW( pszTemp, (GetBufferSize(pszTemp)/sizeof(WCHAR)) - 1 ,
  155. szFormat, _X( pszValue ) );
  156. StringConcat( pszBuffer, pszTemp, ( GetBufferSize( pszBuffer )/ sizeof( WCHAR ) ) );
  157. // check whether this is the last value or not
  158. if ( dw + 1 < dwCount )
  159. {
  160. // there are some more values
  161. // check whether is space for adding the seperator or not
  162. if ( dwLength < dwTemp )
  163. {
  164. // no more space available ... break
  165. break;
  166. }
  167. else
  168. {
  169. // add the seperator and update the length accordingly
  170. StringConcat( pszBuffer, szSeperator, ( GetBufferSize( pszBuffer )/ sizeof( WCHAR ) ) );
  171. dwLength -= dwTemp;
  172. }
  173. }
  174. }
  175. return;
  176. }
  177. VOID
  178. GetValue(
  179. PTCOLUMNS pColumn,
  180. DWORD dwColumn,
  181. TARRAY arrRecord,
  182. LPCWSTR szArraySeperator
  183. )
  184. /*++
  185. Routine Description:
  186. Gets the value from arrRecord and copies it to pszValue using
  187. proper format.
  188. Arguments:
  189. [ in ] pColumn : format info.
  190. [ in ] dwColumn : no of columns
  191. [ in ] arrRecord : value to be formatted
  192. [ out ] pszValue : output string
  193. [ in ] szArraySeperator : seperator used.
  194. Return Value:
  195. NONE
  196. --*/
  197. {
  198. // local variables
  199. LPVOID pData = NULL; // data to be passed to formatter function
  200. TARRAY arrTemp = NULL;
  201. LPCWSTR pszTemp = NULL;
  202. const TCHAR cszString[] = _T( "%s" );
  203. const TCHAR cszDecimal[] = _T( "%d" );
  204. const TCHAR cszFloat[] = _T( "%f" );
  205. LPCWSTR pszFormat = NULL; // format
  206. LPWSTR pszValue = NULL;
  207. // variables used in formatting time
  208. DWORD dwReturn = 0;
  209. SYSTEMTIME systime;
  210. pszValue = GetSRTempBuffer( INDEX_TEMP_BUFFER_LEN4096, NULL, 0 , FALSE );
  211. if( ( NULL == pColumn ) ||
  212. ( NULL == pszValue ) )
  213. {
  214. return;
  215. }
  216. ZeroMemory( &systime, sizeof( SYSTEMTIME ) );
  217. // init first
  218. StringCopy( pszValue, NULL_STRING, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  219. // get the column value and do formatting appropriately
  220. switch( pColumn->dwFlags & SR_TYPE_MASK )
  221. {
  222. case SR_TYPE_STRING:
  223. {
  224. // identify the format to be used
  225. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  226. {
  227. pszFormat = pColumn->szFormat;
  228. }
  229. else
  230. {
  231. pszFormat = cszString; // default format
  232. }
  233. // copy the value to the temporary buffer based on the flags specified
  234. if ( pColumn->dwFlags & SR_ARRAY )
  235. {
  236. // get the value into buffer first - AVOIDING PREFIX BUGS
  237. arrTemp = DynArrayItem( arrRecord, dwColumn );
  238. if ( NULL == arrTemp )
  239. {
  240. return;
  241. }
  242. // form the array of values into one single string with ',' seperated
  243. PrepareString( arrTemp, pColumn->dwWidth,
  244. pszFormat, szArraySeperator );
  245. }
  246. else
  247. {
  248. // get the value into buffer first - AVOIDING PREFIX BUGS
  249. pszTemp = DynArrayItemAsString( arrRecord, dwColumn );
  250. if ( NULL == pszTemp )
  251. {
  252. return;
  253. }
  254. // now copy the value into buffer
  255. StringCchPrintfW( pszValue, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) - 1, pszFormat, pszTemp );
  256. }
  257. // switch case completed
  258. break;
  259. }
  260. case SR_TYPE_NUMERIC:
  261. {
  262. // identify the format to be used
  263. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  264. {
  265. pszFormat = pColumn->szFormat;
  266. }
  267. else
  268. {
  269. pszFormat = cszDecimal; // default format
  270. }
  271. // copy the value to the temporary buffer based on the flags specified
  272. if ( pColumn->dwFlags & SR_ARRAY )
  273. {
  274. // get the value into buffer first - AVOIDING PREFIX BUGS
  275. arrTemp = DynArrayItem( arrRecord, dwColumn );
  276. if ( NULL == arrTemp )
  277. {
  278. return;
  279. }
  280. // form the array of values into one single string with ',' seperated
  281. PrepareString( arrTemp, pColumn->dwWidth,
  282. pszFormat, szArraySeperator );
  283. }
  284. else
  285. {
  286. // get the value using format specified
  287. StringCchPrintfW( pszValue, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) - 1, pszFormat,
  288. DynArrayItemAsDWORD( arrRecord, dwColumn ) );
  289. }
  290. // switch case completed
  291. break;
  292. }
  293. case SR_TYPE_FLOAT:
  294. {
  295. // identify the format to be used
  296. // NOTE: for this type, format needs to be specified
  297. // if not, value displayed is unpredictable
  298. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  299. {
  300. pszFormat = pColumn->szFormat;
  301. }
  302. else
  303. {
  304. pszFormat = cszFloat; // default format
  305. }
  306. // copy the value to the temporary buffer based on the flags specified
  307. if ( pColumn->dwFlags & SR_ARRAY )
  308. {
  309. // get the value into buffer first - AVOIDING PREFIX BUGS
  310. arrTemp = DynArrayItem( arrRecord, dwColumn );
  311. if ( NULL == arrTemp )
  312. {
  313. return;
  314. }
  315. // form the array of values into one single string with ',' seperated
  316. PrepareString( arrTemp,
  317. pColumn->dwWidth, pszFormat, szArraySeperator );
  318. }
  319. else
  320. {
  321. // get the value using format specified
  322. StringCchPrintfW( pszValue, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) - 1, pszFormat,
  323. DynArrayItemAsFloat( arrRecord, dwColumn ) );
  324. }
  325. // switch case completed
  326. break;
  327. }
  328. case SR_TYPE_DOUBLE:
  329. {
  330. // identify the format to be used
  331. // NOTE: for this type, format needs to be specified
  332. // if not, value displayed is unpredictable
  333. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  334. {
  335. pszFormat = pColumn->szFormat;
  336. }
  337. else
  338. {
  339. pszFormat = cszFloat; // default format
  340. }
  341. // copy the value to the temporary buffer based on the flags specified
  342. if ( pColumn->dwFlags & SR_ARRAY )
  343. {
  344. // get the value into buffer first - AVOIDING PREFIX BUGS
  345. arrTemp = DynArrayItem( arrRecord, dwColumn );
  346. if ( NULL == arrTemp )
  347. {
  348. return;
  349. }
  350. // form the array of values into one single string with ',' seperated
  351. PrepareString( arrTemp, pColumn->dwWidth,
  352. pszFormat, szArraySeperator );
  353. }
  354. else
  355. {
  356. // get the value using format specified
  357. StringCchPrintfW( pszValue, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) - 1, pszFormat,
  358. DynArrayItemAsDouble( arrRecord, dwColumn ) );
  359. }
  360. // switch case completed
  361. break;
  362. }
  363. case SR_TYPE_TIME:
  364. {
  365. // get the time in the required format
  366. systime = DynArrayItemAsSystemTime( arrRecord, dwColumn );
  367. // get the time in current locale format
  368. dwReturn = GetTimeFormat( LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE,
  369. &systime, NULL, pszValue, MAX_STRING_LENGTH );
  370. // check the result
  371. if ( 0 == dwReturn )
  372. {
  373. // save the error info that has occurred
  374. SaveLastError();
  375. StringCopy( pszValue, GetReason(), ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  376. }
  377. // switch case completed
  378. break;
  379. }
  380. case SR_TYPE_CUSTOM:
  381. {
  382. // check whether function pointer is specified or not
  383. // if not specified, error
  384. if ( NULL == pColumn->pFunction )
  385. {
  386. return; // function ptr not specified ... error
  387. }
  388. // determine the data to be passed to the formatter function
  389. pData = pColumn->pFunctionData;
  390. if ( NULL == pData ) // function data is not defined
  391. {
  392. pData = pColumn; // the current column info itself as data
  393. }
  394. // call the custom function
  395. ( *pColumn->pFunction)( dwColumn, arrRecord, pData, pszValue );
  396. // switch case completed
  397. break;
  398. }
  399. case SR_TYPE_DATE:
  400. case SR_TYPE_DATETIME:
  401. default:
  402. {
  403. // this should not occur ... still
  404. StringCopy( pszValue, NULL_STRING, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  405. // switch case completed
  406. break;
  407. }
  408. }
  409. // user wants to display "N/A", when the value is empty, copy that
  410. if ( 0 == lstrlen( pszValue ) && pColumn->dwFlags & SR_SHOW_NA_WHEN_BLANK )
  411. {
  412. // copy N/A
  413. StringCopy( pszValue, V_NOT_AVAILABLE, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  414. }
  415. }
  416. VOID
  417. __DisplayTextWrapped(
  418. FILE* fp,
  419. LPWSTR pszValue,
  420. LPCWSTR pszSeperator,
  421. DWORD dwWidth
  422. )
  423. /*++
  424. Routine Description:
  425. Data is written to file depending upon the number of
  426. bytes ( width ) to be displayed.
  427. If number of bytes to be displayed is greater than
  428. max bytes ( width ) then text is wrapped to max bytes
  429. length.
  430. Arguments:
  431. [ in ] fp - File such as stdout, stderr
  432. etc. on to which data needs
  433. to be written.
  434. [ in ] pszValue - Contains data to be displayed.
  435. [ in ] pszSeperator - Contains data seperator.
  436. [ in ] dwWidth - Max bytes that can be displyed.
  437. Return Value:
  438. None.
  439. --*/
  440. {
  441. // local variables
  442. LPWSTR pszBuffer = NULL;
  443. LPCWSTR pszRestValue = NULL;
  444. DWORD dwTemp = 0;
  445. DWORD dwLength = 0;
  446. DWORD dwSepLength = 0;
  447. DWORD dwLenMemAlloc = 0;
  448. // check the input
  449. if ( NULL == pszValue || 0 == dwWidth || NULL == fp )
  450. {
  451. return;
  452. }
  453. // allocate buffer
  454. dwLenMemAlloc = StringLengthInBytes( pszValue );
  455. if ( dwLenMemAlloc < dwWidth )
  456. {
  457. dwLenMemAlloc = dwWidth;
  458. }
  459. // ...
  460. pszBuffer = GetSRTempBuffer( INDEX_TEMP_BUFFER, NULL, ( dwLenMemAlloc + 5 ), TRUE );
  461. if ( NULL == pszBuffer )
  462. {
  463. OUT_OF_MEMORY();
  464. SaveLastError();
  465. // null-ify the remaining text
  466. StringCopy( pszValue, NULL_STRING, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  467. return;
  468. }
  469. // determine the length of the seperator
  470. dwSepLength = 0;
  471. if ( NULL != pszSeperator )
  472. {
  473. dwSepLength = StringLengthInBytes( pszSeperator );
  474. }
  475. // determine the length of the data that can be displayed in this row
  476. dwTemp = 0;
  477. dwLength = 0;
  478. for( ;; )
  479. {
  480. pszRestValue = NULL;
  481. if ( NULL != pszSeperator )
  482. {
  483. pszRestValue = FindString( pszValue, pszSeperator, dwLength );
  484. }
  485. // check whether seperator is found or not
  486. if ( NULL != pszRestValue )
  487. {
  488. // determine the position
  489. dwTemp = StringLengthInBytes( pszValue ) -
  490. StringLengthInBytes( pszRestValue ) + dwSepLength;
  491. // check the length
  492. if ( dwTemp >= dwWidth )
  493. {
  494. // string position exceed the max. width
  495. if ( 0 == dwLength || dwTemp == dwWidth )
  496. {
  497. dwLength = dwWidth;
  498. }
  499. // break from the loop
  500. break;
  501. }
  502. // store the current position
  503. dwLength = dwTemp;
  504. }
  505. else
  506. {
  507. // check if length is determined or not .. if not required width itself is length
  508. if ( 0 == dwLength || ((StringLengthInBytes( pszValue ) - dwLength) > dwWidth) )
  509. {
  510. dwLength = dwWidth;
  511. }
  512. else
  513. {
  514. if ( StringLengthInBytes( pszValue ) <= (LONG) dwWidth )
  515. {
  516. dwLength = StringLengthInBytes( pszValue );
  517. }
  518. }
  519. // break the loop
  520. break;
  521. }
  522. }
  523. // get the partial value that has to be displayed
  524. StringCopy( pszBuffer, pszValue,
  525. MIN_VALUE( dwLenMemAlloc, ( dwLength + 1 ) ) ); // +1 for NULL character
  526. AdjustStringLength( pszBuffer, dwWidth, FALSE ); // adjust the string
  527. ShowMessage( fp, _X( pszBuffer ) ); // display the value
  528. // change the buffer contents so that it contains rest of the undisplayed text
  529. StringCopy( pszBuffer, pszValue, ( GetBufferSize( pszBuffer )/ sizeof( WCHAR ) ) );
  530. if ( StringLengthInBytes( pszValue ) > (LONG) dwLength )
  531. {
  532. StringCopy( pszValue, pszBuffer + dwLength, ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  533. }
  534. else
  535. {
  536. StringCopy( pszValue, _T( "" ), ( GetBufferSize( pszValue )/ sizeof( WCHAR ) ) );
  537. }
  538. }
  539. VOID
  540. __ShowAsTable(
  541. FILE* fp,
  542. DWORD dwColumns,
  543. PTCOLUMNS pColumns,
  544. DWORD dwFlags,
  545. TARRAY arrData
  546. )
  547. /*++
  548. Routine Description:
  549. Displays the arrData in Tabular form.
  550. Arguments:
  551. [ in ] fp : Output Device
  552. [ in ] dwColumns : no. of columns
  553. [ in ] pColumns : Header strings
  554. [ in ] dwFlags : flags
  555. [ in ] arrData : data to be shown
  556. Return Value:
  557. NONE
  558. --*/
  559. {
  560. // local variables
  561. DWORD dwCount = 0; // holds the count of the records
  562. DWORD i = 0; // looping variables
  563. DWORD j = 0; // looping variables
  564. DWORD k = 0; // looping variables
  565. DWORD dwColumn = 0;
  566. LONG lLastColumn = 0;
  567. DWORD dwMultiLineColumns = 0;
  568. BOOL bNeedSpace = FALSE;
  569. BOOL bPadLeft = FALSE;
  570. TARRAY arrRecord = NULL;
  571. TARRAY arrMultiLine = NULL;
  572. LPCWSTR pszData = NULL;
  573. LPCWSTR pszSeperator = NULL;
  574. LPWSTR szValue = NULL_STRING; // custom value formatter
  575. // constants
  576. const DWORD cdwColumn = 0;
  577. const DWORD cdwSeperator = 1;
  578. const DWORD cdwData = 2;
  579. if( ( NULL == fp ) || ( NULL == pColumns ) )
  580. {
  581. INVALID_PARAMETER();
  582. SaveLastError();
  583. return ;
  584. }
  585. // Allocate temporary memory.
  586. szValue = GetSRTempBuffer( INDEX_TEMP_BUFFER_LEN4096, NULL, 4096 , TRUE );
  587. // create an multi-line data display helper array
  588. arrMultiLine = CreateDynamicArray();
  589. if ( ( NULL == arrMultiLine ) || ( NULL == szValue ) )
  590. {
  591. OUT_OF_MEMORY();
  592. SaveLastError();
  593. return;
  594. }
  595. // check whether header has to be displayed or not
  596. if ( ! ( dwFlags & SR_NOHEADER ) )
  597. {
  598. //
  599. // header needs to be displayed
  600. // traverse thru the column headers and display
  601. bNeedSpace = FALSE;
  602. for ( i = 0; i < dwColumns; i++ )
  603. {
  604. // check whether user wants to display this column or not
  605. if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN )
  606. {
  607. continue; // user doesn't want this column to be displayed .. skip
  608. }
  609. // determine the padding direction
  610. bPadLeft = FALSE;
  611. if ( pColumns[ i ].dwFlags & SR_ALIGN_LEFT )
  612. {
  613. bPadLeft = TRUE;
  614. }
  615. else
  616. {
  617. switch( pColumns[ i ].dwFlags & SR_TYPE_MASK )
  618. {
  619. case SR_TYPE_NUMERIC:
  620. case SR_TYPE_FLOAT:
  621. case SR_TYPE_DOUBLE:
  622. bPadLeft = TRUE;
  623. break;
  624. }
  625. }
  626. // check if column header seperator is needed or not and based on that show
  627. if ( TRUE == bNeedSpace )
  628. {
  629. // show space as column header seperator
  630. ShowMessage( fp, _T( " " ) );
  631. }
  632. // print the column heading
  633. // NOTE: column will be displayed either by expanding or shrinking
  634. // based on the length of the column heading as well as width of the column
  635. StringCopy( szValue, pColumns[ i ].szColumn, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) );
  636. AdjustStringLength( szValue, pColumns[ i ].dwWidth, bPadLeft );
  637. ShowMessage( fp, szValue ); // column heading
  638. // inform that from next time onward display column header separator
  639. bNeedSpace = TRUE;
  640. }
  641. // display the new line character ... seperation b/w headings and separator line
  642. ShowMessage( fp, _T( "\n" ) );
  643. // display the seperator chars under each column header
  644. bNeedSpace = FALSE;
  645. for ( i = 0; i < dwColumns; i++ )
  646. {
  647. // check whether user wants to display this column or not
  648. if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN )
  649. {
  650. continue; // user doesn't want this column to be displayed .. skip
  651. }
  652. // check if column header seperator is needed or not and based on that show
  653. if ( TRUE == bNeedSpace )
  654. {
  655. // show space as column header seperator
  656. ShowMessage( fp, _T( " " ) );
  657. }
  658. // display seperator based on the required column width
  659. Replicate( szValue, _T( "=" ), pColumns[ i ].dwWidth, pColumns[ i ].dwWidth + 1 );
  660. ShowMessage( fp, szValue );
  661. // inform that from next time onward display column header separator
  662. bNeedSpace = TRUE;
  663. }
  664. // display the new line character ... seperation b/w headings and actual data
  665. ShowMessage( fp, _T( "\n" ) );
  666. }
  667. //
  668. // start displaying
  669. // get the total no. of records available
  670. dwCount = DynArrayGetCount( arrData );
  671. // traverse thru the records one-by-one
  672. for( i = 0; i < dwCount; i++ )
  673. {
  674. // clear the existing value
  675. StringCopy( szValue, NULL_STRING, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) );
  676. // get the pointer to the current record
  677. arrRecord = DynArrayItem( arrData, i );
  678. if ( NULL == arrRecord )
  679. {
  680. continue;
  681. }
  682. // traverse thru the columns and display the values
  683. bNeedSpace = FALSE;
  684. for ( j = 0; j < dwColumns; j++ )
  685. {
  686. // sub-local variables used in this loop
  687. DWORD dwTempWidth = 0;
  688. BOOL bTruncation = FALSE;
  689. // check whether user wants to display this column or not
  690. if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN )
  691. {
  692. continue; // user doesn't want this column to be displayed .. skip
  693. }
  694. // get the value of the column
  695. // NOTE: CHECK IF USER ASKED NOT TO TRUNCATE THE DATA OR NOT
  696. if ( pColumns[ j ].dwFlags & SR_NO_TRUNCATION )
  697. {
  698. bTruncation = TRUE;
  699. dwTempWidth = pColumns[ j ].dwWidth;
  700. pColumns[ j ].dwWidth = ( GetBufferSize( szValue )/ sizeof( WCHAR ) );
  701. }
  702. // prepare the value
  703. GetValue( &pColumns[ j ], j, arrRecord, _T( ", " ) );
  704. // determine the padding direction
  705. bPadLeft = FALSE;
  706. if ( FALSE == bTruncation )
  707. {
  708. if ( pColumns[ j ].dwFlags & SR_ALIGN_LEFT )
  709. {
  710. bPadLeft = TRUE;
  711. }
  712. else
  713. {
  714. switch( pColumns[ j ].dwFlags & SR_TYPE_MASK )
  715. {
  716. case SR_TYPE_NUMERIC:
  717. case SR_TYPE_FLOAT:
  718. case SR_TYPE_DOUBLE:
  719. bPadLeft = TRUE;
  720. break;
  721. }
  722. }
  723. // adjust ...
  724. AdjustStringLength( szValue, pColumns[ j ].dwWidth, bPadLeft );
  725. }
  726. // reset the width of the current column if it is modified
  727. if ( TRUE == bTruncation )
  728. {
  729. pColumns[ j ].dwWidth = dwTempWidth;
  730. }
  731. // check if column header seperator is needed or not and based on that show
  732. if ( TRUE == bNeedSpace )
  733. {
  734. // show space as column header seperator
  735. ShowMessage( fp, _T( " " ) );
  736. }
  737. // now display the value
  738. if ( pColumns[ j ].dwFlags & SR_WORDWRAP )
  739. {
  740. // display the text ( might be partial )
  741. __DisplayTextWrapped( fp, szValue, _T( ", " ), pColumns[ j ].dwWidth );
  742. // check if any info is left to be displayed
  743. if ( 0 != StringLengthInBytes( szValue ) )
  744. {
  745. LONG lIndex = 0;
  746. lIndex = DynArrayAppendRow( arrMultiLine, 3 );
  747. if ( -1 != lIndex )
  748. {
  749. DynArraySetDWORD2( arrMultiLine, lIndex, cdwColumn, j );
  750. DynArraySetString2( arrMultiLine, lIndex, cdwData, szValue, 0 );
  751. DynArraySetString2( arrMultiLine, lIndex,
  752. cdwSeperator, _T( ", " ), 0 );
  753. }
  754. }
  755. }
  756. else
  757. {
  758. ShowMessage( fp, _X( szValue ) );
  759. }
  760. // inform that from next time onward display column header separator
  761. bNeedSpace = TRUE;
  762. }
  763. // display the new line character ... seperation b/w two record
  764. ShowMessage( fp, _T( "\n" ) );
  765. // now display the multi-line column values
  766. dwMultiLineColumns = DynArrayGetCount( arrMultiLine );
  767. while( 0 != dwMultiLineColumns )
  768. {
  769. // reset
  770. dwColumn = 0;
  771. lLastColumn = -1;
  772. bNeedSpace = FALSE;
  773. // ...
  774. for( j = 0; j < dwMultiLineColumns; j++ )
  775. {
  776. // ge the column number
  777. dwColumn = DynArrayItemAsDWORD2( arrMultiLine, j, cdwColumn );
  778. // show spaces till the current column from the last column
  779. for( k = lLastColumn + 1; k < dwColumn; k++ )
  780. {
  781. // check whether user wants to display this column or not
  782. if ( pColumns[ k ].dwFlags & SR_HIDECOLUMN )
  783. {
  784. continue; // user doesn't want this column to be displayed .. skip
  785. }
  786. // check if column header seperator is needed or not and based on that show
  787. if ( TRUE == bNeedSpace )
  788. {
  789. // show space as column header seperator
  790. ShowMessage( fp, _T( " " ) );
  791. }
  792. // display seperator based on the required column width
  793. Replicate( szValue, _T( " " ), pColumns[ k ].dwWidth,
  794. pColumns[ k ].dwWidth + 1 );
  795. ShowMessage( fp, szValue );
  796. // inform that from next time onward display column header separator
  797. bNeedSpace = TRUE;
  798. }
  799. // update the last column
  800. lLastColumn = dwColumn;
  801. // check if column header seperator is needed or not and based on that show
  802. if ( TRUE == bNeedSpace )
  803. {
  804. // show space as column header seperator
  805. ShowMessage( fp, _T( " " ) );
  806. }
  807. // get the seperator and data
  808. pszData = DynArrayItemAsString2( arrMultiLine, j, cdwData );
  809. pszSeperator = DynArrayItemAsString2( arrMultiLine, j, cdwSeperator );
  810. if ( NULL == pszData || NULL == pszSeperator )
  811. {
  812. continue;
  813. }
  814. // display the information
  815. StringCopy( szValue, pszData, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) );
  816. __DisplayTextWrapped( fp, szValue, pszSeperator,
  817. pColumns[ dwColumn ].dwWidth );
  818. // update the multi-line array with rest of the line
  819. if ( 0 == StringLengthInBytes( szValue ) )
  820. {
  821. // data in this column is completely displayed ... remove it
  822. DynArrayRemove( arrMultiLine, j );
  823. // update the indexes
  824. j--;
  825. dwMultiLineColumns--;
  826. }
  827. else
  828. {
  829. // update the multi-line array with the remaining value
  830. DynArraySetString2( arrMultiLine, j, cdwData, szValue, 0 );
  831. }
  832. }
  833. // display the new line character ... seperation b/w two lines
  834. ShowMessage( fp, _T( "\n" ) );
  835. }
  836. }
  837. // destroy the array
  838. DestroyDynamicArray( &arrMultiLine );
  839. }
  840. VOID
  841. __ShowAsList(
  842. FILE* fp,
  843. DWORD dwColumns,
  844. PTCOLUMNS pColumns,
  845. DWORD dwFlags,
  846. TARRAY arrData
  847. )
  848. /*++
  849. Routine Description:
  850. Displays the in List format
  851. Arguments:
  852. [ in ] fp : Output Device
  853. [ in ] dwColumns : no. of columns
  854. [ in ] pColumns : Header strings
  855. [ in ] dwFlags : flags
  856. [ in ] arrData : data to be shown
  857. Return Value:
  858. NONE
  859. --*/
  860. {
  861. // local variables
  862. DWORD dwCount = 0; // holds the count of all records
  863. DWORD i = 0, j = 0; // looping variables
  864. DWORD dwTempWidth = 0;
  865. DWORD dwMaxColumnLen = 0; // holds the length of the which max. among all the columns
  866. LPWSTR pszTemp = NULL;
  867. TARRAY arrRecord = NULL;
  868. __STRING_64 szBuffer = NULL_STRING;
  869. LPWSTR szValue = NULL_STRING; // custom value formatter
  870. UNREFERENCED_PARAMETER( dwFlags );
  871. if( ( NULL == fp ) || ( NULL == pColumns ) )
  872. {
  873. INVALID_PARAMETER();
  874. SaveLastError();
  875. return ;
  876. }
  877. // Allocate temporary memory.
  878. szValue = GetSRTempBuffer( INDEX_TEMP_BUFFER_LEN4096, NULL, 4096 , TRUE );
  879. if( NULL == szValue )
  880. {
  881. OUT_OF_MEMORY();
  882. SaveLastError();
  883. return;
  884. }
  885. // find out the max. length among all the column headers
  886. dwMaxColumnLen = 0;
  887. for ( i = 0; i < dwColumns; i++ )
  888. {
  889. dwTempWidth = ( DWORD ) StringLengthInBytes( pColumns[ i ].szColumn );
  890. if ( dwMaxColumnLen < dwTempWidth )
  891. {
  892. dwMaxColumnLen = dwTempWidth;
  893. }
  894. }
  895. // start displaying the data
  896. // get the total no. of records available
  897. dwCount = DynArrayGetCount( arrData );
  898. // get the total no. of records available
  899. for( i = 0; i < dwCount; i++ )
  900. {
  901. // get the pointer to the current record
  902. arrRecord = DynArrayItem( arrData, i );
  903. if ( NULL == arrRecord )
  904. {
  905. continue;
  906. }
  907. // traverse thru the columns and display the values
  908. for ( j = 0; j < dwColumns; j++)
  909. {
  910. // clear the existing value
  911. StringCopy( szValue, NULL_STRING, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) );
  912. // check whether user wants to display this column or not
  913. if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN )
  914. {
  915. continue; // user doesn't want this column to be displayed .. skip
  916. }
  917. // display the column heading and its value
  918. // ( heading will be displayed based on the max. column length )
  919. StringCchPrintfW( szValue, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) - 1,
  920. _T( "%s:" ), pColumns[ j ].szColumn);
  921. AdjustStringLength( szValue, dwMaxColumnLen + 2, FALSE );
  922. ShowMessage( fp, szValue );
  923. // get the value of the column
  924. dwTempWidth = pColumns[ j ].dwWidth; // save the current width
  925. pColumns[ j ].dwWidth = ( GetBufferSize( szValue )/ sizeof( WCHAR ) ); // change the width
  926. GetValue( &pColumns[ j ], j, arrRecord, _T( "\n" ) );
  927. pColumns[ j ].dwWidth = dwTempWidth; // restore the original width
  928. // display the [ list of ] values
  929. pszTemp = _tcstok( szValue, _T( "\n" ) );
  930. while ( NULL != pszTemp )
  931. {
  932. // display the value
  933. ShowMessage( fp, _X( pszTemp ) );
  934. pszTemp = _tcstok( NULL, _T( "\n" ) );
  935. if ( NULL != pszTemp )
  936. {
  937. // prepare the next line
  938. StringCopy( szBuffer, _T( " " ), ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) );
  939. AdjustStringLength( szBuffer, dwMaxColumnLen + 2, FALSE );
  940. ShowMessage( fp, _T( "\n" ) );
  941. ShowMessage( fp, _X( szBuffer ) );
  942. }
  943. }
  944. // display the next line character seperation b/w two fields
  945. ShowMessage( fp, _T( "\n" ) );
  946. }
  947. // display the new line character ... seperation b/w two records
  948. // NOTE: do this only if there are some more records
  949. if ( i + 1 < dwCount )
  950. {
  951. ShowMessage( fp, _T( "\n" ) );
  952. }
  953. }
  954. }
  955. VOID
  956. __ShowAsCSV(
  957. FILE* fp,
  958. DWORD dwColumns,
  959. PTCOLUMNS pColumns,
  960. DWORD dwFlags,
  961. TARRAY arrData
  962. )
  963. /*++
  964. Routine Description:
  965. Displays the arrData in CSV form.
  966. Arguments:
  967. [ in ] fp : Output Device
  968. [ in ] dwColumns : no. of columns
  969. [ in ] pColumns : Header strings
  970. [ in ] dwFlags : flags
  971. [ in ] arrData : data to be shown
  972. Return Value:
  973. NONE
  974. --*/
  975. {
  976. // local variables
  977. DWORD dwCount = 0; // holds the count of all records
  978. DWORD i = 0; // looping variables
  979. DWORD j = 0; // looping variables
  980. DWORD dwTempWidth = 0;
  981. BOOL bNeedComma = FALSE;
  982. TARRAY arrRecord = NULL;
  983. LPWSTR szValue = NULL_STRING;
  984. if( ( NULL == fp ) || ( NULL == pColumns ) )
  985. {
  986. INVALID_PARAMETER();
  987. SaveLastError();
  988. return ;
  989. }
  990. // Allocate temporary memory.
  991. szValue = GetSRTempBuffer( INDEX_TEMP_BUFFER_LEN4096, NULL, 4096 , TRUE );
  992. if( NULL == szValue )
  993. {
  994. OUT_OF_MEMORY();
  995. SaveLastError();
  996. return;
  997. }
  998. // check whether header has to be displayed or not
  999. if ( ! ( dwFlags & SR_NOHEADER ) )
  1000. {
  1001. //
  1002. // header needs to be displayed
  1003. // first display the columns ... with comma seperated
  1004. bNeedComma = FALSE;
  1005. for ( i = 0; i < dwColumns; i++ )
  1006. {
  1007. // check whether user wants to display this column or not
  1008. if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN )
  1009. continue; // user doesn't want this column to be displayed .. skip
  1010. // check whether we need to display ',' or not and then display
  1011. if ( TRUE == bNeedComma )
  1012. {
  1013. // ',' has to be displayed
  1014. ShowMessage( fp, _T( "," ) );
  1015. }
  1016. // display the column heading
  1017. StringCchPrintfW( szValue, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) - 1,
  1018. _T( "\"%s\"" ), pColumns[ i ].szColumn );
  1019. DISPLAY_MESSAGE ( fp, szValue );
  1020. // inform that from next time onwards we need to display comma before data
  1021. bNeedComma = TRUE;
  1022. }
  1023. // new line character
  1024. ShowMessage( fp, _T( "\n" ) );
  1025. }
  1026. //
  1027. // start displaying the data
  1028. // get the total no. of records available
  1029. dwCount = DynArrayGetCount( arrData );
  1030. // get the total no. of records available
  1031. for( i = 0; i < dwCount; i++ )
  1032. {
  1033. // get the pointer to the current record
  1034. arrRecord = DynArrayItem( arrData, i );
  1035. if ( NULL == arrRecord )
  1036. continue;
  1037. // traverse thru the columns and display the values
  1038. bNeedComma = FALSE;
  1039. for ( j = 0; j < dwColumns; j++ )
  1040. {
  1041. // clear the existing value
  1042. StringCopy( szValue, NULL_STRING, ( GetBufferSize( szValue )/ sizeof( WCHAR ) ) );
  1043. // check whether user wants to display this column or not
  1044. if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN )
  1045. continue; // user doesn't want this column to be displayed .. skip
  1046. // get the value of the column
  1047. dwTempWidth = pColumns[ j ].dwWidth; // save the current width
  1048. pColumns[ j ].dwWidth = ( GetBufferSize( szValue )/ sizeof( WCHAR ) ); // change the width
  1049. GetValue( &pColumns[ j ], j, arrRecord, _T( "," ) );
  1050. pColumns[ j ].dwWidth = dwTempWidth; // restore the original width
  1051. // check whether we need to display ',' or not and then display
  1052. if ( TRUE == bNeedComma )
  1053. {
  1054. // ',' has to be displayed
  1055. ShowMessage( fp, _T( "," ) );
  1056. }
  1057. // print the value
  1058. ShowMessage( fp, _T( "\"" ) );
  1059. ShowMessage( fp, _X( szValue ) );
  1060. ShowMessage( fp, _T( "\"" ) );
  1061. // inform that from next time onwards we need to display comma before data
  1062. bNeedComma = TRUE;
  1063. }
  1064. // new line character
  1065. ShowMessage( fp, _T( "\n" ) );
  1066. }
  1067. }
  1068. //
  1069. // public functions ... exposed to external world
  1070. //
  1071. VOID
  1072. ShowResults(
  1073. DWORD dwColumns,
  1074. PTCOLUMNS pColumns,
  1075. DWORD dwFlags,
  1076. TARRAY arrData
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. Wrapper function to ShowResults2.
  1081. Arguments:
  1082. [ in ] dwColumns : No. of Columns to be shown
  1083. [ in ] pColumns : Columns header
  1084. [ in ] dwFlags : Required format
  1085. [ in ] arrData : Data to be displayed.
  1086. Return Value:
  1087. None.
  1088. --*/
  1089. {
  1090. // just call the main function ... with stdout
  1091. ShowResults2( stdout, dwColumns, pColumns, dwFlags, arrData );
  1092. }
  1093. VOID
  1094. ShowResults2(
  1095. FILE* fp,
  1096. DWORD dwColumns,
  1097. PTCOLUMNS pColumns,
  1098. DWORD dwFlags,
  1099. TARRAY arrData
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. Show the resuls (arrData) on the screen.
  1104. Arguments:
  1105. [ in ] fp : File on to which data is to be displayed.
  1106. [ in ] dwColumns : No. of Columns to be shown
  1107. [ in ] pColumns : Columns header
  1108. [ in ] dwFlags : Required format
  1109. [ in ] arrData : Data to be displayed.
  1110. Return Value:
  1111. NONE
  1112. --*/
  1113. {
  1114. // local variables
  1115. if( ( NULL == fp ) || ( NULL == pColumns ) )
  1116. {
  1117. return ;
  1118. }
  1119. //
  1120. // Display the information in the format specified
  1121. //
  1122. switch( dwFlags & SR_FORMAT_MASK )
  1123. {
  1124. case SR_FORMAT_TABLE:
  1125. {
  1126. // show the data in table format
  1127. __ShowAsTable( fp, dwColumns, pColumns, dwFlags, arrData );
  1128. // switch case completed
  1129. break;
  1130. }
  1131. case SR_FORMAT_LIST:
  1132. {
  1133. // show the data in table format
  1134. __ShowAsList( fp, dwColumns, pColumns, dwFlags, arrData );
  1135. // switch case completed
  1136. break;
  1137. }
  1138. case SR_FORMAT_CSV:
  1139. {
  1140. // show the data in table format
  1141. __ShowAsCSV( fp, dwColumns, pColumns, dwFlags, arrData );
  1142. // switch case completed
  1143. break;
  1144. }
  1145. default:
  1146. {
  1147. // invalid format requested by the user
  1148. break;
  1149. }
  1150. }
  1151. // flush the memory onto the file buffer
  1152. fflush( fp );
  1153. }