TREE.CPP

// ==================================================================== 
//
// File: tree.cpp
//
// Copyright (c) 1994, 1995 Microsoft Corp.
//
// Author:
// Jonathan Shuval Microsoft Corp.
//
//
// This sample builds a tree of the container/folder hierarchy and
// displays it to the console.
//
// The information that is displayed is as follows:
// For each container we display the container's type and tag followed
// by a list of filters (possibly empty). This lists filters that are
// acted upon directly at that level.
// Following the filter list is a folder list. This gives the folder's
// type and tag, its filter list, and then a list of scalars for the
// folder.
// The scalar display shows the scalar name, it's type, and its access
// mode.
//
// See the readme.txt file in this directory for more information.
//
// ====================================================================


// ====================================================================
//
// Includes
//
// ====================================================================
#include <afx.h>
#include <smsapi.h>


// ====================================================================
//
// Defines.
//
// ====================================================================
#define CCH_MAXSTRING 256


// ====================================================================
//
// Prototypes.
//
// ====================================================================

// Process a container.
// -------------------------------------------------------------
void doContainer( FOLDER_INFO *pContainer );


// Process a folder.
// -------------------------------------------------------------
void doFolder( DWORD folderType, int indent, DWORD dwConType );


// Adds a container to the container list.
// -------------------------------------------------------------
void AddContainer( DWORD dwConType );


// Given a filter type display its properties.
// -------------------------------------------------------------
void doFilter( DWORD dwFilterType, int indent );


// Locates filter of specified type from the global filter list.
// -------------------------------------------------------------
FILTER_INFO *FindFilter( DWORD filterType );


// Mark folder as already enumerated within this container graph.
// -------------------------------------------------------------
void Enumerated( DWORD dwConType, DWORD folderType );


// Call this to find out if this foldertype already been
// enumerated within this container graph.
// -------------------------------------------------------------
BOOL IsEnumerated(DWORD dwConType, DWORD folderType);


// Prompt the user for input and return the reply.
// -------------------------------------------------------------
void InputString( const char *pszMessage, char *pszResult );


// Display the help message.
// -------------------------------------------------------------
void DisplayHelp();

// Display the greeting.
// -------------------------------------------------------------
void DisplayGreeting();


// Check to see if there was a request for help
// on the command line.
// -------------------------------------------------------------
BOOL DidRequestHelp( int argc, char **argv );





// ====================================================================
//
// Globals.
//
// ====================================================================
FOLDER_INFO **gpFolders = NULL; // List of FOLDER_INFOs.
DWORD gctFolders = 0; // Count of them.


FILTER_INFO *gpFilters = NULL; // List of FILTER_INFOs.
DWORD gctFilters = 0; // Count of them.

//
// This struct is used to hold information about what folders
// have already been enumerated for a particular container.
//
typedef struct tagContainerEntry {
DWORD dwConType; // Container's type.
CDWordArray aEnumFolders; // Folders already enumerated.
} ContainerEntry;


CObArray ContainerList; // List of containers (contains list
// of ContainerEntry structs.)





// ====================================================================
//
// Start here.
//
// ====================================================================
void main( int argc, char** argv )
{
// Check to see if this is a request to display the help
// screen. If so, display it. Otherwise, display a greeting
// banner.
//=========================================================
if (DidRequestHelp( argc, argv )) {
DisplayHelp();
return;
}
else {
DisplayGreeting();
}



// Data.
// =====

DWORD ctContainers;
FOLDER_INFO **pContainers = NULL;
FOLDER_INFO *pCont = NULL;




// Enumerate containers.
// =====================

// Get number of containers.
SmsEnumContainers( NULL, &ctContainers );

// Allocate memory and get the containers.
pContainers = new FOLDER_INFO *[ctContainers];
SmsEnumContainers( pContainers, &ctContainers );


// Enumerate all filters.
// ======================
// Get number of filters.
SmsEnumFilters(NULL, &gctFilters);

// Allocate memory and get the filters.
gpFilters = new FILTER_INFO[gctFilters];
SmsEnumFilters( gpFilters, &gctFilters );


// Enumerate all folders.
// ======================
// Get number of folders.
SmsEnumFolders( NULL, &gctFolders );

// Allocate memory and get the folders.
gpFolders = new FOLDER_INFO *[gctFolders];
SmsEnumFolders( gpFolders, &gctFolders );


// Loop through each container.
// ============================

for (DWORD i = 0; i < ctContainers; i++) {

// Process the container
doContainer( pContainers[i] );
}

}



// ====================================================================
//
// doContainer -- process container.
//
// This is called from main. We print out information for this
// container, and then process each folder within the container.
//
// ====================================================================

