Advanced C 1992
.pdfPart II • Managing Data in C
Listing 9.1. continued
case ‘b’:
printf(“Note the bytes written always” “ equal the string’s length\n\n”);
break;
}
return (0);
}
TEXTFILE enables you to open the file in text mode or binary mode so you can see how the modes differ. The ftell() function returns the number of bytes in the file, without regard to the file’s mode. All strings in TEXTFILE have the same number of characters, according to strlen(), but the number of bytes written in the text mode depends on the number of newline characters in the string.
Virtually all files saved by editors and other programs are equivalent to a text file. Many DOS programs cannot read a file that does not have the newline and carriage return combination.
Creating and Using Temporary Work Files
When you create a temporary work file, remember the following simple rules:
• The filename must be unique. This uniqueness can be guaranteed by using
tmpfile() or tmpnam().
•The file must be deleted when you have finished using it. If you create the file using tmpfile(), the operating system deletes the file for you. If you create it with tmpnam() and an explicit open, your program must delete the file.
Few programs can store all their data in memory. You cannot be sure of the amount of memory available to your program for data storage, and you therefore won’t know if there will be enough memory to load the data the program requires.
Many larger programs with large data objects do not even try to save all their data in memory. They read the data, index the data, then write the data to a temporary work file. Listing 9.2, EDLINE, is a simple editor that reads a text file, provides editing
256
Disk Files and Other I/O |
C C C |
|
C9C |
|
C C C |
|
C |
capabilities, then writes the program’s buffers out to the file when the user ends the program. Because this editor is simple, it supports only line-number editing.
Listing 9.2. EDLINE.C.
/* EDLINE, written 1992 by Peter D. Hipson
*This program is a simple line-oriented editor. If
*your compiler supports memory models, use the
*large model.
*/ |
|
#include <stdio.h> |
// Make includes first part of file |
#include <string.h> |
// For string functions |
#include <process.h> |
// For abort(), spawn(), exit(), etc. |
#include <malloc.h> |
// For memory allocation functions |
#include <conio.h> |
// For console getch(), getche(), etc. |
#include <ctype.h> |
// For character conversion functions |
#define MAX_LINES 15500 #define MAX_LENGTH 513 #define DELETED_LINE -1
/* Allow 64K for indexes |
*/ |
|
/* Longest line is |
512 + NULL |
*/ |
/* A line that has |
been deleted */ |
long |
lLineIndex[MAX_LINES]; |
|
|
char |
szInputLine[MAX_LENGTH]; |
|
|
int main( |
|
|
|
int |
argc, |
/* Count of arguments |
*/ |
char |
*argv[], |
/* Array of pointers to arguments |
*/ |
char |
*envp[] |
/* Array of pointers to environment */ |
|
); |
|
|
|
int EditLine(char * szInputLine); /* Used to edit a given line */
int main( |
|
int |
argc, |
char |
*argv[], |
char |
*envp[] |
) |
|
continues
257
Part II • Managing Data in C
Listing 9.2. continued
{ |
|
FILE |
*DataFile = NULL; |
FILE |
*WorkFile = NULL; |
char |
szFileName[25]; |
char |
szBuffer[257]; |
char |
szTempName[L_tmpnam]; |
char |
szNewName[L_tmpnam]; |
char |
szCommand[81]; |
char |
chChar; |
int |
i; |
int |
nMaxLines = 0; |
int |
nStartLine; |
int |
nEndLine; |
/* First, get the filename to edit */
if (argc >= 2)
{
DataFile = fopen(argv[1], “rt”);
if (DataFile == NULL)
{
printf(“ERROR: File ‘%s’ couldn’t be opened.\n”, argv[1]);
}
else
{
strcpy(szFileName, argv[1]);
}
}
while (DataFile == NULL)
{
printf(“\nPlease enter name of file to edit: “);
gets(szFileName);
258
Disk Files and Other I/O |
C C C |
|
C9C |
|
C C C |
|
C |
DataFile = fopen(szFileName, “rt”);
if (DataFile == NULL)
{
printf(“ERROR: File ‘%s’ couldn’t be opened.\n”, szFileName);
}
}
printf(“\n”);
/* Next, get a temporary filename, read the original file, and
*write it to the work file. Create a line-number index so that
*you can access the records.
*/
tmpnam(szTempName);
if (strlen(szTempName) == 0)
{
printf(“Couldn’t get a work file name...\n”); exit(4);
}
WorkFile = fopen(szTempName, “w+t”);
for (i = 0; i < MAX_LINES; i++)
{
lLineIndex[i] = DELETED_LINE;
}
nMaxLines = 1; lLineIndex[nMaxLines] = 0;
while(fgets(szInputLine, sizeof(szInputLine), DataFile))
{
lLineIndex[nMaxLines++] = ftell(WorkFile); fputs(szInputLine, WorkFile);
}
fclose(DataFile);
continues
259
Part II • Managing Data in C
Listing 9.2. continued
printf(“Total lines in file %d.\n”, nMaxLines - 1);
szCommand[0] = ‘\0’;
while(szCommand[0] != ‘q’) // Quit without saving (use w command to // save)
{
printf(“Command? “);
gets(szCommand);
strlwr(szCommand);
nEndLine = -1;
sscanf(&szCommand[1], “%d%d”, &nStartLine,
&nEndLine);
if (nEndLine < nStartLine)
{
nEndLine = nStartLine;
}
if (nEndLine >= nMaxLines)
{
nEndLine = (nMaxLines - 1);
}
switch(szCommand[0])
{
case ‘e’: /* Edit the specified line */
if (nStartLine == 0)
{
printf(“Line number must be 1 to %d\n”, nMaxLines);
}
else
{
260
Disk Files and Other I/O
if (lLineIndex[nStartLine] == DELETED_LINE)
{
printf(“Line %d has been deleted, “ “and cannot be edited.\n”,
nStartLine);
}
C C C
C9C C
C C C
if (nStartLine < nMaxLines && lLineIndex[nStartLine] != DELETED_LINE)
{
fseek(WorkFile, lLineIndex[nStartLine], SEEK_SET);
fgets(szInputLine, sizeof(szInputLine), WorkFile);
if (EditLine(szInputLine))
{
fseek(WorkFile, 0, SEEK_END);
lLineIndex[nStartLine] = ftell(WorkFile);
fputs(szInputLine, WorkFile);
}
}
}
break;
case ‘l’: /* List the specified line */
if (nStartLine == 0)
{
nStartLine = 1;
while(nStartLine < nMaxLines)
{
if (lLineIndex[nStartLine] != DELETED_LINE)
{
fseek(WorkFile, lLineIndex[nStartLine], SEEK_SET);
continues
261
Part II • Managing Data in C
Listing 9.2. continued
fgets(szInputLine, sizeof(szInputLine), WorkFile);
printf(“%4d - %s”, nStartLine, szInputLine);
}
else
{
printf(“%4d ***DELETED LINE***\n”, nStartLine);
}
++nStartLine;
}
nStartLine = 0;
}
else
{
while(nStartLine <= nEndLine)
{
if (lLineIndex[nStartLine] != DELETED_LINE)
{
fseek(WorkFile, lLineIndex[nStartLine], SEEK_SET);
fgets(szInputLine, sizeof(szInputLine), WorkFile);
printf(“%4d - %s”, nStartLine, szInputLine);
}
else
{
printf(“%4d ***DELETED LINE***\n”, nStartLine);
}
262
Disk Files and Other I/O |
C C C |
|
C9C |
|
C C C |
|
C |
++nStartLine;
}
}
break;
case ‘d’: /* Delete the specified line */
if (nStartLine > 0 && nStartLine < nMaxLines)
{
printf(“Do you really want to delete line %d? (y|n) “, nStartLine);
chChar = getche();
printf(“\n”);
if (chChar == ‘y’ || chChar == ‘Y’)
{
lLineIndex[nStartLine] = DELETED_LINE;
}
}
break;
case ‘w’: /* Write; continue editing? */
szNewName[0] = ‘\0’;
tmpnam(szNewName);
if (strlen(szNewName) == 0)
{
printf(“Error getting a temporary file name...\n”);
}
rename(szFileName, szNewName);
DataFile = fopen(szFileName, “wt”);
nStartLine = 1;
continues
263
Part II • Managing Data in C
Listing 9.2. continued
while(nStartLine < nMaxLines)
{
if (lLineIndex[nStartLine] != DELETED_LINE)
{
fseek(WorkFile, lLineIndex[nStartLine], SEEK_SET);
fgets(szInputLine, sizeof(szInputLine), WorkFile);
fputs(szInputLine, DataFile);
}
++nStartLine;
}
nStartLine = 0;
fclose(DataFile);
/* In this version, the original file is simply deleted.
*A better programming practice is to rename it to .BAK
*so the user can recover the original file.
*
*Question:
*When renaming to .BAK, does the user recover from the
*last save or the original file?
*/
remove(szNewName); /* Could be renamed to .BAK */
break;
case ‘q’: /* Quit, with no save */
break;
default:
printf(“Error: the command ‘%c’ is not supported!\n”, szCommand[0]);
264
Disk Files and Other I/O
break;
}
}
fclose(WorkFile);
remove(szTempName);
return (0);
}
int EditLine(
|
char * szInputLine) |
|
{ |
|
|
char |
chChar = |
‘A’; // To fool while() the first time! |
int |
nCurrentChar = 0; |
|
|
printf(“%s”, |
szInputLine); |
while (chChar)
{
chChar = getch(); if (chChar == ‘\0’)
{
chChar = getch();
switch(chChar)
{
case ‘\x4D’:
printf(“%c”, szInputLine[nCurrentChar]); ++nCurrentChar;
break;
default: /* No other keys implemented yet */ printf(“\a”);
break;
}
C C C
C9C C
C C C
continues
265