Well that was easy.
I started mid morning to implement the use of the list box that I
created yesterday and played around getting a dialog box to compile. Then decided that a dialog box wasn't
something I wanted to use and returned to what would be necessary to fill in
the empty list box. By 2:15 I had it
filled in with all the files and folders in my starting folder with a vertical
scroll bar replacing the control that had had only boundary lines.
And now, one and half days later it is all working. It seems that I'm beginning to be quite at
home at the online University of Microsoft.
The application detects when a folder/directory versus a
file is highlighted and switches to displaying the files in the new folder when
a folder is selected. Otherwise, it
opens the file as the file to parse. So
this is similar to the OpenFileDialog() that is an available function with the
visual compilers.
I did have some problems.
I wanted to have the list box display in the order found when using the
FindNextFile function but the files were in alpha order even thou LBS_SORT was not specified as a
style and I couldn't find a way to avoid this so I had to give up. The files were not in the order presented by
Windows Explorer for any of the ways to change the order such as by name, by
type, by creation date, etc.
Also, to empty the list box prior to displaying the files of
a newly selected folder, the LB_RESETCONTENT message didn't work. By that I mean didn't work well. The list box just disappeared except
initially a strange vague shape where its top should have been. So I had to delete its contents line by line
and this in reverse from last to first using the LB_DELETESTRING message to the
list box control.
However, when one way wouldn't work I was able to find
another without too much delay.
Jing captures of the window are shown below. First how the window is displayed when the
application is first launched. Then,
after the Select File button has been clicked.
Following that after the needed folder name has been selected and then
after the file to be parsed has been selected.
Finally, how the sequence can be restarted by clicking the Select File
button once again.
Following these graphics the code is presented. The code to report the results, including
the Key and KeyTable classes, is the same as the last post (except for
truncating the initial label to avoid overlapping the list box) as well as the
code to parse the file. The code to
open the file in the StartApp function is the same except for needing the
obtainFilePath() function to obtain the path of the selected file.
The non-visual C++ code that creates the window and its
controls is as follows.
#ifndef KEYTABLECPP
#define KEYTABLECPP
// Key class
class Key
{
public:
Key(); //
constructor
int
key; // value of key
int
valueCount; // number of different values associated with key
static
const int VALUESSIZE = 20; // initial size of values & sums
// arrays for particular key
int
*values; // will point to the array
int
*sums; // "
}; // end class Key
// KeyTable class
class KeyTable //: public Component
{
public:
KeyTable(); // constructor
int
getKey(int index);
int
getKeyCount();
// Return
number of different values for key at index
int
getValueCount(int index);
int
setKey(int key);
int
setValue(int index, int value);
int
getValue(int indexKey, int indexValue);
int
incSum(int indexKey, int indexValue);
int
getSum(int indexKey, int indexValue);
private:
int
keyCount; // number of different keys
static
const int TABLESIZE = 30; // initial size of keys array
Key* keys
= new Key[TABLESIZE]; // instances of
"struct" class
}; // end class KeyTable
#endif // KEYTABLECPP
Key and KeyTable class within KeyTable.cpp
#include <iostream>
#include "keytable.h"
Key::Key() // constructor
{
valueCount
= 0;
key = 0;
values =
new int[VALUESSIZE];
sums = new
int[VALUESSIZE];
for (int i
= 0; i < VALUESSIZE; i++)
{
values[i]
= -1; // so no match until a value added
sums[i] =
0; // so any first increment of the
sum will be to 1
}
} // end Key constructor
KeyTable::KeyTable() // constructor
{
this->keyCount = 0;
} // end KeyTable constructor
// Return key at index
KeyTable::getKey(int index)
{
int
tempKey;
if (index
< KeyTable::keyCount)
{
int key =
KeyTable::keys[index].key;
return
key;
}
else
{
return 0;
}
} // end getKey
// Return number of keys in table
KeyTable::getKeyCount()
{
return
keyCount;
} // end getKeyCount
KeyTable::getValueCount(int index)
{
return
this->keys[index].valueCount;
} // end getValueCount
KeyTable::setKey(int key)
{
for (int i
= 0; i < keyCount; i++)
{
if
(this->keys[i].key == key) // key already in table
{
return
i;
}
} // end
for loop
if
(this->keyCount < TABLESIZE) // add key to table if room
{
this->keys[keyCount].key = key;
int index
= keyCount;
keyCount++;
return
index;
}
else
{
std::cout
<< "Error: Too many different keys" << "\n";
return
-1;
}
} // end setKey
// Add value for key at index, return value index
KeyTable::setValue(int index, int value)
{
for (int i
= 0; i < this->keys[index].valueCount; i++)
{
if (
this->keys[index].values[i] == value )
{
//
Increment sum
this->keys[index].sums[i]++;
return
i;
}
} // end
for loop
// Add
value to array for key since didn't return for existing value
this->keys[index].values[this->keys[index].valueCount] = value;
this->keys[index].sums[this->keys[index].valueCount]++;
int
valueIndex = this->keys[index].valueCount;
this->keys[index].valueCount++; // increment number of values for key
return
valueIndex;
} // end setValue
// Get value for key at indexes, return value
KeyTable::getValue(int indexKey, int indexValue)
{
return
this->keys[indexKey].values[indexValue];
} // end getValue
// Increment Sum for value of key at indexKey and
value at indexValue
KeyTable::incSum(int indexKey, int indexValue)
{
//
Increment sum
int count =
this->keys[indexKey].sums[indexValue]++;
return
count;
} // end incSum
// Get sum for key at indexes, return sum
KeyTable::getSum(int indexKey, int indexValue)
{
return
this->keys[indexKey].sums[indexValue];
} // end getSum
WinMain.cpp
#include <stdio.h>
#include <iostream>
#include <cstring>
#include "windows.h"
#include "wingdi.h"
#include "winuser.h"
#include "afxres.h"
#include <keytable.h>
// Global variables
HINSTANCE hinst;
HWND hMainWnd; // the main window
ATOM mainWindow;
HWND hSelListBoxWnd = 0; // the listbox
int ncmdShow; // from lauch of the application
// Structure to keep track of controls created for
the window
int numberOfControls = 0; // number of controls
created
struct Controls {
std::string
name; // name of control
HWND
handle; // handle of control
};
Controls control[10];
// Structure to keep track of files and folders
loaded into listbox
int listBoxItemsCount = 0; // largest index into the
array
int nameMaxSize = 300;
struct ListBoxItems {
DWORD
fileAttributes; // attributes of the file or folder
CHAR fileName[300]; // name of the file or folder
};
int listBoxItemsMax = 500;
ListBoxItems listBoxItems[500];
int dirListBoxIndex = 0; // index to use to obtain
directory for fileRelocate
std::string startDir; // directory to use for list box
int fileListBoxIndex = 0; // index to use to obtain
filename to be opened
// Other variables used by both the app thread and
the callback thread
BOOL locateFile = FALSE; // activate ListBox to select the file
BOOL relocateFile = FALSE; // clear ListBox to fill
with files of new directory
BOOL fileSelected = FALSE; // file to parse selected
BOOL fileOpenEvent = TRUE; // only run the Parse,
etc once
FILE* selectedFile;
BOOL finished = FALSE; // finished looking at
window, time to exit
// Function prototypes.
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR,
int);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
BOOL fileLocate(); // Find file to be used using listbox
BOOL fileRelocate(); // Find file in new directory using listbox
BOOL emptyTheListBox(); // Empty the listbox
char* obtainFilePath(); // Form the filepath from
selected filename
BOOL StartApp(); // Determine the LearnToCodeGR
results
// Note: MainWndProc runs in a Windows OpSys thread
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM,
LPARAM);
// Application entry point.
int WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
MSG msg; //
message
ncmdShow =
nCmdShow;
// Create
main window and the initial controls
BOOL
result;
result =
InitApplication(hinstance);
if
(!result)
return
FALSE;
if
(!InitInstance(hinstance, nCmdShow))
return
FALSE;
// Main
"forever" loop
BOOL
fGotMessage;
while
((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0))!=0 &&
fGotMessage != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// Set of
possibilities to run in application thread initiated by setting variable
// in
callback thread.
// Fill
listbox using initial directory/folder
if
(locateFile)
{
fileLocate();
}
// Fill
listbox after the selection of a new directory/folder
if
(dirListBoxIndex > 0)
{
fileRelocate();
}
// Parse
selected file and display results
if
((fileSelected) & (fileOpenEvent)) // open selected file
{
fileOpenEvent = FALSE; // dummy indication that can only be used once
//
Start main portion of the application.
result
= StartApp();
}
// Exit
the forever loop to exit the application
if
(finished)
{
break;
// exit while loop
}
} // end
while loop
// Exit the
application
return
msg.wParam;
UNREFERENCED_PARAMETER(lpCmdLine);
} // end WinMain
// To treat Windows events while executing in a
separate thread
LRESULT CALLBACK MainWndProc( HWND hMainWnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam ) // second message parameter
{
PAINTSTRUCT
ps;
HDC hdc;
switch
(uMsg)
{
case
WM_CREATE:
//
Initialize the window.
return
0;
case
WM_PAINT:
{
//
Paint the window's client area.
return
0;
}
case
WM_SIZE:
// Set
the size and position of the window.
return
0;
case
WM_DESTROY:
//
Clean up window-specific data objects.
return
0;
case
WM_DRAWITEM:
{
return
0;
}
case
WM_SETTEXT:
{
return
true;
}
case
WM_INITDIALOG:
{
return 0;
}
//
WM_COMMAND (treat control events)
case
WM_COMMAND:
{
//
Indicate when control event of interest occurs
BOOL
matchedHandle = FALSE;
// Find
if control of interest used
HWND
errorHandle = 0;
for
(int c = 0; c < numberOfControls; c++)
{
if (control[c].handle == (HWND)lParam) // found
the control
{
matchedHandle = TRUE;
std::string name = control[c].name;
if
(name == "Select ListBox") // Select from ListBox clicked
{
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(control[c].handle, LOWORD(wParam));
return TRUE;
}
switch (HIWORD(wParam))
{
case LBN_SELCHANGE: // listbox selection made
{
// Get selected index.
int lbItem = (int)SendMessage(control[c].handle, LB_GETCURSEL, 0, 0);
// Get listbox item data.
int index = (int)SendMessage(control[c].handle, LB_GETITEMDATA,
lbItem, 0);
// Determine if the selected listbox item is a directory/folder
if
((listBoxItems[index].fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
!= 0)
{
dirListBoxIndex = index;
}
else
{
fileListBoxIndex = index;
fileSelected = TRUE; // indicate that file should be opened
}
return TRUE;
}
}
}
else if (name == "Select File") // Select File button clicked
{
locateFile = TRUE; // indicate that
ListBox should be activated
}
// end Select File
if
(name == "Done")
{
finished = TRUE; // set for use by WinMain thread
return TRUE;
}
} // end if control[c].handle
} //
end for loop
if
(matchedHandle)
{
return TRUE;
} else
{
return 0;
}
} // end
case WM_COMMAND
case
WM_NOTIFY:
{
return
TRUE;
}
//
Process other messages.
default:
return
DefWindowProc(hMainWnd, uMsg, wParam, lParam);
}
return 0;
} // end MainWndProc callback
// Register the main window class
BOOL InitApplication(HINSTANCE hinstance)
{
WNDCLASSEX
wcx;
// Fill in
the window class structure with parameters
// that
describe the main window.
wcx.cbSize
= sizeof(wcx); // size of
structure
wcx.style =
CS_HREDRAW | CS_VREDRAW; // redraw
if size changes
wcx.lpfnWndProc = (WNDPROC) MainWndProc; // points to window procedure
wcx.cbClsExtra = 0;
// no extra class memory
wcx.cbWndExtra = 0;
// no extra window memory
wcx.hInstance = hinstance;
// handle to instance
wcx.hIcon =
LoadIcon(NULL, IDI_APPLICATION); //
predefined app. icon
wcx.hCursor
= LoadCursor(NULL, IDC_ARROW); //
predefined arrow
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // white background
brush
wcx.lpszMenuName =
"MainMenu"; // name
of menu resource
wcx.lpszClassName = "MainWClass"; // name of window class
wcx.hIconSm
= (HICON)LoadImage( hinstance, // small class icon
MAKEINTRESOURCE(5),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR );
// Register
the window class.
mainWindow
= RegisterClassEx(&wcx);
DWORD y;
if
(mainWindow==0)
{ y =
GetLastError();
}
// Return
RegisterClassEx(&wcx);
return
(BOOL)mainWindow;
} // end InitApplication
// Create the main window and the initial controls.
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
{
// Save the
application-instance handle.
hinst =
hinstance;
// Create
the main window.
hMainWnd =
CreateWindow
( "MainWClass",
// name of window class
"LearnToCodeGR", //
title-bar string
WS_OVERLAPPEDWINDOW, // top-level window
CW_USEDEFAULT, // default
horizontal position
CW_USEDEFAULT, // default
vertical position
CW_USEDEFAULT, // default
width
CW_USEDEFAULT, // default
height
(HWND) NULL, // no owner
window
(HMENU) NULL, // use class
menu
hinstance, // handle to
application instance
(LPVOID) NULL ); // no
window-creation data
if
(!hMainWnd)
return
FALSE;
if
(hMainWnd!=0)
{
// Create
Select File button control.
HWND
hwndSelButton = CreateWindow
( "BUTTON", // Predefined class; Unicode assumed
"Select File", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD |
BS_DEFPUSHBUTTON, // Styles
10, // x position
10, // y position
100, // Button width
35,
// Button height
hMainWnd, // Parent window
NULL, // no menu
(HINSTANCE)GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // Pointer not
needed.
control[numberOfControls].handle = hwndSelButton; // Capture handle
control[numberOfControls].name = "Select File"; //
and name of the
numberOfControls++; //
button control
// Create
button to use to exit the application.
HWND
hwndDoneButton = CreateWindow
( "BUTTON", // Predefined class; Unicode assumed
"Done", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD |
BS_DEFPUSHBUTTON,
// Styles
10, // x position
310, // y position
100, // Button width
35, // Button height
hMainWnd, // Parent window
NULL, // no menu
(HINSTANCE)GetWindowLong(hMainWnd, GWL_HINSTANCE),
NULL ); // Pointer not needed.
control[numberOfControls].handle = hwndDoneButton; // Capture handle
control[numberOfControls].name = "Done"; //
and name of the
numberOfControls++; // button control
} // end if
for main window created
// Show the
main window and send a WM_PAINT message to the window procedure.
ShowWindow(hMainWnd, nCmdShow);
UpdateWindow(hMainWnd);
return
TRUE;
}
// Find files in directory and display in the
listbox
BOOL findFiles(HWND listBox, std::string startDir)
{
WIN32_FIND_DATA FindFileData;
int size;
size =
startDir.size();
char
*startVal = new char[size+1];
startVal[size] = 0; // trailing null
memcpy(startVal, startDir.c_str(), size);
HANDLE
hFind = FindFirstFile((LPCSTR)startVal, &FindFileData);
int index =
0;
if(hFind ==
INVALID_HANDLE_VALUE)
{
return
false;
}
else do
{
// Add
file name to array and send to listbox
int pos =
(int)SendMessage( listBox, LB_ADDSTRING, 0,
(LPARAM)FindFileData.cFileName );
if (index
< listBoxItemsMax)
{
listBoxItems[index].fileAttributes = FindFileData.dwFileAttributes;
for
(int f = 0; f < nameMaxSize; f++)
{
listBoxItems[index].fileName[f] = FindFileData.cFileName[f];
}
if
(index > listBoxItemsCount)
{
listBoxItemsCount = index;
}
}
// Set
the array index of the file/folder as item data.
// This will
enable it to be retrieved from the array
// even
after the items are sorted by the list box.
SendMessage(listBox, LB_SETITEMDATA, pos, (LPARAM) index);
index++;
} while
(FindNextFile(hFind, &FindFileData));
DWORD
findError = GetLastError();
if
(findError != 18) // not end of file
{
std::string findErrorStr = "FindNextFile Error " +
std::to_string(findError);
std::cout
<< findErrorStr << '\n';
}
if (index
> listBoxItemsCount) // for the last increment
{
listBoxItemsCount = index;
}
FindClose(hFind);
return
true;
} // end findFiles
// Create listbox and fill with Get the selected
file via a List Box
// or empty if already exists.
BOOL fileLocate()
{
if
(hSelListBoxWnd == 0)
{
hSelListBoxWnd = CreateWindow
( "LISTBOX", //
Predefined class; Unicode assumed
"Select File", // Title text
LBS_NOTIFY | WS_VISIBLE | WS_VSCROLL |
WS_BORDER | WS_CHILD,
200, // x position
10, // y position
350, // Box width
400, // Box height
hMainWnd, // Parent window
NULL,
// no menu
(HINSTANCE)GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // Pointer not needed.
control[numberOfControls].handle = hSelListBoxWnd; // Capture handle
control[numberOfControls].name = "Select ListBox"; // and name of the
numberOfControls++; //
button control
}
else
{
emptyTheListBox();
}
// Select
initial directory/folder
startDir =
("C:/Source/*");
// Fill the
listbox with file names in the folder
findFiles(hSelListBoxWnd,startDir);
// Cause
the controls to be displayed in the main window
UpdateWindow(hMainWnd);
locateFile
= FALSE; // don't repeat call to this routine from forever loop
} // end fileLocate
// Empty the listbox and redisplay
BOOL emptyTheListBox()
{
for (int i
= 0; i < listBoxItemsCount; i++)
{
int j =
listBoxItemsCount - 1 - i;
SendMessage(hSelListBoxWnd, LB_DELETESTRING, j, 0);
}
UpdateWindow(hSelListBoxWnd); // cause the list box to be redisplayed
} // end emptyTheListBox
// Clear the ListBox and then add files of new
selected directory
BOOL fileRelocate()
{
// Save
selected directory name
CHAR
directoryName[nameMaxSize];
memcpy(directoryName,listBoxItems[dirListBoxIndex].fileName,nameMaxSize);
emptyTheListBox();
dirListBoxIndex = 0; // prepare for next selection
listBoxItemsCount = 0; // empty listBoxItems array
int last =
startDir.length();
std::string
slash = "/";
startDir.insert(last-1,slash);
// add extra / before *
startDir.insert(last-1,directoryName); // insert new directory before
last /
findFiles(hSelListBoxWnd,startDir); // load list box from selected
folder
UpdateWindow(hSelListBoxWnd); // cause the list box to be redisplayed
return FALSE; // don't repeat call to this
routine until new folder selected
} // end fileRelocate
// File path to be returned via obtainFilePath
// Declared as static to avoid being on stack when
returned
char filePath[64];
// Obtain file path by combining directory and file
name
char* obtainFilePath()
{
int last =
startDir.length();
memcpy(filePath,startDir.c_str(),last-1); // start with directory
for (int i
= 0; i < 64; i++) // append selected file to directory
{
filePath[last-1+i] = listBoxItems[fileListBoxIndex].fileName[i];
if
(listBoxItems[fileListBoxIndex].fileName[i] == 0)
{
break;
// exit the loop after trailing null added to filePath
}
}
return
filePath;
} // end obtainFilePath
/*
* From here
to the end is the C++ code for the LearnToCodeGR application.
* This code
runs in the WinMain application thread.
*/
KeyTable keyTable; // Instance of KeyTable class
object
// Report the key and value with the most references
void Report()
{
// Report
individual results to the console.
printf("\n");
printf("Report ");
printf("\n");
for (int i
= 0; i < keyTable.getKeyCount(); i++)
{
for (int
j = 0; j < keyTable.getValueCount(i); j++)
{
std::string report = ("Key ");
report
= report + std::to_string(keyTable.getKey(i));
report
= report + (" Value ");
report
= report + std::to_string(keyTable.getValue(i,j));
report
= report + (" Sum ");
report
= report + std::to_string(keyTable.getSum(i,j));
std::cout << report << '\n';
} // end
for loop
} // end
for loop
// Items
identifying the key with the largest number of a particular value.
int key =
0;
int value =
0;
int sum =
0;
for (int i
= 0; i < keyTable.getKeyCount(); i++)
{
for (int
j = 0; j < keyTable.getValueCount(i); j++)
{
if
(keyTable.getSum(i,j) > sum) // save key and value with greater sum
{
key =
keyTable.getKey(i);
value
= keyTable.getValue(i,j);
sum =
keyTable.getSum(i,j);
}
} // end
for loop
} // end
for loop
// Report
the key and value with the greatest number of references to the console.
printf("\n");
std::string
report = ("Key and Value with greatest Sum ");
report =
report + std::to_string(key) + " ";
report =
report + std::to_string(value) + " ";
report =
report + std::to_string(sum);
std::cout
<< report << '\n';
// Create
and report the results to window controls.
// Convert
int's to char arrays.
std::string
keyStr = std::to_string(key);
int size;
size =
keyStr.size();
char
*keyVal = new char[size+1];
keyVal[size] = 0;
memcpy(keyVal, keyStr.c_str(), size);
std::string
valueStr = std::to_string(value);
size =
valueStr.size();
char
*valueVal = new char[size+1];
valueVal[size] = 0;
memcpy(valueVal, valueStr.c_str(), size);
std::string
sumStr = std::to_string(sum);
size =
sumStr.size();
char
*sumVal = new char[size+1];
sumVal[size] = 0;
memcpy(sumVal, sumStr.c_str(), size);
HWND
hResultsWnd1 = CreateWindow
( "EDIT", // predefined class
"Key and Value with", // label
text
WS_CHILD | WS_VISIBLE | ES_LEFT, // Styles
10, 125, 150, 20, // set size and location
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // pointer not needed
HWND
hResultsWnd2 = CreateWindow
( "EDIT", // predefined class
" greatest Sum", // label text
WS_CHILD | WS_VISIBLE | ES_LEFT, // Styles
10, 150, 150, 20, // set size and location
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL );
// pointer not needed
HWND
hKeyLabelWnd = CreateWindow
( "EDIT", // predefined class
"Key ", // label text
WS_CHILD | WS_VISIBLE | ES_LEFT, // Styles
10, 180, 60, 20, // set size
and location
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // pointer not needed
HWND
hKeyValueWnd = CreateWindow
( "EDIT", // predefined class
(LPCTSTR)keyVal, // result for key
WS_CHILD | WS_VISIBLE | ES_LEFT |
WS_BORDER,
60, 178, 60, 30, // set size in WM_SIZE
message
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // pointer not needed
HWND
hValLabelWnd = CreateWindow
( "EDIT", // predefined class
"Value", // label text
WS_CHILD | WS_VISIBLE |
ES_LEFT, // Styles
10, 220, 60, 20, // set size and location
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE)
GetWindowLong(hMainWnd, GWL_HINSTANCE),
NULL ); // pointer not needed
HWND
hValValueWnd = CreateWindow
( "EDIT", // predefined class
(LPCTSTR)valueVal,// result for key
WS_CHILD | WS_VISIBLE | ES_LEFT |
WS_BORDER,
60, 218, 60, 30, // set size in WM_SIZE message
hMainWnd, // parent window
NULL, // edit
control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // pointer not needed
HWND
hSumLabelWnd = CreateWindow
( "EDIT", // predefined class
"Sum ", // label text
WS_CHILD | WS_VISIBLE | ES_LEFT, // Styles
10, 260, 60, 20, // set size and location
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // pointer not needed
HWND
hSumValueWnd = CreateWindow
( "EDIT", // predefined class
(LPCTSTR)sumVal, // result for key
WS_CHILD | WS_VISIBLE | ES_LEFT |
WS_BORDER,
60, 258, 60, 30, // set size in WM_SIZE
message
hMainWnd, // parent window
NULL, // edit control ID
(HINSTANCE) GetWindowLong(hMainWnd,
GWL_HINSTANCE),
NULL ); // pointer not needed
UpdateWindow(hMainWnd);
// cause the controls to be displayed in the main window
return;
} // end Report
// Update keyTable with data from a parsed line
void Update(int nKey, int nValue1, int nValue2)
{
// This
function first checks if the key is new and, if so, adds it to the
// keys
array. It then does similar for the
values associated with it.
// Check
whether the key is already in the table
int
keyIndex = -1;
int
valueIndex = -1;
int
keyCount = keyTable.getKeyCount();
for (int i
= 0; i < keyCount; i++)
{
if
(keyTable.getKey(i) == nKey)
{
keyIndex = i; // key already in
table
break;
// exit loop
}
} // end
loop
if
(keyIndex < 0) // key not in the table
{
keyIndex
= keyTable.setKey(nKey); // add key
valueIndex =
keyTable.setValue(keyIndex,nValue1); // add value for key
if
(nValue1 != nValue2)
{
keyTable.setValue(keyIndex,nValue2); }
else
{
keyTable.incSum(keyIndex,valueIndex); }
}
else // key
in the table
{
int
valueCount = keyTable.getValueCount(keyIndex);
valueIndex = keyTable.setValue(keyIndex,nValue1); // add value for key
if
(nValue1 != nValue2)
{
keyTable.setValue(keyIndex,nValue2); }
else
{
keyTable.incSum(keyIndex,valueIndex); }
}
return;
} // end Update
#define NINE 57 // ASCII character for digit 9
#define ZERO 48 // ASCII character for digit 0
// Convert character array to int
int toInt(char* data, int length) //iS, int iE)
{
int index =
length - 1; // loop in reverse
int digit;
int m =
1; // multiplier for shift
int number
= 0; // Numeric result
while
(index >= 0) //iS)
{
digit =
data[index] - ZERO; // convert ASCII to digit
number =
number + (m * digit);
m = m *
10;
index--;
}
return
number;
} // end toInt
enum Scan //Fields
{ BYPASS, FKEY, VALUE1, VALUE2 };
// Extract the fields of interest from the file's
line and retain the data
void Parse(int count, char* data)
{
#define CR
'\r' // carriage return
#define HT
'\t' // horizontal tab
#define LF
'\n' // line feed
#define
TRUE 1
// Parse
the supplied line of data from the file to obtain the three
// fields
of interest (key and two values), convert those fields to
//
integers, and then update a data structure (the KeyTable class) to
// retain the data for evaluation when the
complete file has been parsed.
int
keyValue = 0;
int
value1Value = 0;
int
value2Value = 0;
char
alphaDigits [10];
int
numDigits = 0;
bool
updateDone = false;
int offset
= 0; // offset into data
Scan
scanPhase = BYPASS;
// Parse
all bytes of record previously read from the file. Each field of
// interest
is preceded by a horizontal tab. The
end of the final field
// is
marked by a CR LF or only a LF (NL) except the last record where
// there
are no more characters to be treated.
while
(offset < count)
{
switch
(scanPhase)
{
case
BYPASS:
if
(data[offset] == HT)
{
scanPhase = FKEY;
keyValue = 0;
value1Value = 0;
value2Value
= 0;
numDigits = 0;
}
break;
case
FKEY:
if
(data[offset] != HT)
{
if
((data[offset] >= ZERO) & (data[offset] <= NINE))
{
alphaDigits[numDigits] = data[offset];
numDigits++;
}
}
else
{
keyValue = toInt(alphaDigits, numDigits);
scanPhase = VALUE1;
numDigits = 0;
}
break;
case
VALUE1:
if
(data[offset] != HT)
{
if
((data[offset] >= ZERO) & (data[offset] <= NINE))
{
alphaDigits[numDigits] = data[offset];
numDigits++;
}
}
else
{
value1Value = toInt(alphaDigits, numDigits);
scanPhase = VALUE2;
numDigits = 0;
}
break;
case
VALUE2:
if
((data[offset] == LF) | (data[offset] == CR) | offset+1 >= count)
{
value2Value = toInt(alphaDigits, numDigits);
//
Update tables with the data from the record.
Update( keyValue, value1Value, value2Value );
updateDone = true;
//
Initialize for next record
keyValue = 0;
value1Value = 0;
value2Value = 0;
numDigits
= 0;
scanPhase = BYPASS;
}
else
{
if
((data[offset] >= ZERO) & (data[offset] <= NINE))
{
alphaDigits[numDigits] = data[offset];
numDigits++;
}
}
break;
} // end
switch
//
Complete processing of final record when not terminated by New Line
offset++;
// increment to next data buffer position
if
(offset >= count) // no more data
{
if
(value2Value > 0) // last record fully parsed without trailing NL
{
if
(!updateDone)
{
value2Value = toInt(alphaDigits, numDigits);
Update( keyValue, value1Value, value2Value );
updateDone = true;
}
}
break;
// exit loop
}
} // end
loop
return;
} // end Parse
BOOL StartApp()
// Treat the opened the LearnToCodeGR file.
{
char*
filePath;
filePath =
obtainFilePath();
FILE* file;
char
buffer[30];
file =
fopen(filePath, "r");
int
currPos;
int lastPos
= 0;
int length;
if(file ==
NULL)
{
perror("Error opening file");
return
FALSE;
}
else
{ // Read
file records until end-of-file
// Read
each record/line of the file and Parse it.
while
(!feof(file))
{
fgets(buffer, 30, (FILE*)file);
currPos
= ftell(file);
length
= currPos - lastPos; // number of characters read into buffer
lastPos
= currPos;
for
(int i=0; i < length; i++) // output the
printf("%c ", buffer[i]);
// record to
printf("\n"); // the console
//
Parse the line and update to retain all the necessary data.
Parse(length, buffer);
}
// Close
the selected file.
fclose(file);
// Report
the results.
Report();
}
return
TRUE;
} // end StartApp
No comments:
Post a Comment