void doContainer( FOLDER_INFO *pContainer )
{
DWORD dwI;

// Add this container to our container list.
// =========================================
AddContainer( pContainer->dwTag );

// We are now looking at the FOLDER_INFO for a container.
// We want to print out the count and list of filters,
// the folder type count, and then process each folder.
// ======================================================
printf("Container: %s [%d]\n", pContainer->pszTag, pContainer->dwTag);

// Print out list of filters.
// =============================
printf("%d filter(s)\n", pContainer->ctFilters);
DWORD *pFilters = pContainer->pFilterTags;

for (dwI = 0; dwI < pContainer->ctFilters; dwI++) {
doFilter( pFilters[dwI], 1 );
}


// Print out list of folders.
// ==========================
printf("%d folder-type(s)\n", pContainer->ctFolders);

DWORD *pFolderIDs = pContainer->pFolderTags;
for (dwI = 0; dwI < pContainer->ctFolders; dwI++) {

// Now cause the folder to print himself out.
// ------------------------------------------
doFolder( pFolderIDs[dwI], 1, pContainer->dwTag );
}

// No scalars for container.
// =========================

printf("\n\n");
}



// ====================================================================
//
// FindFilter -- locate filter of specified type from the list of
// filter descriptors returned by the API SmsEnumFilters.
//
// Return a pointer to the FILTER_INFO for the filter.
//
// Called from doFilter.
//
// ====================================================================

FILTER_INFO *FindFilter( DWORD filterType )
{
FILTER_INFO *pFI;
for (DWORD dwI = 0; dwI < gctFilters; dwI++) {
pFI = &gpFilters[dwI];
if (pFI->filterType == filterType) {
return(pFI);
}
}

return(NULL);
}


// ====================================================================
//
// dumpScalar -- given a SCALAR_INFO, display the scalar.
//
// We display the scalar's name, type, and access mode.
//
// Params:
// SCALAR_INFO Scalar to display.
// indent indent level
//
//
// ====================================================================

void dumpScalar( SCALAR_INFO *pSc, int indent )
{
// Indentation.
// ============
char szIndent[100];
memset( szIndent, '\0', 100 );
for (int iLevel = 0; iLevel < indent; iLevel++) {
strcat( szIndent, "\t");
}

char *pszType, *pszAccess;

// Determine scalar type, display accordingly.
// ===========================================
switch (pSc->scType) {
case SCALAR_STRING:
pszType = "string"; break;

case SCALAR_INT:
pszType = "integer"; break;

case SCALAR_TIME:
pszType = "time"; break;

case SCALAR_BINARY:
pszType = "binary"; break;
}

// Determine access mode, display accordingly.
// ===========================================
switch (pSc->fAccess) {
case ACCESS_READ:
pszAccess = "read"; break;

case ACCESS_CREATE:
pszAccess = "create"; break;

case ACCESS_MODIFY:
pszAccess = "modify"; break;

case ACCESS_DELETE:
pszAccess = "delete"; break;
}


printf("%s%s (%s, %s)\n", szIndent, pSc->szName, pszType, pszAccess);

}



// ====================================================================
//
// doScalars -- display a folder's scalar.
//
// Loop through the list of SCALAR structures that are embedded in the
// FOLDER_INFO, and display them.
//
// The 'indent' parameter says how far to indent the resulting display
// string so it looks almost presentable.
//
// Params:
// FOLDER_INFO *pFolder The structure describing the folder
// under consideration.
// int indent Indent level.
//
// Returns:
// Nothing.
//
// ====================================================================

void doScalars( FOLDER_INFO *pFolder, int indent )
{
SCALAR_INFO *pScalar;

for (DWORD dwI = 0; dwI < pFolder->ctScalars; dwI++) {
pScalar = &pFolder->pScalars[dwI];
dumpScalar( pScalar, indent );
}
}


// ====================================================================
//
// doFolder -- Given a folder type print out this folder's information.
//
// The folder has already been retrieved in SmsEnumFolders, we just
// access it from there.
//
// Params:
// folderType Folder type we're interested in.
// dwConType Container's type.
//
// Returns:
// Nothing.
//
// ====================================================================

