Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
92
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Part 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