// ********************************************************************************* // // Copyright (c) Microsoft Corporation // // Module Name: // // ShowResults.c // // Abstract: // // This modules has functions which are to shoow formatted Results on screen. // // Author: // // Sunil G.V.N. Murali (murali.sunil@wipro.com) 24-Sep-2000 // // Revision History: // // Sunil G.V.N. Murali (murali.sunil@wipro.com) 01-Sep-2000 : Created It. // // ********************************************************************************* #include "pch.h" #include "cmdline.h" #include "cmdlineres.h" // // constants / defines / enumerations // // // private functions ... used only within this file // // *************************************************************************** // Routine Description: // Prepares the pszBuffer string by taking values from arrValues and // formate these values as per szFormat string. // // Arguments: // [ in ] arrValues : values to be formated. // [ out ] pszBuffer : output string // [ in ] dwLength : string length. // [ in ] szFormat : format // [ in ] szSeperator : Seperator string // // Return Value: // NONE // // *************************************************************************** VOID __PrepareString( TARRAY arrValues, LPTSTR pszBuffer, DWORD dwLength, LPCTSTR szFormat, LPCTSTR szSeperator ) { // local variables DWORD dw = 0; DWORD dwCount = 0; LPTSTR pszTemp = NULL; LPTSTR pszValue = NULL; // // kick off // init lstrcpy( pszBuffer, NULL_STRING ); dwCount = DynArrayGetCount( arrValues ); // allocate memory for buffers pszTemp = __calloc( dwLength + 5, sizeof( TCHAR ) ); pszValue = __calloc( dwLength + 5, sizeof( TCHAR ) ); if ( pszTemp == NULL || pszValue == NULL ) { // release memories __free( pszTemp ); __free( pszValue ); return; } // // traverse thru the list of the values and concatenate them // to the destination buffer for( dw = 0; dw < dwCount; dw++ ) { // get the current value into the temporary string buffer DynArrayItemAsStringEx( arrValues, dw, pszValue, dwLength ); // concatenate the temporary string to the original buffer FORMAT_STRING( pszTemp, szFormat, _X( pszValue ) ); lstrcat( pszBuffer, pszTemp ); dwLength -= StringLengthInBytes( pszTemp ); // check whether this is the last value or not if ( dw + 1 < dwCount ) { // there are some more values // check whether is space for adding the seperator or not if ( dwLength < (DWORD) StringLengthInBytes( szSeperator ) ) { // no more space available ... break break; } else { // add the seperator and update the length accordingly lstrcat( pszBuffer, szSeperator ); dwLength -= StringLengthInBytes( szSeperator ); } } } // release memories __free( pszTemp ); __free( pszValue ); } // *************************************************************************** // Routine Description: // Gets the value from arrRecord and copies it to pszValue using // proper format. // // Arguments: // [ in ] pColumn : format info. // [ in ] dwColumn : no of columns // [ in ] arrRecord : value to be formatted // [ out ] pszValue : output string // [ in ] szArraySeperator : seperator used. // // Return Value: // NONE // // *************************************************************************** VOID __GetValue( PTCOLUMNS pColumn, DWORD dwColumn, TARRAY arrRecord, LPTSTR pszValue, LPCTSTR szArraySeperator ) { // local variables LPVOID pData = NULL; // data to be passed to formatter function TARRAY arrTemp = NULL; LPCTSTR pszTemp = NULL; __STRING_64 szFormat = NULL_STRING; // format // variables used in formatting time DWORD dwReturn = 0; SYSTEMTIME systime = { 0 }; // init first lstrcpy( pszValue, NULL_STRING ); // get the column value and do formatting appropriately switch( pColumn->dwFlags & SR_TYPE_MASK ) { case SR_TYPE_STRING: { // identify the format to be used if ( pColumn->dwFlags & SR_VALUEFORMAT ) lstrcpy( szFormat, pColumn->szFormat ); else lstrcpy( szFormat, _T( "%s" ) ); // default format // copy the value to the temporary buffer based on the flags specified if ( pColumn->dwFlags & SR_ARRAY ) { // get the value into buffer first - AVOIDING PREFIX BUGS arrTemp = DynArrayItem( arrRecord, dwColumn ); if ( arrTemp == NULL ) return; // form the array of values into one single string with ',' seperated __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, szArraySeperator ); } else { // get the value into buffer first - AVOIDING PREFIX BUGS pszTemp = DynArrayItemAsString( arrRecord, dwColumn ); if ( pszTemp == NULL ) return; // now copy the value into buffer FORMAT_STRING( pszValue, szFormat, _X( pszTemp ) ); } // switch case completed break; } case SR_TYPE_NUMERIC: { // identify the format to be used if ( pColumn->dwFlags & SR_VALUEFORMAT ) lstrcpy( szFormat, pColumn->szFormat ); else lstrcpy( szFormat, _T( "%d" ) ); // default format // copy the value to the temporary buffer based on the flags specified if ( pColumn->dwFlags & SR_ARRAY ) { // get the value into buffer first - AVOIDING PREFIX BUGS arrTemp = DynArrayItem( arrRecord, dwColumn ); if ( arrTemp == NULL ) return; // form the array of values into one single string with ',' seperated __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, _T( ", " ) ); } else { // get the value using format specified FORMAT_STRING( pszValue, szFormat, DynArrayItemAsDWORD( arrRecord, dwColumn ) ); } // switch case completed break; } case SR_TYPE_FLOAT: { // identify the format to be used // NOTE: for this type, format needs to be specified // if not, value displayed is unpredictable if ( pColumn->dwFlags & SR_VALUEFORMAT ) lstrcpy( szFormat, pColumn->szFormat ); else lstrcpy( szFormat, _T( "%f" ) ); // default format // copy the value to the temporary buffer based on the flags specified if ( pColumn->dwFlags & SR_ARRAY ) { // get the value into buffer first - AVOIDING PREFIX BUGS arrTemp = DynArrayItem( arrRecord, dwColumn ); if ( arrTemp == NULL ) return; // form the array of values into one single string with ',' seperated __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, szArraySeperator ); } else { // get the value using format specified FORMAT_STRING( pszValue, szFormat, DynArrayItemAsFloat( arrRecord, dwColumn ) ); } // switch case completed break; } case SR_TYPE_DOUBLE: { // identify the format to be used // NOTE: for this type, format needs to be specified // if not, value displayed is unpredictable if ( pColumn->dwFlags & SR_VALUEFORMAT ) lstrcpy( szFormat, pColumn->szFormat ); else lstrcpy( szFormat, _T( "%f" ) ); // default format // copy the value to the temporary buffer based on the flags specified if ( pColumn->dwFlags & SR_ARRAY ) { // get the value into buffer first - AVOIDING PREFIX BUGS arrTemp = DynArrayItem( arrRecord, dwColumn ); if ( arrTemp == NULL ) return; // form the array of values into one single string with ',' seperated __PrepareString( arrTemp, pszValue, pColumn->dwWidth, szFormat, szArraySeperator ); } else { // get the value using format specified FORMAT_STRING( pszValue, szFormat, DynArrayItemAsDouble( arrRecord, dwColumn ) ); } // switch case completed break; } case SR_TYPE_TIME: { // get the time in the required format systime = DynArrayItemAsSystemTime( arrRecord, dwColumn ); // get the time in current locale format dwReturn = GetTimeFormat( LOCALE_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &systime, NULL, pszValue, MAX_STRING_LENGTH ); // check the result if ( dwReturn == 0 ) { // save the error info that has occurred SaveLastError(); lstrcpy( pszValue, GetReason() ); } // switch case completed break; } case SR_TYPE_CUSTOM: { // check whether function pointer is specified or not // if not specified, error if ( pColumn->pFunction == NULL ) return; // function ptr not specified ... error // determine the data to be passed to the formatter function pData = pColumn->pFunctionData; if ( pData == NULL ) // function data is not defined pData = pColumn; // the current column info itself as data // call the custom function ( *pColumn->pFunction)( dwColumn, arrRecord, pData, pszValue ); // switch case completed break; } case SR_TYPE_DATE: case SR_TYPE_DATETIME: default: { // this should not occur ... still lstrcpy( pszValue, NULL_STRING ); // switch case completed break; } } // user wants to display "N/A", when the value is empty, copy that if ( lstrlen( pszValue ) == 0 && pColumn->dwFlags & SR_SHOW_NA_WHEN_BLANK ) { // copy N/A lstrcpy( pszValue, V_NOT_AVAILABLE ); } } // *************************************************************************** // Routine Description: // // Arguments: // // Return Value: // // *************************************************************************** VOID __DisplayTextWrapped( FILE* fp, LPTSTR pszValue, LPCTSTR pszSeperator, DWORD dwWidth ) { // local variables LPTSTR pszBuffer = NULL; LPCTSTR pszRestValue = NULL; DWORD dwTemp = 0, dwLength = 0, dwSepLength = 0; // check the input if ( pszValue == NULL || dwWidth == 0 || fp == NULL ) return; // allocate buffer dwLength = StringLengthInBytes( pszValue ); if ( dwLength < dwWidth ) dwLength = dwWidth; // ... pszBuffer = __calloc( dwLength + 5, sizeof( TCHAR ) ); if ( pszBuffer == NULL ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); lstrcpy( pszValue, NULL_STRING ); // null-ify the remaining text return; } // determine the length of the seperator dwSepLength = 0; if ( pszSeperator != NULL ) dwSepLength = StringLengthInBytes( pszSeperator ); // determine the length of the data that can be displayed in this row dwTemp = 0; dwLength = 0; while ( 1 ) { pszRestValue = NULL; if ( pszSeperator != NULL ) pszRestValue = FindString( pszValue, pszSeperator, dwLength ); // check whether seperator is found or not if ( pszRestValue != NULL ) { // determine the position dwTemp = StringLengthInBytes( pszValue ) - StringLengthInBytes( pszRestValue ) + dwSepLength; // check the length if ( dwTemp >= dwWidth ) { // string position exceed the max. width if ( dwLength == 0 || dwTemp == dwWidth ) dwLength = dwWidth; // break from the loop break; } // store the current position dwLength = dwTemp; } else { // check if length is determined or not .. if not required width itself is length if ( dwLength == 0 || ((StringLengthInBytes( pszValue ) - dwLength) > dwWidth) ) dwLength = dwWidth; else if ( StringLengthInBytes( pszValue ) <= (LONG) dwWidth ) dwLength = StringLengthInBytes( pszValue ); // break the loop break; } } // get the partial value that has to be displayed lstrcpyn( pszBuffer, pszValue, dwLength + 1 ); // +1 for NULL character AdjustStringLength( pszBuffer, dwWidth, FALSE ); // adjust the string ShowMessage( fp, pszBuffer ); // display the value // change the buffer contents so that it contains rest of the undisplayed text lstrcpy( pszBuffer, pszValue ); if ( StringLengthInBytes( pszValue ) > (LONG) dwLength ) lstrcpy( pszValue, pszBuffer + dwLength ); else lstrcpy( pszValue, _T( "" ) ); // release the memory allocated __free( pszBuffer ); } // *************************************************************************** // Routine Description: // Displays the arrData in Tabular form. // // Arguments: // [ in ] fp : Output Device // [ in ] dwColumns : no. of columns // [ in ] pColumns : Header strings // [ in ] dwFlags : flags // [ in ] arrData : data to be shown // // Return Value: // NONE // // *************************************************************************** VOID __ShowAsTable( FILE* fp, DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData ) { // local variables DWORD dwCount = 0; // holds the count of the records DWORD i = 0, j = 0, k = 0; // looping variables DWORD dwColumn = 0; LONG lLastColumn = 0; DWORD dwMultiLineColumns = 0; BOOL bNeedSpace = FALSE; BOOL bPadLeft = FALSE; TARRAY arrRecord = NULL; TARRAY arrMultiLine = NULL; LPCTSTR pszData = NULL; LPCTSTR pszSeperator = NULL; __STRING_4096 szValue = NULL_STRING; // custom value formatter // constants const DWORD cdwColumn = 0; const DWORD cdwSeperator = 1; const DWORD cdwData = 2; // create an multi-line data display helper array arrMultiLine = CreateDynamicArray(); if ( arrMultiLine == NULL ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); return; } // check whether header has to be displayed or not if ( ! ( dwFlags & SR_NOHEADER ) ) { // // header needs to be displayed // traverse thru the column headers and display bNeedSpace = FALSE; for ( i = 0; i < dwColumns; i++ ) { // check whether user wants to display this column or not if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // determine the padding direction bPadLeft = FALSE; if ( pColumns[ i ].dwFlags & SR_ALIGN_LEFT ) bPadLeft = TRUE; else { switch( pColumns[ i ].dwFlags & SR_TYPE_MASK ) { case SR_TYPE_NUMERIC: case SR_TYPE_FLOAT: case SR_TYPE_DOUBLE: bPadLeft = TRUE; break; } } // check if column header seperator is needed or not and based on that show if ( bNeedSpace == TRUE ) { // show space as column header seperator DISPLAY_MESSAGE( fp, _T( " " ) ); } // print the column heading // NOTE: column will be displayed either by expanding or shrinking // based on the length of the column heading as well as width of the column FORMAT_STRING_EX( szValue, _T( "%s" ), pColumns[ i ].szColumn, pColumns[ i ].dwWidth, bPadLeft ); DISPLAY_MESSAGE( fp, szValue ); // column heading // inform that from next time onward display column header separator bNeedSpace = TRUE; } // display the new line character ... seperation b/w headings and separator line DISPLAY_MESSAGE( fp, _T( "\n" ) ); // display the seperator chars under each column header bNeedSpace = FALSE; for ( i = 0; i < dwColumns; i++ ) { // check whether user wants to display this column or not if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // check if column header seperator is needed or not and based on that show if ( bNeedSpace == TRUE ) { // show space as column header seperator DISPLAY_MESSAGE( fp, _T( " " ) ); } // display seperator based on the required column width DISPLAY_MESSAGE( fp, Replicate( szValue, _T( "=" ), pColumns[ i ].dwWidth ) ); // inform that from next time onward display column header separator bNeedSpace = TRUE; } // display the new line character ... seperation b/w headings and actual data DISPLAY_MESSAGE( fp, _T( "\n" ) ); } // // start displaying // get the total no. of records available dwCount = DynArrayGetCount( arrData ); // traverse thru the records one-by-one for( i = 0; i < dwCount; i++ ) { // clear the existing value lstrcpy( szValue, NULL_STRING ); // get the pointer to the current record arrRecord = DynArrayItem( arrData, i ); if ( arrRecord == NULL ) continue; // traverse thru the columns and display the values bNeedSpace = FALSE; for ( j = 0; j < dwColumns; j++ ) { // sub-local variables used in this loop DWORD dwTempWidth = 0; BOOL bTruncation = FALSE; // check whether user wants to display this column or not if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // get the value of the column // NOTE: CHECK IF USER ASKED NOT TO TRUNCATE THE DATA OR NOT if ( pColumns[ j ].dwFlags & SR_NO_TRUNCATION ) { bTruncation = TRUE; dwTempWidth = pColumns[ j ].dwWidth; pColumns[ j ].dwWidth = SIZE_OF_ARRAY( szValue ); } // prepare the value __GetValue( &pColumns[ j ], j, arrRecord, szValue, _T( ", " ) ); // determine the padding direction bPadLeft = FALSE; if ( bTruncation == FALSE ) { if ( pColumns[ j ].dwFlags & SR_ALIGN_LEFT ) bPadLeft = TRUE; else { switch( pColumns[ j ].dwFlags & SR_TYPE_MASK ) { case SR_TYPE_NUMERIC: case SR_TYPE_FLOAT: case SR_TYPE_DOUBLE: bPadLeft = TRUE; break; } } // adjust ... AdjustStringLength( szValue, pColumns[ j ].dwWidth, bPadLeft ); } // reset the width of the current column if it is modified if ( bTruncation == TRUE ) pColumns[ j ].dwWidth = dwTempWidth; // check if column header seperator is needed or not and based on that show if ( bNeedSpace == TRUE ) { // show space as column header seperator DISPLAY_MESSAGE( fp, _T( " " ) ); } // now display the value if ( pColumns[ j ].dwFlags & SR_WORDWRAP ) { // display the text ( might be partial ) __DisplayTextWrapped( fp, szValue, _T( ", " ), pColumns[ j ].dwWidth ); // check if any info is left to be displayed if ( StringLengthInBytes( szValue ) != 0 ) { LONG lIndex = 0; lIndex = DynArrayAppendRow( arrMultiLine, 3 ); if ( lIndex != -1 ) { DynArraySetDWORD2( arrMultiLine, lIndex, cdwColumn, j ); DynArraySetString2( arrMultiLine, lIndex, cdwData, szValue, 0 ); DynArraySetString2( arrMultiLine, lIndex, cdwSeperator, _T( ", " ), 0 ); } } } else { DISPLAY_MESSAGE( fp, szValue ); } // inform that from next time onward display column header separator bNeedSpace = TRUE; } // display the new line character ... seperation b/w two record DISPLAY_MESSAGE( fp, _T( "\n" ) ); // now display the multi-line column values dwMultiLineColumns = DynArrayGetCount( arrMultiLine ); while( dwMultiLineColumns != 0 ) { // reset dwColumn = 0; lLastColumn = -1; bNeedSpace = FALSE; // ... for( j = 0; j < dwMultiLineColumns; j++ ) { // ge the column number dwColumn = DynArrayItemAsDWORD2( arrMultiLine, j, cdwColumn ); // show spaces till the current column from the last column for( k = lLastColumn + 1; k < dwColumn; k++ ) { // check whether user wants to display this column or not if ( pColumns[ k ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // check if column header seperator is needed or not and based on that show if ( bNeedSpace == TRUE ) { // show space as column header seperator DISPLAY_MESSAGE( fp, _T( " " ) ); } // display seperator based on the required column width DISPLAY_MESSAGE( fp, Replicate( szValue, _T( " " ), pColumns[ k ].dwWidth ) ); // inform that from next time onward display column header separator bNeedSpace = TRUE; } // update the last column lLastColumn = dwColumn; // check if column header seperator is needed or not and based on that show if ( bNeedSpace == TRUE ) { // show space as column header seperator DISPLAY_MESSAGE( fp, _T( " " ) ); } // get the seperator and data pszData = DynArrayItemAsString2( arrMultiLine, j, cdwData ); pszSeperator = DynArrayItemAsString2( arrMultiLine, j, cdwSeperator ); if ( pszData == NULL || pszSeperator == NULL ) continue; // display the information lstrcpyn( szValue, pszData, SIZE_OF_ARRAY( szValue ) ); __DisplayTextWrapped( fp, szValue, pszSeperator, pColumns[ dwColumn ].dwWidth ); // update the multi-line array with rest of the line if ( StringLengthInBytes( szValue ) == 0 ) { // data in this column is completely displayed ... remove it DynArrayRemove( arrMultiLine, j ); // update the indexes j--; dwMultiLineColumns--; } else { // update the multi-line array with the remaining value DynArraySetString2( arrMultiLine, j, cdwData, szValue, 0 ); } } // display the new line character ... seperation b/w two lines DISPLAY_MESSAGE( fp, _T( "\n" ) ); } } // destroy the array DestroyDynamicArray( &arrMultiLine ); } // *************************************************************************** // Routine Description: // Displays the in List format // // Arguments: // [ in ] fp : Output Device // [ in ] dwColumns : no. of columns // [ in ] pColumns : Header strings // [ in ] dwFlags : flags // [ in ] arrData : data to be shown // // Return Value: // NONE // // *************************************************************************** VOID __ShowAsList( FILE* fp, DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData ) { // local variables DWORD dwCount = 0; // holds the count of all records DWORD i = 0, j = 0; // looping variables DWORD dwTempWidth = 0; DWORD dwMaxColumnLen = 0; // holds the length of the which max. among all the columns LPTSTR pszTemp = NULL; TARRAY arrRecord = NULL; __STRING_64 szBuffer = NULL_STRING; __STRING_4096 szValue = NULL_STRING; // custom value formatter // find out the max. length among all the column headers dwMaxColumnLen = 0; for ( i = 0; i < dwColumns; i++ ) { if ( dwMaxColumnLen < ( DWORD ) StringLengthInBytes( pColumns[ i ].szColumn ) ) dwMaxColumnLen = StringLengthInBytes( pColumns[ i ].szColumn ); } // // start displaying the data // get the total no. of records available dwCount = DynArrayGetCount( arrData ); // get the total no. of records available for( i = 0; i < dwCount; i++ ) { // get the pointer to the current record arrRecord = DynArrayItem( arrData, i ); if ( arrRecord == NULL ) continue; // traverse thru the columns and display the values for ( j = 0; j < dwColumns; j++) { // clear the existing value lstrcpy( szValue, NULL_STRING ); // check whether user wants to display this column or not if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // display the column heading and its value // ( heading will be displayed based on the max. column length ) FORMAT_STRING_EX( szValue, _T( "%s:" ), pColumns[ j ].szColumn, dwMaxColumnLen + 2, FALSE ); DISPLAY_MESSAGE( fp, szValue ); // get the value of the column dwTempWidth = pColumns[ j ].dwWidth; // save the current width pColumns[ j ].dwWidth = SIZE_OF_ARRAY( szValue ); // change the width __GetValue( &pColumns[ j ], j, arrRecord, szValue, _T( "\n" ) ); pColumns[ j ].dwWidth = dwTempWidth; // restore the original width // display the [ list of ] values pszTemp = _tcstok( szValue, _T( "\n" ) ); while ( pszTemp != NULL ) { // display the value DISPLAY_MESSAGE( fp, pszTemp ); pszTemp = _tcstok( NULL, _T( "\n" ) ); if ( pszTemp != NULL ) { // prepare the next line FORMAT_STRING_EX( szBuffer, _T( "%s" ), _T( " " ), dwMaxColumnLen + 2, FALSE ); DISPLAY_MESSAGE( fp, _T( "\n" ) ); DISPLAY_MESSAGE( fp, szBuffer ); } } // display the next line character seperation b/w two fields DISPLAY_MESSAGE( fp, _T( "\n" ) ); } // display the new line character ... seperation b/w two records // NOTE: do this only if there are some more records if ( i + 1 < dwCount ) { DISPLAY_MESSAGE( fp, _T( "\n" ) ); } } } // *************************************************************************** // Routine Description: // Displays the arrData in CSV form. // // Arguments: // [ in ] fp : Output Device // [ in ] dwColumns : no. of columns // [ in ] pColumns : Header strings // [ in ] dwFlags : flags // [ in ] arrData : data to be shown // // Return Value: // NONE // // *************************************************************************** VOID __ShowAsCSV( FILE* fp, DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData ) { // local variables DWORD dwCount = 0; // holds the count of all records DWORD i = 0, j = 0; // looping variables DWORD dwTempWidth = 0; BOOL bNeedComma = FALSE; TARRAY arrRecord = NULL; __STRING_4096 szValue = NULL_STRING; // check whether header has to be displayed or not if ( ! ( dwFlags & SR_NOHEADER ) ) { // // header needs to be displayed // first display the columns ... with comma seperated bNeedComma = FALSE; for ( i = 0; i < dwColumns; i++ ) { // check whether user wants to display this column or not if ( pColumns[ i ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // check whether we need to display ',' or not and then display if ( bNeedComma == TRUE ) { // ',' has to be displayed DISPLAY_MESSAGE( fp, _T( "," ) ); } // display the column heading DISPLAY_MESSAGE1( fp, szValue, _T( "\"%s\"" ), pColumns[ i ].szColumn ); // inform that from next time onwards we need to display comma before data bNeedComma = TRUE; } // new line character DISPLAY_MESSAGE( fp, _T( "\n" ) ); } // // start displaying the data // get the total no. of records available dwCount = DynArrayGetCount( arrData ); // get the total no. of records available for( i = 0; i < dwCount; i++ ) { // get the pointer to the current record arrRecord = DynArrayItem( arrData, i ); if ( arrRecord == NULL ) continue; // traverse thru the columns and display the values bNeedComma = FALSE; for ( j = 0; j < dwColumns; j++ ) { // clear the existing value lstrcpy( szValue, NULL_STRING ); // check whether user wants to display this column or not if ( pColumns[ j ].dwFlags & SR_HIDECOLUMN ) continue; // user doesn't want this column to be displayed .. skip // get the value of the column dwTempWidth = pColumns[ j ].dwWidth; // save the current width pColumns[ j ].dwWidth = SIZE_OF_ARRAY( szValue ); // change the width __GetValue( &pColumns[ j ], j, arrRecord, szValue, _T( "," ) ); pColumns[ j ].dwWidth = dwTempWidth; // restore the original width // check whether we need to display ',' or not and then display if ( bNeedComma == TRUE ) { // ',' has to be displayed DISPLAY_MESSAGE( fp, _T( "," ) ); } // print the value DISPLAY_MESSAGE( fp, _T( "\"" ) ); DISPLAY_MESSAGE( fp, szValue ); DISPLAY_MESSAGE( fp, _T( "\"" ) ); // inform that from next time onwards we need to display comma before data bNeedComma = TRUE; } // new line character DISPLAY_MESSAGE( fp, _T( "\n" ) ); } } // // public functions ... exposed to external world // // *************************************************************************** // Routine Description: // // Arguments: // // Return Value: // // *************************************************************************** VOID ShowResults( DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData ) { // just call the main function ... with stdout ShowResults2( stdout, dwColumns, pColumns, dwFlags, arrData ); } // *************************************************************************** // Routine Description: // Show the resuls (arrData) on the screen. // // Arguments: // [ in ] dwColumns : No. of Columns to be shown // [ in ] pColumns : Columns header // [ in ] dwFlags : Required format // [ in ] arrData : Data to be displayed. // // Return Value: // NONE // // *************************************************************************** VOID ShowResults2( FILE* fp, DWORD dwColumns, PTCOLUMNS pColumns, DWORD dwFlags, TARRAY arrData ) { // local variables // // Display the information in the format specified // switch( dwFlags & SR_FORMAT_MASK ) { case SR_FORMAT_TABLE: { // show the data in table format __ShowAsTable( fp, dwColumns, pColumns, dwFlags, arrData ); // switch case completed break; } case SR_FORMAT_LIST: { // show the data in table format __ShowAsList( fp, dwColumns, pColumns, dwFlags, arrData ); // switch case completed break; } case SR_FORMAT_CSV: { // show the data in table format __ShowAsCSV( fp, dwColumns, pColumns, dwFlags, arrData ); // switch case completed break; } default: { // invalid format requested by the user break; } } // flush the memory onto the file buffer fflush( fp ); }