void doFolder( DWORD folderType, int indent, DWORD dwConType )
{

FOLDER_INFO *pFolder;
DWORD dwI;
BOOL bFound = FALSE;

// Indentation.
// ============
char szIndent[100];
memset( szIndent, '\0', 100 );
for (int iLevel = 0; iLevel < indent; iLevel++) {
strcat( szIndent, "\t");
}


// Loop through the retrieved folders looking for
// the one with a tag for folderType.
// ==============================================
for (dwI = 0; dwI < gctFolders; dwI++) {
pFolder = gpFolders[dwI];
if (pFolder->dwTag == folderType) {
bFound = TRUE;
break;
}
}


if (!bFound) {
printf("<<< Error: couldn't locate folder %d >>>\n", folderType);
return;
}


// Display folder type and tag and filter count.
// =============================================
printf("%s********** %s folder [%d] **********\n",
szIndent, pFolder->pszTag, pFolder->dwTag);

// Check to see if it's already been displayed.
// We only want to do this in the context of the current container.
// ----------------------------------------------------------------
if (IsEnumerated(dwConType, folderType)) {
printf("%sFolder already enumerated in this container\n", szIndent);
printf("%s********** End of %s folder **********\n\n",
szIndent, pFolder->pszTag );
return;
}

printf("%s%d filter(s)\n", szIndent, pFolder->ctFilters);

// Print out list of filter types.
// ===============================
DWORD *pFilters = pFolder->pFilterTags;

for (dwI = 0; dwI < pFolder->ctFilters; dwI++) {
doFilter( pFilters[dwI], indent );
}

// Print out number of scalars, then display them.
// ===============================================
printf("%s%d scalars\n", szIndent, pFolder->ctScalars);
doScalars( pFolder, indent );


// Prepare to display sub-folders.
// ===============================
printf("%s%d folder-type(s)\n", szIndent, pFolder->ctFolders);


// Before processing sub-folder types mark this folder as already
// enumerated in this container. Prevents infinite recursion.
Enumerated(dwConType, folderType);

// Print out list of folder types.
DWORD *pFolderIDs = pFolder->pFolderTags;
for (dwI = 0; dwI < pFolder->ctFolders; dwI++) {
// Now cause the folder to print himself out.
doFolder( pFolderIDs[dwI], indent+1, dwConType );

}

printf("%s********** End of %s folder **********\n\n",
szIndent, pFolder->pszTag );

}



// ====================================================================
//
// doFilter -- given a filter type display its properties.
//
// Called from doContainer and doFolder.
//
// ====================================================================

void doFilter( DWORD dwFilterType, int indent )
{

FILTER_INFO *pFilter = FindFilter( dwFilterType );

if (!pFilter) {
printf("<<< Error: couldn't locate filter %d >>>\n", dwFilterType);
return;
}

// Indentation.
// ============
char szIndent[100];
memset( szIndent, '\0', 100 );
for (int iLevel = 0; iLevel < indent; iLevel++) {
strcat( szIndent, "\t");
}

// Display filter type and tag.
// ============================
printf("%s%s (%d)\n", szIndent, pFilter->szTag, dwFilterType);


// Display filter properties.
// ==========================
char *ppszField[10]; // Store pointers here.
DWORD ctFields = 0; // Number of pointers.

char szBuff[256]; // Build up output string here.
sprintf(szBuff, "%s\t[", szIndent); // Additional level of indent.

if (*(pFilter->szName)) {
ppszField[ctFields++] = "Token.szName = ";
ppszField[ctFields++] = pFilter->szName;
}

if (*(pFilter->szValue)) {
ppszField[ctFields++] = "Token.szValue = ";
ppszField[ctFields++] = pFilter->szValue;
}

if (*(pFilter->szOperator)) {
ppszField[ctFields++] = "Token.szOperator = ";
ppszField[ctFields++] = pFilter->szOperator;
}

if (*(pFilter->szArchitecture)) {
ppszField[ctFields++] = "Token.szArchitecture = ";
ppszField[ctFields++] = pFilter->szArchitecture;
}

if (*(pFilter->szGroupClass)) {
ppszField[ctFields++] = "Token.szGroupClass = ";
ppszField[ctFields++] = pFilter->szGroupClass;
}

if (*(pFilter->szAttributeName)) {
ppszField[ctFields++] = "Token.szAttributeName = ";
ppszField[ctFields++] = pFilter->szAttributeName;
}


for (DWORD dwI = 0; dwI < ctFields; dwI += 2) {
printf("\t%s%s\"%s\"\n", szIndent, ppszField[dwI], ppszField[dwI+1]);
}


}



// ====================================================================
//
// AddContainer -- adds a container to the container list.
//
// This is only for detecting folders that have already been
// enumerated. Nothing more.
// Trouble is we duplicate!
//
// ====================================================================

void AddContainer( DWORD dwConType )
{
ContainerEntry *pCEntry;
pCEntry = new ContainerEntry;
pCEntry->dwConType = dwConType;

ContainerList.Add((CObject *)pCEntry );
}



// ====================================================================
//
// Enumerated -- Mark this folder as already enumerated within this
// container graph.
//
// ====================================================================

