///////////////////////////////////////////////////////////////
// Module:DemoTest.c
//
// Purpose:Simple test program to illustrate use of the demographic library interface.
//
// These coded instructions, statements, and computer programs contain unpublished trade secrets and proprietary
// information of Precisely and are protected by Federal Copyright law and by Trade Secret law.
// They may not be disclosed to third parties or used or copied or duplicated in any form, in whole or in part,
// without the prior written consent of Precisely.
///////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dl.h"
static long password;
static char initPaths[256], licenseFile[256];
#define FILE_HANDLES 3 // How many demographics files can be open at once
#define LINES_PER_PAGE 24 // How many lines to scroll at a time
/*
** Function: ShowError
**
** Purpose: Prints the message and detail of the last error that occured, or "No Error." if none have occured.
*/
void ShowError(DlId dl)
{
char msg[256], detail[256];
if ( DlErrorGet(dl, msg, detail) ) // DlErrorGet returns zero if there is NOT an error
{
printf("\nDlErrorGet:\n");
printf("Msg: %s\n", msg);
printf("Detail: %s\n\n", detail);
}
else
{
printf("\nNo Error.\n\n");
}
}
/*
** Function: PickHandle
**
** Purpose: DemoTest has several file handles, so that more than one .DLD file can be open at once. The exact
number is specified by FILE_HANDLES. This function lets the user choose which of these to use.
*/
void PickHandle(int *pCurrentFile)
{
char buffer[10];
int iTemp;
printf("\nChoose a file number between 1 and %d.\n", FILE_HANDLES);
// Handles are zero based, so add one
printf("Current file handle is %d.\n", *pCurrentFile + 1);
gets(buffer);
if ( *buffer )// If user simply hits return, return to menu
{
iTemp = atoi(buffer) - 1;// Subtract 1 because handles are zero-based
// Make sure that the number is a valid choice
if (iTemp >= 0 && iTemp < FILE_HANDLES)
{
*pCurrentFile = iTemp;
}
else
{
printf("Handle must be between 1 and %d.\n", FILE_HANDLES);
}
}
printf("\n");
}
/*
** Function: Close
**
** Purpose: Close an open .DLD file.
*/
void Close(DlId dl, DlFileId *pId)
{
if (!(*pId))// File Id's are kept equal to zero, if not open in this program.
{
printf("\nNo file open.\n");
}
else
{
if (!DlFileClose(*pId))// DlFileClose returns zero if it failed
{
printf("\nError closing file.\n");
ShowError(dl);
}
else
{
*pId = 0;// If a file id is zero we know it is NOT open.
printf("\nClosed.\n");
}
}
printf("\n");
}
/*
** Function: Open
**
** Purpose: Open a .DLD file. If a file is currently open, it is closed.
*/
void Open(DlId dl, DlFileId *pId)
{
char buffer[256];
if (*pId)// First make sure no file is open
{
if (!DlFileClose(*pId))// If it is, then close it
{
printf("\nError closing file.\n");
ShowError(dl);
return;
}
}
printf("\nEnter the path and filename of the demographics file.\n");
gets(buffer);
if (*buffer)// If the user simply hits return, return to menu.
{
*pId = DlFileOpen(dl, buffer);
if (!(*pId))// DlFileOpen returns zero if it failed
{
printf("Unable to open specified file.\n");
ShowError(dl);
}
}
printf("\n");
}
/*
** Function: ShowFileAttributes
**
** Purpose: Shows attributes about the currently open file.
** These are returned from DlFileGetAttribute, and are such things as the number of fields, the key type,
** the key field name, etc.
*/
void ShowFileAttributes(DlFileId id)
{
char buffer[256];
intl lRetVal, lNumFields;
if (!id)// First make sure a .DLD file is open
{
printf("\nNo file open.\n");
}
else
{
printf("\nFILE ATTRIBUTES:\n");
// Retrieve the key field name - the key field is the one you search by
DlFileGetAttribute(id, DlKeyFieldName, buffer, sizeof(buffer));
printf("Name of key field: %s\n", buffer);
// Retrieve the type of value the key field is
lRetVal = DlFileGetAttribute(id, DlKeyType, buffer, sizeof(buffer));
printf("Numeric type of key: ");
// To check if a value (bit) is set in lRetVal, the binary & operator is used.
if (lRetVal & DL_TYPE_ZIP)
printf("ZIP Code\n");
else if (lRetVal & DL_TYPE_ZIP4)
printf("ZIP+4 Code\n");
else if (lRetVal & DL_TYPE_CTY)
printf("County\n");
else if (lRetVal & DL_TYPE_CT)
printf("Census tract\n");
else if (lRetVal & DL_TYPE_BG)
printf("Block group\n");
else if (lRetVal & DL_TYPE_BLK)
printf("Block\n");
// Retrieve the number of fields in the file.
lRetVal = DlFileGetAttribute(id, DlNumFields, buffer, sizeof(buffer));
lNumFields = DlFileNumFields(id);
if (lRetVal == lNumFields) // Quick test to verify both functions return the same value
printf("Number of fields: %d\n", lRetVal);
else
{
printf("\nERROR\n");
printf("DlFileGetAttribute returned %d fields in file.\n", lRetVal);
printf("DlFileNumFields returned %d fields in file.\n\n", lNumFields);
}
// Retrieve the maximum number of values per field
lRetVal = DlFileGetAttribute(id, DlNumValues, buffer, sizeof(buffer));
printf("Max Values per field: %d\n", lRetVal);
// Retrieve the key limit - if it is 1, then the key is limited to alphanumeric characters.
DlFileGetAttribute(id, DlKeyLimit, buffer, sizeof(buffer));
printf("Limited to alphanumeric?: %s\n", ( (lRetVal == 1)? "TRUE": "FALSE") );
// Retrieve a description of the file.
DlFileGetAttribute(id, DlFileDescription, buffer, sizeof(buffer));
printf("Description of file: %s\n", buffer);
}
printf("\n");
}
/*
** Function: Search
**
** Purpose: To search the current .DLD file for a key, specified by the user. Remember that the key field
** type can be displayed from Attributes in the file menu (ShowFileAttributes).
*/
void Search(DlFileId id)
{
char buffer[256];
printf("\nEnter the key you wish to search for.\n");
gets(buffer);
if ( DlFileSearch(id, buffer) )// DlFileSearch returns a non- zero value for success.
{
printf("Found\n");
}
else
{
printf("Not Found\n");
}
printf("\n");
}
/*
** Function: ListFields
**
** Purpose: This function determines how many fields there are, and then loops through all of them, outputting
** their names.
*/
void ListFields(DlId dl, DlFileId idFile)
{
intl lNumFields, lCount;
// Number of fields in the file, and a counter for the loop ID that will be used to retrieve DlFieldId idField;
// each field name
char buffer[256];
//Here we get the number of fields
lNumFields = DlFileNumFields(idFile);
if (lNumFields < 1)
{
//Error if the return was invalid
printf("\nDlFileNumFields returned less than 1.\n");
ShowError(dl);
}
else
{
printf("\n");
// Now loop through all the fields (zero based)
for (lCount = 0; lCount < lNumFields; lCount++)
{
// Set idField to the current field number
idField = DlFieldGetN(idFile, lCount);
// Make sure it was set, print an error if not
if (!idField)
{
printf("DlFieldGetN failed to retrieve field number %d.\n", lCount);
ShowError(dl);
break;
}
// Get the field name and print it
DlFieldGetAttribute(idField, DlName, buffer,
sizeof(buffer));
printf("%d: %s\n", lCount, buffer);
// If LINES_PER_PAGE lines have been printed
if (!((lCount + 1) % LINES_PER_PAGE))
{ // Pause until return is pressed so the user can read what was output.
printf("<more>");
gets(buffer);
}
}
}
printf("\n");
}
/*
** Function: ChooseField
**
** Purpose: To retrieve data, a successful file search on a key value must have been done, and a field
** must be specified. This function specifies the field by name or number.
*/
void ChooseField(DlFileId idFile, DlFieldId *idField)
{
intl lFieldNum; // Used when a user chooses by number
intl lNumFields; // Used to show a user the valid range when choosing by number
char choice[10]; // Choice - to choose by name or number
char buffer[256]; // Used when a user chooses by name
printf("\nChoose by number? (Y or N for name): ");
gets(choice);
if (*choice)// If the user simply hit return, return to menu.
{
if (*choice == 'Y' || *choice== 'y')// Check for upper & lower case...
{
lNumFields = DlFileNumFields(idFile);
printf("Enter the field number (between 0 and %d): ", lNumFields - 1);
gets(buffer);
lFieldNum = atol(buffer);//Convert to a number
// DlFieldGetN retrieves a field by number
*idField = DlFieldGetN(idFile, lFieldNum);
}
else if (*choice == 'N' || *choice== 'n')// Check for upper & lower case.
{
printf("Enter the field name: ");
gets(buffer);
*idField = DlFieldGet(idFile, buffer);// DlFieldGet retrieves a field name.
}
else
printf("Invalid entry.\n");
if (!*idField)// Check to see if the field was found
{
printf("Field not found.\n");
}
}
printf("\n");
}
/*
** Function: ShowFieldAttributes
**
** Purpose: Shows attribute information on the currently selected field. Some of these include
** field name, width, type (character or numeric),etc.
*/
void ShowFieldAttributes(DlFieldId idField)
{
char buffer[256];
intl lRetVal;
// Make sure there is a field selected
if (!idField)
{
printf("\nNo field specified.\n");
}
else
{
printf("\nFIELD ATTRIBUTES:\n");
// Retrieve the name
DlFieldGetAttribute(idField, DlName, buffer, sizeof(buffer));
printf("Field Name: %s\n", buffer);
// Retrieve the name as seen in the .DLD file
DlFieldGetAttribute(idField, DlFieldname, buffer, sizeof(buffer));
printf("Name in .DLD file: %s\n", buffer);
// Retrieve the field width. Notice that numeric values are retrieved by return value, rather than through buffer
lRetVal = DlFieldGetAttribute(idField, DlWidth, buffer, sizeof(buffer));
printf("Field Width: %d\n", lRetVal);
// Retrieve the field type.
lRetVal = DlFieldGetAttribute(idField, DlType, buffer, sizeof(buffer));
if (lRetVal == 'C')
{
printf("Field Type: Character\n");
}
else if (lRetVal == 'N')
{
printf("Field Type: Numeric\n");
// If the field is numeric, then retrieve the number of decimal places. All numbers come back without
// decimals, and this value can be used to display them correctly
lRetVal = DlFieldGetAttribute(idField, DlDecimals, buffer, sizeof(buffer));
printf("Decimal Places: %d\n", lRetVal);
}
// Retrieve the number of possible unique values for this field
// This value is used with DlFieldGetValueAttribute
lRetVal = DlFieldGetAttribute(idField, DlNumvalues,
buffer, sizeof(buffer));
printf("Number of possible values: %d\n", lRetVal);
// Retrieve a short description of the field
DlFieldGetAttribute(idField, DlDescription, buffer, sizeof(buffer));
printf("Short Description of file: %s\n", buffer);
// Retrieve a long description of the field
DlFieldGetAttribute(idField, DlHelp, buffer, sizeof(buffer));
printf("Long Description of file: %s\n", buffer);
}
printf("\n");
}
/*
** Function: ShowFieldValueAttributes
**
** Purpose: Show attributes for unique values in current field. The number of unique values is retrieved by
** DlFieldGetAttribue, and the attributes for these values are retrieved by DlFieldGetValueAttribute.
*/
void ShowFieldValueAttributes(DlFieldId idField)
{
intl lNumValues, lCount;
// Number of unique values in field, and a counter for the loop.
char buffer[256];
if (!idField)// Make sure a field is selected
{
printf("\nNo field specified.\n");
}
else
{
printf("\n");
// First get the number of unique values
lNumValues = DlFieldGetAttribute(idField, DlNumvalues,
buffer, sizeof(buffer));
// If it returns zero, there are no unique values, and thus no descriptions
if(!lNumValues)
{
printf("No value descriptions for this field.\n");
}
// DlFieldGetValueAttribute accepts a number which serves as an index to retrieve a description.
// Remember that this index is zero based.
for (lCount = 0; lCount < lNumValues; lCount++)
{
// Retrieve the unique value, notify user if unsuccessful
if ( DlFieldGetValueAttribute(idField, lCount, DlKey, buffer, sizeof(buffer)) )
printf("DlKey: %s\n", buffer);
else
printf("DlKey: <valnum %d unsuccessful>\n", lCount);
// Retrieve the short description for this unique value
if ( DlFieldGetValueAttribute(idField, lCount, DlValDescription, buffer, sizeof(buffer)) )
printf(" DlValDescription: %s\n", buffer);
else
printf(" DlValDescription: <unsuccessful>\n");
// Retrieve the long description for this unique value
if ( DlFieldGetValueAttribute(idField, lCount, DlValHelp, buffer, sizeof(buffer)) )
printf(" DlValHelp: %s\n", buffer);
else
printf(" DlValHelp: <unsuccessful>\n");
// We'll assume that each value is 4 lines, just to make sure nothing scrolls off the top of the screen
// before the user can read it. Waits for return to be pressed to continue.
if (!( ((lCount + 1) * 4 ) % LINES_PER_PAGE))
{
printf("<more>");
gets(buffer);
}
}
}
printf("\n");
}
/*
** Function: PrintData
**
** Purpose: To output the data specified after a successful search has been completed, and a file
** has been successfully specified. This checks if a field is specified, but whether a search has been
** completed is tracked internally by DemoLib.
*/
void PrintData(DlId dl, DlFieldId idField)
{
char buffer[256];
intl lRetVal;
// Make sure a field is selected
if (!idField)
{
printf("\nNo field specified.\n");
}
else
{
printf("\n");
// First determine what type of value will be retrieved, by using DlFieldGetAttribute
lRetVal = DlFieldGetAttribute(idField, DlType, buffer, sizeof(buffer));
// If it's a character, then the value will be retrieved from DlFieldGetString
if (lRetVal == 'C')
{
printf("Value is character; results will be shown from DlFieldGetString.\n");
// DlFieldGetString returns zero if it failed.
if (!(DlFieldGetString(idField, "DlFieldGetString printf string: %s\n", buffer, sizeof(buffer))) )
{
printf("No data returned from DlFieldGetString.\n");
ShowError(dl);
}
printf(buffer);
}
// If it's numeric, the value will be retrieved from DlFieldGetString and DlFieldGetNum.
else if (lRetVal == 'N')
{
printf("Value is numeric; results will be shown from DlFieldGetString and DlFieldGetNum.\n");
printf("Decimal places are not shown.\n");
lRetVal = DlFieldGetNum(idField);
printf("DlFieldGetNum value: %d\n", lRetVal);
// DlFieldGetString returns zero if it failed
if (!(DlFieldGetString(idField, "DlFieldGetString
printf string: %d\n", buffer, sizeof(buffer))) )
{
printf("No data returned from DlFieldGetString.\n");
ShowError(dl);
}
printf(buffer);
}
// The short description (SDESC) and long description (LDESC) are always retrieved
if (!(DlFieldGetString(idField, "SDESC", buffer, sizeof(buffer))) )
{
printf("No short description returned from DlFieldGetString.\n");
}
else
{
printf("DlFieldGetString SDESC: %s\n", buffer);
}
if (!(DlFieldGetString(idField, "LDESC", buffer, sizeof(buffer))) )
{
printf("No long description returned from DlFieldGetString.\n");
}
else
{
printf("DlFieldGetString LDESC: %s\n", buffer);
}
}
printf("\n");
}
/*
** Function: ReadIniFile
**
** Purpose: Reads in a file name "demotest.ini" in the working directory,which contains the license file name,
** password, and the path for DlInit, so the user doesn't have to enter it every time they run the program.
*/
void ReadIniFile()
{
char pass[10];
char * p;
FILE * setup = fopen( "demotest.ini", "rt" );
if ( setup )
{
fgets( licenseFile, sizeof(licenseFile), setup );
p = strchr( licenseFile, '\n' );
if ( p ) *p = 0;
fgets( pass, sizeof(pass), setup );
p = strchr( pass, '\n' );
if ( p ) *p = 0;
password = atol(pass);
// If this entry is not in the file, initPaths will simply be empty ("") which is what we want
fgets( initPaths, sizeof(initPaths), setup );
p = strchr( initPaths, '\n' );
if ( p ) *p = 0;
fclose( setup );
}
else
{
// If there is no ini file, and no command line parameters, just make everything empty, strings or zero.
*licenseFile = 0;
password = 0;
*initPaths = 0;
}
}
/*
** Function: FieldMenu
**
** Purpose: This is the second menu that is presented after a file has successfully been opened.
*/
void FieldMenu(DlId dl, DlFileId idFile)
{
int iDone;
DlFieldId idField;
if (idFile)
{
idField = 0;
for (iDone = 0 ; !iDone ; )
{
char choice[10];
printf( "Search File, List Fields, Choose Field, Attributes, Value Attributes,\n" "Print Data,
Error, File Menu (S/L/C/A/V/P/E/F):" );
gets( choice );
switch (*choice)
{
case 'S':
case 's':
Search(idFile);
break;
case 'L':
case 'l':
ListFields(dl, idFile);
break;
case 'C':
case 'c':
// This accepts a pointer to a DlFieldId, so it can change its value
ChooseField(idFile, &idField);
break;
case 'A':
case 'a':
ShowFieldAttributes(idField);
break;
case 'V':
case 'v':
ShowFieldValueAttributes(idField);
break;
case 'P':
case 'p':
PrintData(dl, idField);
break;
case 'E':
case 'e':
ShowError(dl);
break;
case 'F':
case 'f':
iDone = 1;
break;
default:
// If the user enters an invalid choice, request a valid one
printf( "Please enter S, L, C, A, V, P, E, or F.\n" );
}
}
}
else
{
printf("\nNo file open.\n\n");
}
}
/*
** Function: main
**
** Purpose: This gets all initilization data, either from the user or from the ini file, and
** initialized the demographics library.
*/
void main( int argc, char ** argv )
{
DlId dl;// Handle to demographics library
DlFileId dlFiles[FILE_HANDLES];// Array of demographics file handles
int iCurrentFile;// Current index into handle array
int iCount, iDone;// Counter for loop, and value to check if loop is done
char pass[16]; // Password from user
printf( "Starting...\n" );
// If user didn't enter at least a license file and password, read the ini file
if ( argc < 3 )
{
ReadIniFile();
if ( password == 0 )// There was no ini file, so get info from user
{
printf("Enter license file path and name: ");
gets( licenseFile );
if ( *licenseFile )
{
printf("Enter the 8 digit password: ");
password = atol(pass);
printf("Enter the search path for DlInit: ");
gets(initPaths);
}
}
}
// Otherwise the user did enter license file and password
else
{
strcpy( licenseFile, argv[1] );
password= atol(argv[2]);
// If there are more arguments, then take it as the search path for DlInit
if (argc > 3)
strcpy( initPaths, argv[3]);
else
*initPaths = 0;
}
// Initialize demographics library
dl = DlInit(initPaths);
// And check to make sure it was successful
if ( !dl )
{
printf( "Unable to initialize demographics library.\n" );
}
else
{
#if defined( _WINDOWS )
_wsetexit( _WINEXITNOPERSIST );
#endif
// Set the license file and password. This is not needed to use Census90.dld
if ( !(DlSetLicense(dl, licenseFile, password)) )
printf("License file could not be opened.\nOnly\CENSUS90.DLD will be accessible.\n");
// Set all file handles to zero to indicate no file is open
for (iCount = 0; iCount < FILE_HANDLES; iCount++)
{
dlFiles[iCount] = 0;
}
// The current file handle (in the array) is the first one (zero)
iCurrentFile = 0;
// Loop until user chooses to quit, at which point iDone will be set to zero
for (iDone = 0 ; !iDone ; )
{
char choice[10];
printf( "Pick Handle, Open, Close, Attributes, Field Menu, Error, Quit(P/O/C/A/F/E/Q): " );
gets( choice );
switch (*choice)
{
case 'P':
case 'p':
// Accepts a pointer so it can alter the value
PickHandle(&iCurrentFile);
break;
case 'O':
case 'o':
// Sending a pointer to the file handle specified by iCurrentFile
Open(dl, &(dlFiles[iCurrentFile]));
break;
case 'C':
case 'c':
// Sending a pointer to the file handle specified by iCurrentFile
Close(dl, &(dlFiles[iCurrentFile]));
break;
case 'A':
case 'a':
ShowFileAttributes(dlFiles[iCurrentFile]);
break;
case 'F':
case 'f':
FieldMenu(dl, dlFiles[iCurrentFile]);
break;
case 'E':
case 'e':
ShowError(dl);
break;
case 'Q':
case 'q':
iDone = 1;
break;
default:
// If the user enters an invalid choice, request a valid one.
printf( "Please enter P, O, C, A, F, E, or Q.\n" );
}
}
}
// Close all file handles
printf("\nClosing files...\n");
for (iCount = 0; iCount < FILE_HANDLES; iCount++)
{
printf("Handle %d:", iCount + 1);
Close(dl, &(dlFiles[iCount]));
}
// Free all memory and resources allocated by DlInit
DlTerm( dl );
}