The Power of Visual C++ - Case Study I

The Story

Background

I have a friend who is a writer and a poet and he wanted to post on the web some of his writings. He tried saving his Microsoft Word files (.doc) as web pages but the conversion from .doc to .htm files done by Microsoft Word is so cumbersome and introduces so much excessive formatting commands that the pages were not not displayed properly and some times were not even displayed at all. I suggested to him to save the .doc files as plain text (.txt) and then introduce manually (using Notepad) the few necessary formatting commands: a <p> at the beginning of a line (.txt maps .doc paragraphs to single lines) with the exception of the first line which should be bracketed by <h5> and </h5>. In addition a <div> tag was needed at the start and </div> tag at the end to facilitate incorporation of the document into the web page builder he was using. While the manual insertion of tags was not particularly onerous it was a routine task that could be easily automated.

Solutions

The automation of the task is straightforward using AWK (or Perl), both popular tools in the Unix world. Let the file script contain the lines

BEGIN { print "<div>", "<h5>";}
{if(NR==1) { print $0, "</h5>"; continue;}}
{ print "<p>", $0; }
END { print "</div>"; }
Then a command such as
	  awk -f script storyA.txt > storyA.htm

will do the job.

However, I was not sure whether my friend's computer supported AWK or whether he would fill comfortable with typing commands. (Remember, he is a poet, not a computer technologist.) So I wrote an application in Visual C++ that automates the task and it does not require command typing. It appears as a small popup window with three buttons, as shown below

Clicking on the "Get File" button pops up a file dialogue window displaying only .txt files in the current directory and the user can select one of them by clicking on its name. Then the file is converted into a .htm file and a sounds tells the user the operation is completed. This not only saves the user from typing but also from mistakes because the program warns the user if a file is about to be overwritten.

On the negative side this programs requires a lot more code than the four line AWK script. However, most of the code is generated automatically! The only code the programmer has to provide is for the callbacks of the "Get File" and "Help" buttons listed below. It may still seem as too much code (about 30 lines for the "Get File" callback and 10 for the "Help" callback) but this is missleading. I have color-code the listings below. There are a few orange lines marking the automatically generated code. The green lines of code provide features that do not exist in the AWK version but which make the program much more user-friendly. In addition the lines in the first callback consist of pretty standard code that I copied (with slight modifications) from another program.

The remaining lines are still twice as many as those in the AWK program because they include the code for opening and closing the input and output files, again fairly standard code. So the "significant" programming effort (the lines shown in bold) is the same in both cases! If we would like to add more tags, that is the only part of the code that will have to be modified.

The Moral

It is important to provide users with applications that do not require a lot of typing, as well as make it easy for programmers to write such applications. (It took me less than an hour to write this particular program.) See a full discussion in the main article.

Code Listing

(The whole program has about 350 lines of code, but I omit most of what is generated automatically since the programmer does not have to see it.)


void CWebizeDlg::OnButtonFile() 
{
	// select .txt file and check whether corresponding .htm file already exists
	static char szFilter[] = "TXT Files (*.txt)|*.txt||";
	CFileDialog dlg(TRUE, ".txt", NULL, OFN_HIDEREADONLY, szFilter);
	if (dlg.DoModal() != IDOK) return;	// user selected no file

	CString tmp = dlg.GetPathName();
	int lastDot = tmp.Find(".txt");
	CString Output = tmp.Left(lastDot+1);
	Output += "htm";
	FILE *gp = fopen(Output.GetBuffer(0), "r");
	if(gp != NULL) {
		if(AfxMessageBox("HTM file already exists. Overwrite?", MB_YESNO) == IDNO) {
			MessageBeep(0xFFFFFFFF);
			return;
		}
		fclose(gp);
	}
	// do the real work
	FILE *fp = fopen(dlg.GetPathName().GetBuffer(0), "r");
	gp = fopen(Output.GetBuffer(0), "w");
#define TXTBFSZ 4096	// assumes fewer than 600 words per paragraph (a page of text!)
	char buffer[TXTBFSZ];
	fprintf(gp, "<DIV>\n");
	int line = 0;
	while(fgets(buffer, TXTBFSZ, fp) != NULL) {
		if(line==0) fprintf(gp, "<h5>\n%s</h5>\n", buffer);
		else fprintf(gp,"<p>%s", buffer);
		line++;
	}
	fprintf(gp, "</DIV>\n");
	fclose(fp);	fclose(gp);
	MessageBeep(MB_ICONEXCLAMATION);
}

void CWebizeDlg::OnButtonHelp() 
{
	static char *help[] = {
		"Press the Get File button to open a file selection\n",
		"dialogue box then select and Open a .txt file.\n",
		"That file is converetd to an .htm file and after this\n",
		"is finished you hear a beep.\n",
		"Then you can press Get File to convert another file.",
		0
	};
	CString tmp = help[0];
	for(int i=1; i<5; i++) tmp += help[i];
	AfxMessageBox(tmp.GetBuffer(0));
}
 
theopavlidis.com Site Map