void Enumerated(DWORD dwConType, DWORD folderType)
{
// Locate the container.
BOOL bFound = FALSE;
DWORD dwI; // loop index.
ContainerEntry *pCEntry;

// We keep a global ContainerList (CObArray) which contains
// a list of container entries (above).

// Locate container entry.
// =======================
for (dwI = 0; dwI < (DWORD)ContainerList.GetSize(); dwI++) {
pCEntry = (ContainerEntry *)ContainerList[dwI];
if (pCEntry->dwConType == dwConType) {
bFound = TRUE;
break;
}
}

if (!bFound) {
printf("<<< Error: container tag %d not found in list >>>\n", dwConType);
return;
}

// Add this folder to our list of enumerated folders.
// ==================================================
pCEntry->aEnumFolders.Add( folderType );

}



// ====================================================================
//
// IsEnumerated -- Has this foldertype already been enumerated within
// this container graph?
//
// ====================================================================

BOOL IsEnumerated(DWORD dwConType, DWORD folderType)
{
BOOL bFound = FALSE;
DWORD dwI; // loop index.
ContainerEntry *pCEntry;

// We keep a global ContainerList (CObArray) which contains
// a list of container entries (above).

// Locate container entry.
// =======================
for (dwI = 0; dwI < (DWORD)ContainerList.GetSize(); dwI++) {
pCEntry = (ContainerEntry *)ContainerList[dwI];
if (pCEntry->dwConType == dwConType) {
bFound = TRUE;
break;
}
}

if (!bFound) {
printf("<<< Error: container tag %d not found in list >>>\n", dwConType);
return(FALSE);
}

// Now look through the array of enumerated folders.
// =================================================
for (dwI = 0; dwI < (DWORD)pCEntry->aEnumFolders.GetSize(); dwI++) {
if (pCEntry->aEnumFolders[dwI] == folderType) {

// Found it. Folder already enumerated.
// ------------------------------------
return(TRUE);
}
}

// Folder hasn't been enumerated.
// ------------------------------
return(FALSE);
}





// ====================================================================
// InputString
//
// Prompt the user to input a string and return the string in the
// specified buffer.
//
// Parameters:
// const char* pszMessage
// The user prompt to display.
//
// char* pszResult
// Pointer to the buffer where the user's input will be returned.
//
// Returns;
// The user's input is returned via the given buffer.
//
// ====================================================================
void InputString( const char *pszMessage, char *pszResult)
{
printf("%s: ", pszMessage);
gets(pszResult);
}








// ====================================================================
// DidRequestHelp
//
// Check the program's arguments to see if the user asked for
// the help screen to be displayed.
//
// Parameters:
// int argc
// The argc value from main(argc, argv)
//
// char** argv
// The argv value from main(argc, argv)
//
// Returns:
// TRUE if command line parameters included a request
// for help to be displayed.
//
// ====================================================================
BOOL DidRequestHelp(int argc, char** argv)
{
if (argc == 2 && (strcmp(argv[1], "-help") == 0)) {
return(TRUE);
}
else {
return(FALSE);
}
}


// ====================================================================
// DisplayHelp
//
// This function displays the samples help screen.
//
// Parameters:
// None
//
// Returns:
// Nothing.
//
// ====================================================================
void DisplayHelp()
{
// Version information.
// ====================
char *pVer;
SmsAPIVer( &pVer );
printf("\n%s\n\n", pVer);


// Description.
// ============

printf("********************************************************************\n");
printf("* tree.exe: *\n");
printf("* *\n");
printf("* This is a sample program for the SMS SDK. It shows how the *\n");
printf("* container hierarchy can be displayed. *\n");
printf("* *\n");
printf("* For each container in SMS, the following details are displayed: *\n");
printf("* the container's tag and type *\n");
printf("* any filters that are acted upon directly by the container *\n");
printf("* *\n");
printf("* Following this is a display of all folders within that container.*\n");
printf("* *\n");
printf("* For folders the following is displayed: *\n");
printf("* the folder's type and tag *\n");
printf("* any filters that are acted upon by the folder *\n");
printf("* a list of the folder's scalars *\n");
printf("* Note that folder enumeration is recursive, that is, some folders *\n");
printf("* contain sub-folders. *\n");
printf("* *\n");
printf("* For filters a list of the filter's attributes are displayed. *\n");
printf("* *\n");
printf("* Syntax: *\n");
printf("* tree.exe [-help] *\n");
printf("* *\n");
printf("* Switches: *\n");
printf("* -help Display this help screen. *\n");
printf("* *\n");
printf("********************************************************************\n");
printf("\n");
}



// ====================================================================
// DisplayGreeting
//
// Display the initial greeting banner.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
// ====================================================================
void DisplayGreeting()
{
// For this sample, the greeting is identical to the help screen.
//===============================================================
DisplayHelp();

// Pause so the description doesn't fly off the screen.
// ====================================================
char szReply[CCH_MAXSTRING];
InputString("Press ENTER to continue", szReply);
printf("\n");
}






/* EOF: tree.cpp */