home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource1
/
cenvid
/
cmmedit.cmm
< prev
next >
Wrap
Text File
|
1993-11-17
|
16KB
|
409 lines
/**************************************************************************
*** CmmEdit - A simple text editor. This is the tutorial program from ***
*** chapter 3 of the CEnvi manual. ***
**************************************************************************/
main(ArgCount,ArgList)
{
FileName = GetFileName(ArgCount,ArgList);
ReadFile(FileName);
if ( Edit() ) // Edit returns TRUE if changes made to file
WriteFile(FileName);
}
GetFileName(argc,argv)
// return a file name from the program input arguments, or prompt user for the
// file name if none was supplied at the command line. exit() program if no
// file name is gotten.
{
// If at least one argument was supplied to main() in addition to the source
// file name (which is always supplied), then that argument is the file name.
if ( 1 < argc )
return(argv[1]);
// File name wasn't supplied on the command line, and so prompt for name.
printf("Enter file name to edit: ");
filespec = gets();
if ( filespec == NULL || filespec[0] == 0 ) // no name was entered so quit
exit(EXIT_FAILURE);
return(filespec);
}
Text[0] = ""; // Text is an array of s text strings; one for each file line
ReadFile(FileSpec) // read FileSpec file into global data. exit() if error.
{
// Open the file, in text mode, for reading into Text.
fp = fopen(FileSpec,"rt");
if ( fp == NULL ) {
// The file doesn't exist, and so ask user if they want to quit. If they
// don't want to create file then simply exit this program. If they do
// want to create file then we're done, as Text is already initialized.
printf("File \"%s\" does not exist. Create file? Y/N ",FileSpec);
do {
key = toupper(getch()); // make uppercase to compare to Y and N
if ( key == 'N' )
exit(EXIT_FAILURE);
} while( key != 'Y' ); // wasn't Y or N, and so try again
} else {
// File opened. Read each line of file into the next element of Text.
for ( LineCount = 0; NULL != (line = fgets(fp)); LineCount++ ) {
// line set to new string for next line in the text file. Set the next
// line of Text to this line.
Text[LineCount] = line;
}
fclose(fp); // Should always close a file that has been opened.
}
}
WriteFile(FileSpec) // write global data to back to FileSpec. exit() if error.
{
// Open FileSpec for writing in text mode. If the file already exists then
// truncate the file. If file doesn't exist then create it.
fp = fopen(FileSpec,"wt");
if ( fp == NULL ) {
printf("\aUnable to open \"%s\" for writing.\a\n");
exit(EXIT_FAILURE);
}
// write every line of Text into fp
for ( i = 0; i <= GetArraySpan(Text); i++ )
fputs( Text[i], fp );
// close fp
fclose(fp);
}
// define movement keys - Give values over 0x100 to distinguish from text
#define MIN_CUR_MOVE 0x101
#define UP 0x101
#define DOWN 0x102
#define LEFT 0x103
#define RIGHT 0x104
#define PG_UP 0x105
#define PG_DN 0x106
#define HOME 0x107
#define END 0x108
#define BK_TAB 0x109
#define DELETE 0x110
GetKeyChar() // return key from keyboard, ascii for above #defined
{
if defined(_DOS_) || defined(_OS2_) {
// DOS and OS/2 return 0 on first getch for extended keys
KeyCode = getch();
if ( KeyCode == 0 ) {
// set value for extended key; these value found using KeyCode.cmd
switch( getch() ) {
case 0x48: KeyCode = UP; break;
case 0x50: KeyCode = DOWN; break;
case 0x4B: KeyCode = LEFT; break;
case 0x4D: KeyCode = RIGHT; break;
case 0x49: KeyCode = PG_UP; break;
case 0x51: KeyCode = PG_DN; break;
case 0x47: KeyCode = HOME; break;
case 0x4F: KeyCode = END; break;
case 0x0F; KeyCode = BK_TAB; break;
case 0x53; KeyCode = DELETE; break;
default: break; // return 0, which will do nothing
}
}
} else {
// Windows version
KeyCode = getch();
if ( 0x100 < KeyCode ) {
switch ( KeyCode ) {
// special values in the following table come from KeyCode.cmm
case 0x126: KeyCode = UP; break;
case 0x128: KeyCode = DOWN; break;
case 0x125: KeyCode = LEFT; break;
case 0x127: KeyCode = RIGHT; break;
case 0x121: KeyCode = PG_UP; break;
case 0x122: KeyCode = PG_DN; break;
case 0x124: KeyCode = HOME; break;
case 0x123: KeyCode = END; break;
case 0x109; KeyCode = BK_TAB; break;
case 0x12E; KeyCode = DELETE; break;
default: KeyCode = 0; break;
}
}
}
return(KeyCode);
}
Edit() // Edit file. This is were the hard work happens. exit() if error.
{ // Return FALSE if no editing was done, else return TRUE.
LineCount = 1 + GetArraySpan(Text); // how many lines in file
// Initialize screen: get its dimensions, and cursor location.
ScreenClear();
ScreenDimension = ScreenSize();
CursorCol = CursorRow = 0; // initialize cursor position
// Starting at row 0, draw all lines on screen. Initialize Start as structure
// for upper-left visible portion of file. Then draw the file.
Start.Row = Start.Col = 0;
DrawVisibleTextLines( Start, ScreenDimension, LineCount );
DrawnStart = Start; // remember which lines were drawn
CursorStatus(CursorRow,CursorCol,Start,ScreenDimension);
// FileWasEdited is boolean to say if changes made
FileWasEdited = FALSE;
// Stay here getting all keyboard input until escape is pressed
#define ESCAPE_KEY '\033'
while ( (key = GetKeyChar()) != ESCAPE_KEY ) {
// special keyboard codes are returned if getch() first
switch( key ) {
case UP: CursorRow--; break;
case DOWN: CursorRow++; break;
case LEFT: CursorCol--; break;
case RIGHT: CursorCol++; break;
case HOME: CursorCol = 0; break;
case END:
// go to end of visible line, but not including newline
CursorCol = strlen(Text[CursorRow]);
if ( 0 < CursorCol && Text[CursorRow][CursorCol-1] == '\n' )
CursorCol--;
break;
case PG_UP:
CursorRow -= (ScreenDimension.row - 1);
Start.Row -= (ScreenDimension.row - 1);
break;
case PG_DN:
CursorRow += (ScreenDimension.row - 1);
Start.Row += (ScreenDimension.row - 1);
break;
#define TABSIZE 8
case '\t':
CursorCol += TABSIZE;
CursorCol -= CursorCol % TABSIZE;
break;
case BK_TAB:
CursorCol -= TABSIZE;
CursorCol -= CursorCol % TABSIZE;
break;
#define BACKSPACE '\010'
case BACKSPACE:
// Back space is just like deleting from one column to the left,
// and so check that we're not on the first column and then move
// left a column and let control fall to DELETE
if ( --CursorCol < 0 ) {
// backspace from beginning of line; move to end of previous line
if ( CursorRow == 0 ) {
// cannot backup to earlier row, so do nothing
CursorCol = 0;
break;
}
CursorCol = strlen(Text[--CursorRow]) - 1;
}
case DELETE:
if ( DeleteCharacterAtCursor(CursorRow,CursorCol,LineCount) ) {
FileWasEdited = TRUE