DOS下虽然有edit编辑器和更加原始的EDLIN行编辑器,但近几天我把《THE CRAFT OF C》中关于Screen-Editor的代码全部输机,想自己再弄出个新的文本编辑器。
代码如下:(在turboc下成功编译通过,但无法正常运行)
/* A Screen Editor Subsystem*/
#define TURBOC
#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <bios.h>
#include <conio.h>
#define BUF_SIZE 32000
#define LINE_LEN 79
#define MAX_LINES 24
#define KILL_BUF_SIZE 4*LINE_LEN
char buf[BUF_SIZE];
char *curloc,*endloc;
int scrnx,scrny;
char killbuf[KILL_BUF_SIZE];
char *helpline=
"F1:save F2:load F3:find F4:replace\
^K:Kill line ^Y:Yank ^Z:Quit ";
void edit(char *fname),help();
void gotoxy(int x,int y),clrline(int y);
void edit_clr_eol(int x,int y),clrscr();
void printline(char *p),delete_char(void);
void search(),kill_line();
void upline();
void downline(),left(),right();
void scrolldn (int x,int y);
void scrollup(int topx,int topy,int endx,int endy);
void display_scrn(int x,int y,char *p);
void pagedown(),pageup(),replace();
void home(),gotoend(),yank();
int load(char *fname),save(char *fname);
void edit_gets(char *str);
main(int argc,char *argv[])
{
if (argc==2) edit(argv[1]);
clrscr();
return 0;
}
/* This is the editor's entry function and contains
its main loop.
Call it with the name of the file you want to edit.
*/
void edit(char *fname)
{
union k{
char ch[2];
unsigned i;
}key;
char name[80];
/*try to load the file*/
if(!load(fname)) curloc=endloc=buf;
strcpy(name,fname);
clrscr();
scrnx=scrny=0;
display_scrn(0,0,curloc);
help();
gotoxy(0,0);
/*Editor main loop*/
do{
key.i=bioskey(0);
if(!key.ch[0]){
switch(key.ch[1]){
case 59: /*F1 save*/
save (name);
break;
case 60: /*F2 load*/
clrline(MAX_LINES);
gotoxy(0,MAX_LINES);
printf ("Enter filename:");
edit_gets(name);
if (*name) load (name);
help();
display_scrn(0,0,curloc);
scrnx=scrny=0;
break;
case 61: /*F3 search*/
search();
break;
case 62: /*F4 relace*/
replace();
break;
case 71: /*home*/
home();
break;
case 79: /*end*/
gotoend();
break;
case 75: /* left*/
left();
break;
case 77: /*right*/
right();
break;
case 72: /*up*/
upline();
break;
case 80: /*down*/
downline();
break;
case 73: /*page up*/
pageup();
break;
case 81: /*page down*/
pagedown();
break;
case 83: /*del*/
if(curloc<endloc) delete_char();
break;
}
if(curloc<buf){
scrnx=scrny=0;
curloc=buf;
}
gotoxy(scrnx,scrny);
}
else{ /* enter keystroke into file*/
switch(key.ch[0]){
case '\r': /* Carriage return*/
/*see if buffer is full*/
if(endloc==buf+BUF_SIZE-2) break;
/* move contents of file below current
location down one byte to make room
for the RETURN
*/
memmove(curloc+1,curloc,endloc-curloc+1);
*curloc=key.ch[0];
curloc++;
/*clear rest of line*/
edit_clr_eol(scrnx,scrny);
scrnx=0;
scrny++;
/*move text on the screen down*/
if (scrny==MAX_LINES){
scrny=MAX_LINES-1;
scrollup(0,0,LINE_LEN,scrny);
}
else scrolldn(scrnx,scrny);
gotoxy(scrnx,scrny);
printline(curloc);
endloc++;
break;
case '\b': /*backspace*/
if(curloc==buf) break;
left ();
delete_char();
break;
case 11: /*C-K:kiil line*/
kill_line();
break;
case 25: /*C-Y:yank kill buffer*/
yank();
break;
default:
if(endloc==buf+BUF_SIZE-2) break;
/*can't type past end of line*/
if(scrnx==LINE_LEN) break;
memmove(curloc+1,curloc,endloc-curloc+1);
*curloc=key.ch[0];
putch(*curloc);
scrnx++;
gotoxy(scrnx,scrny);
printline(curloc+1);
curloc++;
endloc++;
}
gotoxy(scrnx,scrny);
}
}while(key.ch[0]!=26);
}
/* Display a line pointed to by P.*/
void printline(register char *p)
{
register int i;
i=scrnx;
while(*p!='\r'&& *p && i<LINE_LEN){
putch(*p);
p++;
i++;
}
}
/*Insert previously killed line*/
void yank()
{
char *p;
p=killbuf;
while(*p){
memmove(curloc+1,curloc,endloc-curloc+1);
*curloc=*p;
if(scrnx<LINE_LEN){
putch(*curloc);
scrnx++;
}
curloc++;
endloc++;
p++;
}
printline (curloc);
}
/*Delete the line at the current location*/
void kill_line()
{
register int i;
char *p,*killbufptr;
if(*curloc=='\r'){
delete_char();
return;
}
edit_clr_eol(scrnx,scrny);
/*find out how many characters are in the line*/
p=curloc;
i=0;
killbufptr=killbuf;
while(*p!='\r' && p<endloc){
i++;
*killbufptr=*p;
p++;
if(killbufptr<killbuf+KILL_BUF_SIZE-2) killbufptr++;
}
*killbufptr='\0';
/*remove the line*/
memmove(curloc,curloc+1,endloc-curloc);
endloc-=i;
}
/*Global search and replace*/
void replace()
{
register int len1;
char str1[80],str2[80];
char *p,*p2;
clrline(MAX_LINES);
gotoxy(0,MAX_LINES);
printf("enter string to replace: ");
edit_gets(str1);
clrline(MAX_LINES);
gotoxy(0,MAX_LINES);
printf ("enter replacement: ");
edit_gets(str2);
p=curloc;
len1=strlen(str1);
while(*str1){
/*search for a string*/
while(*p && strncmp(str1,p,len1)) p++;
if (!p) break;
/*remove old string*/
memmove(p,p+len1,endloc-p);
endloc-=len1;
/*insert new string*/
p2=str2;
while(*p2){
memmove(p+1,p,endloc-p+1);
*p=*p2;
p++;
endloc++;
p2++;
}
}
clrscr();
/*find location of top of screen*/
p=curloc;
for(len1=scrny;len1>=0&&p>buf;){
p--;
if(*p=='\r') len1--;
}
if(*p=='\r') p++;
/*redisplay current screen*/
display_scrn(0,0,p);
help();
}
/*Delete character at the current location.*/
void delete_char()
{
gotoxy(scrnx,scrny);
if(*curloc=='\r'){
scrollup(0,scrny+1,LINE_LEN,MAX_LINES-1);
memmove(curloc,curloc+1,endloc-curloc);
endloc--;
display_scrn(scrnx,scrny,curloc);
help();
}
else{
memmove(curloc,curloc+1,endloc-curloc);
endloc--;
printline(curloc); printf(" ");
}
}
/*Display help line*/
void help()
{
gotoxy(0,MAX_LINES);
printf(helpline);
}
/*Move current location left*/
void left()
{
if(curloc==buf) return;
scrnx--;
if(scrnx<0){
scrnx=0;
upline();
/*find end of line*/
while(*curloc!='\r'){
curloc++;
scrnx++;
}
}
else curloc--;
}
/*Move currrent position right*/
void right()
{
/*can't move rihgt*/
if(curloc+1>endloc) return;
scrnx++;
/*if at end of line,go to next one*/
if(scrnx>LINE_LEN||*curloc=='\r'){
scrnx=0;
scrny++;
if(scrny==MAX_LINES){
scrny=MAX_LINES-1;
downline();
/*move cursor and current loc to start
of new line*/
curloc--;
while(*curloc!='\r') curloc--;
curloc++;
scrnx=0;
}
else curloc++;
}
else curloc++;
}
/*Find a string*/
void search()
{
char str[80];
register char *p;
int len,i;
clrline(MAX_LINES);
gotoxy(0,MAX_LINES);
printf("search string: ");
edit_gets(str);
if(!*str) return;
p=curloc;
len=strlen(str);
/*search for the string*/
while(*p && strncmp(str,p,len)) p++;
if(!*p) return;
/*back up to start of line*/
i=0;
while(p>buf&&*p!='\r'){
p--;
i++;
}
p++;
i--;
/*reposition current location to start of match*/
curloc=p+i;
scrnx=i;
scrny=0;
/*diplay screenof text at location of match*/
clrscr();
display_scrn(0,0,p);
help();
}
/*Move up one line.*/
void upline()
{
register int i;
char *p;
if(curloc==buf) return;
p=curloc;
if(*p=='\r') p--;
/*back up loacator to start of current line.*/
for(;*p!='\r'&&p>buf;p--);
if(*p!='\r') return;
curloc=p;
curloc--;
i=scrnx;
/*find start of next line*/
while(*curloc!='\r' && curloc>=buf) curloc--;
scrny--;scrnx=0;
curloc++;
/*at top of screen,must scroll up*/
if(scrny<0){
scrolldn(0,0);
scrny=0;
gotoxy(0,0);
printline(curloc);
}
/* position the cursor and current location at
same scrnx position as previous line if possible*/
while(i&& *curloc!='\r'){
curloc++;
scrnx++;
i--;
}
}
/* Move down one line. */
void downline()
{
register int i;
char *p;
i=scrnx;
p=curloc;
/* advance current location to start to next line*/
while(*p!='\r' && p<endloc) p++;
if(p==endloc) return;
p++;
curloc=p;
scrny++;scrnx=0;
/*if moving down past the bottom of the screen*/
if(scrny==MAX_LINES){
scrny=MAX_LINES-1;
scrollup(0,0,LINE_LEN,MAX_LINES-1);
gotoxy(scrnx,scrny);
printline(curloc);
}
/* advance to corresponding character in next line*/
while(i && *curloc!='\r' && curloc<endloc){
curloc++;
scrnx++;
i--;
}
}
/* Display a screen full of text(up to 24lines)
starting at the specified location.
*/
void display_scrn(int x,int y,char *p)
{
register int i;
gotoxy(x,y);
i=0;
while(y<MAX_LINES && *p){
switch(*p){
case '\r':printf("\n");
y++;
i=0;
break;
default:if(i<LINE_LEN) putch(*p);
i++;
}
p++;
}
}
/* Page down MAX_LINES lines.*/
void pagedown()
{
register int i;
clrscr();
/*count down MAX_LINES lines.*/
for(i=0;i<MAX_LINES && curloc<endloc;){
if (*curloc=='\r') i++;
curloc++;
}
help();
scrnx=0;scrny=0;
display_scrn(0,0,curloc);
}
/* Page up MAX_LINES lines*/
void pageup()
{
register int i;
clrscr();
if (*curloc=='\r' && curloc>buf) curloc--;
/* go back MAX_LINES in buffer*/
for(i=0;i<MAX_LINES+1 && curloc>buf;){
if(*curloc=='\r') i++;
curloc--;
}
if(i==MAX_LINES+1) curloc+=2;
help();
scrnx=0;scrny=0;
display_scrn(0,0,curloc);
}
/* Go to the top of the file.*/
void home()
{
clrscr();
curloc=buf;
scrnx=scrny=0;
display_scrn(0,0,curloc);
help();
}
/* Go to the end of the file. */
void gotoend()
{
clrscr();
curloc=endloc;
pageup();
}
/* Load a file.*/
load(char *fname)
{
FILE *fp;
char ch,*p;
if((fp=fopen(fname,"rb"))==NULL)
return 0;
p=buf;
while(!feof(fp) && p!=buf+BUF_SIZE-2){
ch=getc(fp);
if(ch!='\n' && ch!=EOF){
*p=ch;
p++;
}
}
*p='\0';
fclose (fp);
curloc=buf;
endloc=p;
return 1;
}
/* Save a file.*/
save(char *fname)
{
FILE *fp;
char *p,name[80];
if(!*fname){
printf("filename: ");
gets(name);
}
else strcpy(name,fname);
if((fp=fopen(name,"wb"))==NULL)
return 0;
p=buf;
while(p!=endloc){
if(*p!='\r')
putc(*p,fp);
else{
putc('\r',fp);
putc('\n',fp);
}
p++;
}
fclose(fp);
return 1;
}
/* Read a string from the keyboard,but do not
scroll the display when a RETURN is entered.
*/
void edit_gets(char *str)
{
char *p;
p=str;
for(;;){
*str=getch();
if(*str=='\r'){
*str='\0';
return;
}
if(*str=='\b'){
if(str>p){
str--;
putch('\b');
putch(' ');
putch('\b');
}
}
else{
putch(*str);
str++;
}
}
}
/* Read and save cursor coordinates.*/
void cursor_pos()
{
union REGS i,o;
i.h.bh=0;
i.h.ah=3;
int86(16,&i,&o);
}
/* Send cursor to specified X,Y (0,0 is
Upper left corner.
*/
void gotoxy(int x,int y)
{
union REGS i;
i.h.dh=y;
i.h.dl=x;
i.h.ah=2;
i.h.bh=0;
int86(16,&i,&i);
}
/* Clear entire line given its Y coordinate.*/
void clrline(int y)
{
register int i;
gotoxy(0,y);
for(i=0;i<LINE_LEN;i++) putch(' ');
}
/* Clear to end of specified line.*/
void edit_clr_eol(int x,int y)
{
char *p;
p=curloc;
gotoxy(x,y);
for(;x<LINE_LEN && *p!='\r' && *p;x++,p++){
printf(" ");
}
}
/* Clear the screen.*/
void clrscr()
{
union REGS r;
r.h.ah=6;
r.h.al=0;
r.h.ch=0;
r.h.cl=0;
r.h.dh=MAX_LINES;
r.h.dl=LINE_LEN;
r.h.bh=7;
int86(0x10,&r,&r);
}
/*Scroll down the screen.*/
void scrolldn(int x,int y)
{
union REGS r;
r.h.ah=7;
r.h.al=1;
r.h.ch=y;
r.h.cl=x;
r.h.dh=MAX_LINES-1;
r.h.dl=LINE_LEN;
r.h.bh=7;
int86(0x10,&r,&r);
}
/* Scroll up the screen using the specified coordinate.*/
void scrollup(int topx,int topy,int endx,int endy)
{
union REGS r;
r.h.ah=6;
r.h.al=1;
r.h.ch=topy;
r.h.cl=topx;
r.h.dh=endy;
r.h.dl=endx;
r.h.bh=7;
int86(0x10,&r,&r);
}