Source code of Windows XP (NT5)
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.

1033 lines
28 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. //
  29. // private functions ... used only within this file
  30. //
  31. // ***************************************************************************
  32. // Routine Description:
  33. // Prepares the pszBuffer string by taking values from arrValues and
  34. // formate these values as per szFormat string.
  35. //
  36. // Arguments:
  37. // [ in ] arrValues : values to be formated.
  38. // [ out ] pszBuffer : output string
  39. // [ in ] dwLength : string length.
  40. // [ in ] szFormat : format
  41. // [ in ] szSeperator : Seperator string
  42. //
  43. // Return Value:
  44. // NONE
  45. //
  46. // ***************************************************************************
  47. VOID __PrepareString( TARRAY arrValues,
  48. LPTSTR pszBuffer, DWORD dwLength,
  49. LPCTSTR szFormat, LPCTSTR szSeperator )
  50. {
  51. // local variables
  52. DWORD dw = 0;
  53. DWORD dwCount = 0;
  54. LPTSTR pszTemp = NULL;
  55. LPTSTR pszValue = NULL;
  56. //
  57. // kick off
  58. // init
  59. lstrcpy( pszBuffer, NULL_STRING );
  60. dwCount = DynArrayGetCount( arrValues );
  61. // allocate memory for buffers
  62. pszTemp = __calloc( dwLength + 5, sizeof( TCHAR ) );
  63. pszValue = __calloc( dwLength + 5, sizeof( TCHAR ) );
  64. if ( pszTemp == NULL || pszValue == NULL )
  65. {
  66. // release memories
  67. __free( pszTemp );
  68. __free( pszValue );
  69. return;
  70. }
  71. //
  72. // traverse thru the list of the values and concatenate them
  73. // to the destination buffer
  74. for( dw = 0; dw < dwCount; dw++ )
  75. {
  76. // get the current value into the temporary string buffer
  77. DynArrayItemAsStringEx( arrValues, dw, pszValue, dwLength );
  78. // concatenate the temporary string to the original buffer
  79. FORMAT_STRING( pszTemp, szFormat, _X( pszValue ) );
  80. lstrcat( pszBuffer, pszTemp );
  81. dwLength -= StringLengthInBytes( pszTemp );
  82. // check whether this is the last value or not
  83. if ( dw + 1 < dwCount )
  84. {
  85. // there are some more values
  86. // check whether is space for adding the seperator or not
  87. if ( dwLength < (DWORD) StringLengthInBytes( szSeperator ) )
  88. {
  89. // no more space available ... break
  90. break;
  91. }
  92. else
  93. {
  94. // add the seperator and update the length accordingly
  95. lstrcat( pszBuffer, szSeperator );
  96. dwLength -= StringLengthInBytes( szSeperator );
  97. }
  98. }
  99. }
  100. // release memories
  101. __free( pszTemp );
  102. __free( pszValue );
  103. }
  104. // ***************************************************************************
  105. // Routine Description:
  106. // Gets the value from arrRecord and copies it to pszValue using
  107. // proper format.
  108. //
  109. // Arguments:
  110. // [ in ] pColumn : format info.
  111. // [ in ] dwColumn : no of columns
  112. // [ in ] arrRecord : value to be formatted
  113. // [ out ] pszValue : output string
  114. // [ in ] szArraySeperator : seperator used.
  115. //
  116. // Return Value:
  117. // NONE
  118. //
  119. // ***************************************************************************
  120. VOID __GetValue( PTCOLUMNS pColumn,
  121. DWORD dwColumn, TARRAY arrRecord,
  122. LPTSTR pszValue, LPCTSTR szArraySeperator )
  123. {
  124. // local variables
  125. LPVOID pData = NULL; // data to be passed to formatter function
  126. TARRAY arrTemp = NULL;
  127. LPCTSTR pszTemp = NULL;
  128. __STRING_64 szFormat = NULL_STRING; // format
  129. // variables used in formatting time
  130. DWORD dwReturn = 0;
  131. SYSTEMTIME systime = { 0 };
  132. // init first
  133. lstrcpy( pszValue, NULL_STRING );
  134. // get the column value and do formatting appropriately
  135. switch( pColumn->dwFlags & SR_TYPE_MASK )
  136. {
  137. case SR_TYPE_STRING:
  138. {
  139. // identify the format to be used
  140. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  141. lstrcpy( szFormat, pColumn->szFormat );
  142. else
  143. lstrcpy( szFormat, _T( "%s" ) ); // default format
  144. // copy the value to the temporary buffer based on the flags specified
  145. if ( pColumn->dwFlags & SR_ARRAY )
  146. {
  147. // get the value into buffer first - AVOIDING PREFIX BUGS
  148. arrTemp = DynArrayItem( arrRecord, dwColumn );
  149. if ( arrTemp == NULL )
  150. return;
  151. // form the array of values into one single string with ',' seperated
  152. __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, szArraySeperator );
  153. }
  154. else
  155. {
  156. // get the value into buffer first - AVOIDING PREFIX BUGS
  157. pszTemp = DynArrayItemAsString( arrRecord, dwColumn );
  158. if ( pszTemp == NULL )
  159. return;
  160. // now copy the value into buffer
  161. FORMAT_STRING( pszValue, szFormat, _X( pszTemp ) );
  162. }
  163. // switch case completed
  164. break;
  165. }
  166. case SR_TYPE_NUMERIC:
  167. {
  168. // identify the format to be used
  169. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  170. lstrcpy( szFormat, pColumn->szFormat );
  171. else
  172. lstrcpy( szFormat, _T( "%d" ) ); // default format
  173. // copy the value to the temporary buffer based on the flags specified
  174. if ( pColumn->dwFlags & SR_ARRAY )
  175. {
  176. // get the value into buffer first - AVOIDING PREFIX BUGS
  177. arrTemp = DynArrayItem( arrRecord, dwColumn );
  178. if ( arrTemp == NULL )
  179. return;
  180. // form the array of values into one single string with ',' seperated
  181. __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, _T( ", " ) );
  182. }
  183. else
  184. {
  185. // get the value using format specified
  186. FORMAT_STRING( pszValue, szFormat, DynArrayItemAsDWORD( arrRecord, dwColumn ) );
  187. }
  188. // switch case completed
  189. break;
  190. }
  191. case SR_TYPE_FLOAT:
  192. {
  193. // identify the format to be used
  194. // NOTE: for this type, format needs to be specified
  195. // if not, value displayed is unpredictable
  196. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  197. lstrcpy( szFormat, pColumn->szFormat );
  198. else
  199. lstrcpy( szFormat, _T( "%f" ) ); // default format
  200. // copy the value to the temporary buffer based on the flags specified
  201. if ( pColumn->dwFlags & SR_ARRAY )
  202. {
  203. // get the value into buffer first - AVOIDING PREFIX BUGS
  204. arrTemp = DynArrayItem( arrRecord, dwColumn );
  205. if ( arrTemp == NULL )
  206. return;
  207. // form the array of values into one single string with ',' seperated
  208. __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, szArraySeperator );
  209. }
  210. else
  211. {
  212. // get the value using format specified
  213. FORMAT_STRING( pszValue, szFormat, DynArrayItemAsFloat( arrRecord, dwColumn ) );
  214. }
  215. // switch case completed
  216. break;
  217. }
  218. case SR_TYPE_DOUBLE:
  219. {
  220. // identify the format to be used
  221. // NOTE: for this type, format needs to be specified
  222. // if not, value displayed is unpredictable
  223. if ( pColumn->dwFlags & SR_VALUEFORMAT )
  224. lstrcpy( szFormat, pColumn->szFormat );
  225. else
  226. lstrcpy( szFormat, _T( "%f" ) ); // default format
  227. // copy the value to the temporary buffer based on the flags specified
  228. if ( pColumn->dwFlags & SR_ARRAY )
  229. {
  230. // get the value into buffer first - AVOIDING PREFIX BUGS
  231. arrTemp = DynArrayItem( arrRecord, dwColumn );
  232. if ( arrTemp == NULL )
  233. return;
  234. // form the array of values into one single string with ',' seperated
  235. __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, szArraySeperator );
  236. }
  237. else
  238. {
  239. // get the value using format specified
  240. FORMAT_STRING( pszValue, szFormat, DynArrayItemAsDouble( arrRecord, dwColumn ) );
  241. }
  242. // switch case completed
  243. break;
  244. }
  245. case SR_TYPE_TIME:
  246. {
  247. // get the time in the required format
  248. systime = DynArrayItemAsSystemTime( arrRecord, dwColumn );
  249. // get the time in current locale format
  250. dwReturn = GetTimeFormat( LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE,
  251. &systime, NULL, pszValue, MAX_STRING_LENGTH );
  252. // check the result
  253. if ( dwReturn == 0 )
  254. {
  255. // save the error info that has occurred
  256. SaveLastError();
  257. lstrcpy( pszValue, GetReason() );
  258. }
  259. // switch case completed
  260. break;
  261. }
  262. case SR_TYPE_CUSTOM:
  263. {
  264. // check whether function pointer is specified or not
  265. // if not specified, error
  266. if ( pColumn->pFunction == NULL )
  267. return; // function ptr not specified ... error
  268. // determine the data to be passed to the formatter function
  269. pData = pColumn->pFunctionData;
  270. if ( pData == NULL ) // function data is not defined
  271. pData = pColumn; // the current column info itself as data
  272. // call the custom function
  273. ( *pColumn->pFunction)( dwColumn, arrRecord, pData, pszValue );
  274. // switch case completed
  275. break;
  276. }
  277. case SR_TYPE_DATE:
  278. case SR_TYPE_DATETIME:
  279. default:
  280. {
  281. // this should not occur ... still
  282. lstrcpy( pszValue, NULL_STRING );
  283. // switch case completed
  284. break;
  285. }
  286. }
  287. // user wants to display "N/A", when the value is empty, copy that
  288. if ( lstrlen( pszValue ) == 0 && pColumn->dwFlags & SR_SHOW_NA_WHEN_BLANK )
  289. {
  290. // copy N/A
  291. lstrcpy( pszValue, V_NOT_AVAILABLE );
  292. }
  293. }
  294. // ***************************************************************************
  295. // Routine Description:
  296. //
  297. // Arguments:
  298. //
  299. // Return Value:
  300. //
  301. // ***************************************************************************
  302. VOID __DisplayTextWrapped( FILE* fp, LPTSTR pszValue, LPCTSTR pszSeperator, DWORD dwWidth )
  303. {
  304. // local variables
  305. LPTSTR pszBuffer = NULL;
  306. LPCTSTR pszRestValue = NULL;
  307. DWORD dwTemp = 0, dwLength = 0, dwSepLength = 0;
  308. // check the input
  309. if ( pszValue == NULL || dwWidth == 0 || fp == NULL )
  310. return;
  311. // allocate buffer
  312. dwLength = StringLengthInBytes( pszValue );
  313. if ( dwLength < dwWidth )
  314. dwLength = dwWidth;
  315. // ...
  316. pszBuffer = __calloc( dwLength + 5, sizeof( TCHAR ) );
  317. if ( pszBuffer == NULL )
  318. {
  319. SetLastError( E_OUTOFMEMORY );
  320. SaveLastError();
  321. lstrcpy( pszValue, NULL_STRING ); // null-ify the remaining text
  322. return;
  323. }
  324. // determine the length of the seperator
  325. dwSepLength = 0;
  326. if ( pszSeperator != NULL )
  327. dwSepLength = StringLengthInBytes( pszSeperator );
  328. // determine the length of the data that can be displayed in this row
  329. dwTemp = 0;
  330. dwLength = 0;
  331. while ( 1 )
  332. {
  333. pszRestValue = NULL;
  334. if ( pszSeperator != NULL )
  335. pszRestValue = FindString( pszValue, pszSeperator, dwLength );
  336. // check whether seperator is found or not
  337. if ( pszRestValue != NULL )
  338. {
  339. // determine the position
  340. dwTemp = StringLengthInBytes( pszValue ) - StringLengthInBytes( pszRestValue ) + dwSepLength;
  341. // check the length
  342. if ( dwTemp >= dwWidth )
  343. {
  344. // string position exceed the max. width
  345. if ( dwLength == 0 || dwTemp == dwWidth )
  346. dwLength = dwWidth;
  347. // break from the loop
  348. break;
  349. }
  350. // store the current position
  351. dwLength = dwTemp;
  352. }
  353. else
  354. {
  355. // check if length is determined or not .. if not required width itself is length
  356. if ( dwLength == 0 || ((StringLengthInBytes( pszValue ) - dwLength) > dwWidth) )
  357. dwLength = dwWidth;
  358. else if ( StringLengthInBytes( pszValue ) <= (LONG) dwWidth )
  359. dwLength = StringLengthInBytes( pszValue );
  360. // break the loop
  361. break;
  362. }
  363. }
  364. // get the partial value that has to be displayed
  365. lstrcpyn( pszBuffer, pszValue, dwLength + 1 ); // +1 for NULL character
  366. AdjustStringLength( pszBuffer, dwWidth, FALSE ); // adjust the string
  367. ShowMessage( fp, pszBuffer ); // display the value
  368. // change the buffer contents so that it contains rest of the undisplayed text
  369. lstrcpy( pszBuffer, pszValue );
  370. if ( StringLengthInBytes( pszValue ) > (LONG) dwLength )
  371. lstrcpy( pszValue, pszBuffer + dwLength );
  372. else
  373. lstrcpy( pszValue, _T( "" ) );
  374. // release the memory allocated
  375. __free( pszBuffer );
  376. }
  377. // ***************************************************************************
  378. // Routine Description:
  379. // Displays the arrData in Tabular form.
  380. //
  381. // Arguments:
  382. // [ in ] fp : Output Device
  383. // [ in ] dwColumns : no. of columns
  384. // [ in ] pColumns : Header strings
  385. // [ in ] dwFlags : flags
  386. // [ in ] arrData : data to be shown
  387. //
  388. // Return Value:
  389. // NONE
  390. //
  391. // ***************************************************************************
  392. VOID __ShowAsTable( FILE* fp, DWORD dwColumns,
  393. PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData )
  394. {
  395. // local variables
  396. DWORD dwCount = 0; // holds the count of the records
  397. DWORD i = 0, j = 0, k = 0; // looping variables
  398. DWORD dwColumn = 0;
  399. LONG lLastColumn = 0;
  400. DWORD dwMultiLineColumns = 0;
  401. BOOL bNeedSpace = FALSE;
  402. BOOL bPadLeft = FALSE;
  403. TARRAY arrRecord = NULL;
  404. TARRAY arrMultiLine = NULL;
  405. LPCTSTR pszData = NULL;
  406. LPCTSTR pszSeperator = NULL;
  407. __STRING_4096 szValue = NULL_STRING; // custom value formatter
  408. // constants
  409. const DWORD cdwColumn = 0;
  410. const DWORD cdwSeperator = 1;
  411. const DWORD cdwData = 2;
  412. // create an multi-line data display helper array
  413. arrMultiLine = CreateDynamicArray();
  414. if ( arrMultiLine == NULL )
  415. {
  416. SetLastError( E_OUTOFMEMORY );
  417. SaveLastError();
  418. return;
  419. }
  420. // check whether header has to be displayed or not
  421. if ( ! ( dwFlags & SR_NOHEADER ) )
  422. {
  423. //
  424. // header needs to be displayed
  425. // traverse thru the column headers and display
  426. bNeedSpace = FALSE;
  427. for ( i = 0; i < dwColumns; i++ )
  428. {
  429. // check whether user wants to display this column or not
  430. if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN )
  431. continue; // user doesn't want this column to be displayed .. skip
  432. // determine the padding direction
  433. bPadLeft = FALSE;
  434. if ( pColumns[ i ].dwFlags & SR_ALIGN_LEFT )
  435. bPadLeft = TRUE;
  436. else
  437. {
  438. switch( pColumns[ i ].dwFlags & SR_TYPE_MASK )
  439. {
  440. case SR_TYPE_NUMERIC:
  441. case SR_TYPE_FLOAT:
  442. case SR_TYPE_DOUBLE:
  443. bPadLeft = TRUE;
  444. break;
  445. }
  446. }
  447. // check if column header seperator is needed or not and based on that show
  448. if ( bNeedSpace == TRUE )
  449. {
  450. // show space as column header seperator
  451. DISPLAY_MESSAGE( fp, _T( " " ) );
  452. }
  453. // print the column heading
  454. // NOTE: column will be displayed either by expanding or shrinking
  455. // based on the length of the column heading as well as width of the column
  456. FORMAT_STRING_EX( szValue, _T( "%s" ),
  457. pColumns[ i ].szColumn, pColumns[ i ].dwWidth, bPadLeft );
  458. DISPLAY_MESSAGE( fp, szValue ); // column heading
  459. // inform that from next time onward display column header separator
  460. bNeedSpace = TRUE;
  461. }
  462. // display the new line character ... seperation b/w headings and separator line
  463. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  464. // display the seperator chars under each column header
  465. bNeedSpace = FALSE;
  466. for ( i = 0; i < dwColumns; i++ )
  467. {
  468. // check whether user wants to display this column or not
  469. if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN )
  470. continue; // user doesn't want this column to be displayed .. skip
  471. // check if column header seperator is needed or not and based on that show
  472. if ( bNeedSpace == TRUE )
  473. {
  474. // show space as column header seperator
  475. DISPLAY_MESSAGE( fp, _T( " " ) );
  476. }
  477. // display seperator based on the required column width
  478. DISPLAY_MESSAGE( fp, Replicate( szValue, _T( "=" ), pColumns[ i ].dwWidth ) );
  479. // inform that from next time onward display column header separator
  480. bNeedSpace = TRUE;
  481. }
  482. // display the new line character ... seperation b/w headings and actual data
  483. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  484. }
  485. //
  486. // start displaying
  487. // get the total no. of records available
  488. dwCount = DynArrayGetCount( arrData );
  489. // traverse thru the records one-by-one
  490. for( i = 0; i < dwCount; i++ )
  491. {
  492. // clear the existing value
  493. lstrcpy( szValue, NULL_STRING );
  494. // get the pointer to the current record
  495. arrRecord = DynArrayItem( arrData, i );
  496. if ( arrRecord == NULL )
  497. continue;
  498. // traverse thru the columns and display the values
  499. bNeedSpace = FALSE;
  500. for ( j = 0; j < dwColumns; j++ )
  501. {
  502. // sub-local variables used in this loop
  503. DWORD dwTempWidth = 0;
  504. BOOL bTruncation = FALSE;
  505. // check whether user wants to display this column or not
  506. if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN )
  507. continue; // user doesn't want this column to be displayed .. skip
  508. // get the value of the column
  509. // NOTE: CHECK IF USER ASKED NOT TO TRUNCATE THE DATA OR NOT
  510. if ( pColumns[ j ].dwFlags & SR_NO_TRUNCATION )
  511. {
  512. bTruncation = TRUE;
  513. dwTempWidth = pColumns[ j ].dwWidth;
  514. pColumns[ j ].dwWidth = SIZE_OF_ARRAY( szValue );
  515. }
  516. // prepare the value
  517. __GetValue( &pColumns[ j ], j, arrRecord, szValue, _T( ", " ) );
  518. // determine the padding direction
  519. bPadLeft = FALSE;
  520. if ( bTruncation == FALSE )
  521. {
  522. if ( pColumns[ j ].dwFlags & SR_ALIGN_LEFT )
  523. bPadLeft = TRUE;
  524. else
  525. {
  526. switch( pColumns[ j ].dwFlags & SR_TYPE_MASK )
  527. {
  528. case SR_TYPE_NUMERIC:
  529. case SR_TYPE_FLOAT:
  530. case SR_TYPE_DOUBLE:
  531. bPadLeft = TRUE;
  532. break;
  533. }
  534. }
  535. // adjust ...
  536. AdjustStringLength( szValue, pColumns[ j ].dwWidth, bPadLeft );
  537. }
  538. // reset the width of the current column if it is modified
  539. if ( bTruncation == TRUE )
  540. pColumns[ j ].dwWidth = dwTempWidth;
  541. // check if column header seperator is needed or not and based on that show
  542. if ( bNeedSpace == TRUE )
  543. {
  544. // show space as column header seperator
  545. DISPLAY_MESSAGE( fp, _T( " " ) );
  546. }
  547. // now display the value
  548. if ( pColumns[ j ].dwFlags & SR_WORDWRAP )
  549. {
  550. // display the text ( might be partial )
  551. __DisplayTextWrapped( fp, szValue, _T( ", " ), pColumns[ j ].dwWidth );
  552. // check if any info is left to be displayed
  553. if ( StringLengthInBytes( szValue ) != 0 )
  554. {
  555. LONG lIndex = 0;
  556. lIndex = DynArrayAppendRow( arrMultiLine, 3 );
  557. if ( lIndex != -1 )
  558. {
  559. DynArraySetDWORD2( arrMultiLine, lIndex, cdwColumn, j );
  560. DynArraySetString2( arrMultiLine, lIndex, cdwData, szValue, 0 );
  561. DynArraySetString2( arrMultiLine, lIndex, cdwSeperator, _T( ", " ), 0 );
  562. }
  563. }
  564. }
  565. else
  566. {
  567. DISPLAY_MESSAGE( fp, szValue );
  568. }
  569. // inform that from next time onward display column header separator
  570. bNeedSpace = TRUE;
  571. }
  572. // display the new line character ... seperation b/w two record
  573. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  574. // now display the multi-line column values
  575. dwMultiLineColumns = DynArrayGetCount( arrMultiLine );
  576. while( dwMultiLineColumns != 0 )
  577. {
  578. // reset
  579. dwColumn = 0;
  580. lLastColumn = -1;
  581. bNeedSpace = FALSE;
  582. // ...
  583. for( j = 0; j < dwMultiLineColumns; j++ )
  584. {
  585. // ge the column number
  586. dwColumn = DynArrayItemAsDWORD2( arrMultiLine, j, cdwColumn );
  587. // show spaces till the current column from the last column
  588. for( k = lLastColumn + 1; k < dwColumn; k++ )
  589. {
  590. // check whether user wants to display this column or not
  591. if ( pColumns[ k ].dwFlags & SR_HIDECOLUMN )
  592. continue; // user doesn't want this column to be displayed .. skip
  593. // check if column header seperator is needed or not and based on that show
  594. if ( bNeedSpace == TRUE )
  595. {
  596. // show space as column header seperator
  597. DISPLAY_MESSAGE( fp, _T( " " ) );
  598. }
  599. // display seperator based on the required column width
  600. DISPLAY_MESSAGE( fp, Replicate( szValue, _T( " " ), pColumns[ k ].dwWidth ) );
  601. // inform that from next time onward display column header separator
  602. bNeedSpace = TRUE;
  603. }
  604. // update the last column
  605. lLastColumn = dwColumn;
  606. // check if column header seperator is needed or not and based on that show
  607. if ( bNeedSpace == TRUE )
  608. {
  609. // show space as column header seperator
  610. DISPLAY_MESSAGE( fp, _T( " " ) );
  611. }
  612. // get the seperator and data
  613. pszData = DynArrayItemAsString2( arrMultiLine, j, cdwData );
  614. pszSeperator = DynArrayItemAsString2( arrMultiLine, j, cdwSeperator );
  615. if ( pszData == NULL || pszSeperator == NULL )
  616. continue;
  617. // display the information
  618. lstrcpyn( szValue, pszData, SIZE_OF_ARRAY( szValue ) );
  619. __DisplayTextWrapped( fp, szValue, pszSeperator, pColumns[ dwColumn ].dwWidth );
  620. // update the multi-line array with rest of the line
  621. if ( StringLengthInBytes( szValue ) == 0 )
  622. {
  623. // data in this column is completely displayed ... remove it
  624. DynArrayRemove( arrMultiLine, j );
  625. // update the indexes
  626. j--;
  627. dwMultiLineColumns--;
  628. }
  629. else
  630. {
  631. // update the multi-line array with the remaining value
  632. DynArraySetString2( arrMultiLine, j, cdwData, szValue, 0 );
  633. }
  634. }
  635. // display the new line character ... seperation b/w two lines
  636. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  637. }
  638. }
  639. // destroy the array
  640. DestroyDynamicArray( &arrMultiLine );
  641. }
  642. // ***************************************************************************
  643. // Routine Description:
  644. // Displays the in List format
  645. //
  646. // Arguments:
  647. // [ in ] fp : Output Device
  648. // [ in ] dwColumns : no. of columns
  649. // [ in ] pColumns : Header strings
  650. // [ in ] dwFlags : flags
  651. // [ in ] arrData : data to be shown
  652. //
  653. // Return Value:
  654. // NONE
  655. //
  656. // ***************************************************************************
  657. VOID __ShowAsList( FILE* fp, DWORD dwColumns,
  658. PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData )
  659. {
  660. // local variables
  661. DWORD dwCount = 0; // holds the count of all records
  662. DWORD i = 0, j = 0; // looping variables
  663. DWORD dwTempWidth = 0;
  664. DWORD dwMaxColumnLen = 0; // holds the length of the which max. among all the columns
  665. LPTSTR pszTemp = NULL;
  666. TARRAY arrRecord = NULL;
  667. __STRING_64 szBuffer = NULL_STRING;
  668. __STRING_4096 szValue = NULL_STRING; // custom value formatter
  669. // find out the max. length among all the column headers
  670. dwMaxColumnLen = 0;
  671. for ( i = 0; i < dwColumns; i++ )
  672. {
  673. if ( dwMaxColumnLen < ( DWORD ) StringLengthInBytes( pColumns[ i ].szColumn ) )
  674. dwMaxColumnLen = StringLengthInBytes( pColumns[ i ].szColumn );
  675. }
  676. //
  677. // start displaying the data
  678. // get the total no. of records available
  679. dwCount = DynArrayGetCount( arrData );
  680. // get the total no. of records available
  681. for( i = 0; i < dwCount; i++ )
  682. {
  683. // get the pointer to the current record
  684. arrRecord = DynArrayItem( arrData, i );
  685. if ( arrRecord == NULL )
  686. continue;
  687. // traverse thru the columns and display the values
  688. for ( j = 0; j < dwColumns; j++)
  689. {
  690. // clear the existing value
  691. lstrcpy( szValue, NULL_STRING );
  692. // check whether user wants to display this column or not
  693. if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN )
  694. continue; // user doesn't want this column to be displayed .. skip
  695. // display the column heading and its value
  696. // ( heading will be displayed based on the max. column length )
  697. FORMAT_STRING_EX( szValue, _T( "%s:" ),
  698. pColumns[ j ].szColumn, dwMaxColumnLen + 2, FALSE );
  699. DISPLAY_MESSAGE( fp, szValue );
  700. // get the value of the column
  701. dwTempWidth = pColumns[ j ].dwWidth; // save the current width
  702. pColumns[ j ].dwWidth = SIZE_OF_ARRAY( szValue ); // change the width
  703. __GetValue( &pColumns[ j ], j, arrRecord, szValue, _T( "\n" ) );
  704. pColumns[ j ].dwWidth = dwTempWidth; // restore the original width
  705. // display the [ list of ] values
  706. pszTemp = _tcstok( szValue, _T( "\n" ) );
  707. while ( pszTemp != NULL )
  708. {
  709. // display the value
  710. DISPLAY_MESSAGE( fp, pszTemp );
  711. pszTemp = _tcstok( NULL, _T( "\n" ) );
  712. if ( pszTemp != NULL )
  713. {
  714. // prepare the next line
  715. FORMAT_STRING_EX( szBuffer, _T( "%s" ), _T( " " ),
  716. dwMaxColumnLen + 2, FALSE );
  717. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  718. DISPLAY_MESSAGE( fp, szBuffer );
  719. }
  720. }
  721. // display the next line character seperation b/w two fields
  722. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  723. }
  724. // display the new line character ... seperation b/w two records
  725. // NOTE: do this only if there are some more records
  726. if ( i + 1 < dwCount )
  727. {
  728. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  729. }
  730. }
  731. }
  732. // ***************************************************************************
  733. // Routine Description:
  734. // Displays the arrData in CSV form.
  735. //
  736. // Arguments:
  737. // [ in ] fp : Output Device
  738. // [ in ] dwColumns : no. of columns
  739. // [ in ] pColumns : Header strings
  740. // [ in ] dwFlags : flags
  741. // [ in ] arrData : data to be shown
  742. //
  743. // Return Value:
  744. // NONE
  745. //
  746. // ***************************************************************************
  747. VOID __ShowAsCSV( FILE* fp, DWORD dwColumns,
  748. PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData )
  749. {
  750. // local variables
  751. DWORD dwCount = 0; // holds the count of all records
  752. DWORD i = 0, j = 0; // looping variables
  753. DWORD dwTempWidth = 0;
  754. BOOL bNeedComma = FALSE;
  755. TARRAY arrRecord = NULL;
  756. __STRING_4096 szValue = NULL_STRING;
  757. // check whether header has to be displayed or not
  758. if ( ! ( dwFlags & SR_NOHEADER ) )
  759. {
  760. //
  761. // header needs to be displayed
  762. // first display the columns ... with comma seperated
  763. bNeedComma = FALSE;
  764. for ( i = 0; i < dwColumns; i++ )
  765. {
  766. // check whether user wants to display this column or not
  767. if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN )
  768. continue; // user doesn't want this column to be displayed .. skip
  769. // check whether we need to display ',' or not and then display
  770. if ( bNeedComma == TRUE )
  771. {
  772. // ',' has to be displayed
  773. DISPLAY_MESSAGE( fp, _T( "," ) );
  774. }
  775. // display the column heading
  776. DISPLAY_MESSAGE1( fp, szValue, _T( "\"%s\"" ), pColumns[ i ].szColumn );
  777. // inform that from next time onwards we need to display comma before data
  778. bNeedComma = TRUE;
  779. }
  780. // new line character
  781. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  782. }
  783. //
  784. // start displaying the data
  785. // get the total no. of records available
  786. dwCount = DynArrayGetCount( arrData );
  787. // get the total no. of records available
  788. for( i = 0; i < dwCount; i++ )
  789. {
  790. // get the pointer to the current record
  791. arrRecord = DynArrayItem( arrData, i );
  792. if ( arrRecord == NULL )
  793. continue;
  794. // traverse thru the columns and display the values
  795. bNeedComma = FALSE;
  796. for ( j = 0; j < dwColumns; j++ )
  797. {
  798. // clear the existing value
  799. lstrcpy( szValue, NULL_STRING );
  800. // check whether user wants to display this column or not
  801. if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN )
  802. continue; // user doesn't want this column to be displayed .. skip
  803. // get the value of the column
  804. dwTempWidth = pColumns[ j ].dwWidth; // save the current width
  805. pColumns[ j ].dwWidth = SIZE_OF_ARRAY( szValue ); // change the width
  806. __GetValue( &pColumns[ j ], j, arrRecord, szValue, _T( "," ) );
  807. pColumns[ j ].dwWidth = dwTempWidth; // restore the original width
  808. // check whether we need to display ',' or not and then display
  809. if ( bNeedComma == TRUE )
  810. {
  811. // ',' has to be displayed
  812. DISPLAY_MESSAGE( fp, _T( "," ) );
  813. }
  814. // print the value
  815. DISPLAY_MESSAGE( fp, _T( "\"" ) );
  816. DISPLAY_MESSAGE( fp, szValue );
  817. DISPLAY_MESSAGE( fp, _T( "\"" ) );
  818. // inform that from next time onwards we need to display comma before data
  819. bNeedComma = TRUE;
  820. }
  821. // new line character
  822. DISPLAY_MESSAGE( fp, _T( "\n" ) );
  823. }
  824. }
  825. //
  826. // public functions ... exposed to external world
  827. //
  828. // ***************************************************************************
  829. // Routine Description:
  830. //
  831. // Arguments:
  832. //
  833. // Return Value:
  834. //
  835. // ***************************************************************************
  836. VOID ShowResults( DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData )
  837. {
  838. // just call the main function ... with stdout
  839. ShowResults2( stdout, dwColumns, pColumns, dwFlags, arrData );
  840. }
  841. // ***************************************************************************
  842. // Routine Description:
  843. // Show the resuls (arrData) on the screen.
  844. //
  845. // Arguments:
  846. // [ in ] dwColumns : No. of Columns to be shown
  847. // [ in ] pColumns : Columns header
  848. // [ in ] dwFlags : Required format
  849. // [ in ] arrData : Data to be displayed.
  850. //
  851. // Return Value:
  852. // NONE
  853. //
  854. // ***************************************************************************
  855. VOID ShowResults2( FILE* fp, DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData )
  856. {
  857. // local variables
  858. //
  859. // Display the information in the format specified
  860. //
  861. switch( dwFlags & SR_FORMAT_MASK )
  862. {
  863. case SR_FORMAT_TABLE:
  864. {
  865. // show the data in table format
  866. __ShowAsTable( fp, dwColumns, pColumns, dwFlags, arrData );
  867. // switch case completed
  868. break;
  869. }
  870. case SR_FORMAT_LIST:
  871. {
  872. // show the data in table format
  873. __ShowAsList( fp, dwColumns, pColumns, dwFlags, arrData );
  874. // switch case completed
  875. break;
  876. }
  877. case SR_FORMAT_CSV:
  878. {
  879. // show the data in table format
  880. __ShowAsCSV( fp, dwColumns, pColumns, dwFlags, arrData );
  881. // switch case completed
  882. break;
  883. }
  884. default:
  885. {
  886. // invalid format requested by the user
  887. break;
  888. }
  889. }
  890. // flush the memory onto the file buffer
  891. fflush( fp );
  892. }