Feb 14

trans程序的源代码在Msys下用gcc编译调试通过。

使用说明:trans  [-r/-s] srcfile objfile

    其中,-R 将摩斯码翻译成英文;
          -S 将英语翻译成摩斯码。
          srcfile为需要翻译的文本文件。运行成功后结果会保存在objfile文件中。

    注意:若是翻译英文,须保证所有字母均为大写字母。且标点符号仅可为“.”和“,”

代码已上传至github https://github.com/longqzh/MorseCode_Translator

/* *******************************
 *
 * Translator for Morse Code
 *
 * Author: Long Qianzhi
 * Date:2010/1/28
 *
 * *******************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX 39

struct table{
	char letter;
	char mor[8];
}table[]={
	{'A',".-"},{'B',"-..."},{'C',"-.-."},
	{'D',"-.."},{'E',"."},{'F',"..-."},
	{'G',"--."},{'H',"...."},{'I',".."},
	{'J',".---"},{'K',"-.-"},{'L',".-.."},
	{'M',"--"},{'N',"-."},{'O',"---"},
	{'P',".--."},{'Q',"--.-"},{'R',".-."},
	{'S',"..."},{'T',"-"},{'U',"..-"},
	{'V',"...-"},{'W',".--"},{'X',"-..-"},
	{'Y',"-.--"},{'Z',"--.."},{'0',"-----"},
	{'1',".----"},{'2',"..---"},{'3',"...--"},
	{'4',"....-"},{'5',"....."},{'6',"-...."},
	{'7',"--..."},{'8',"---.."},{'9',"----."},
	{'.',".-.-.-"},{',',"--..--"},{' ',".--.-."},
	{'\n',""}
};

FILE *infp=NULL, *outfp=NULL;

void check_file(char *in, char *out)
{
	if((infp=fopen(in,"r"))==NULL){
		printf("\nCan't open source file : %s\n", in);
		exit(1);
	}
	else if ((outfp=fopen(out,"w"))==NULL){
		printf("\nCan't open output file : %s\n", out);
		exit(1);
	}
	return;
}

int file_size(FILE *fp)
{
	int fsize=0;
	char c;
	while((c=fgetc(fp))!=EOF)
		fsize++;
	rewind(fp);
	return fsize;
}

char* make_buf(int n)
{
	char *pstr;
	pstr=(char *)malloc(n*sizeof(char));
	if(pstr==NULL){
		printf("\nMalloc failed!\n");
		exit(1);
	}
	return pstr;
}

void m2t()
{
	char *buffer;
	int fnum,n=0,i=0;
	char tmp[8]="";

	/* Read all of the data from srcfile to buffer.*/
	fnum=file_size(infp);
	buffer=make_buf(fnum+1);
	if((fread(buffer,sizeof(char),fnum,infp))!=fnum){
		printf("\nSomething wrong about reading file!\n");
		exit(1);
	}
	*(buffer+fnum)='\0';
	fclose(infp);

	printf("%s\n",buffer);fflush(stdout);

	while(*buffer!='\0'){

		/* Read a word from buffer to tmp.*/
		while(*buffer!=' ' && *buffer!='\0'){
			tmp[n++]=*buffer++;
			if(n>7){
				tmp[7]='\0';
				printf(" %s : Bad MorseCode!\n", tmp);
				exit(1);
			}
		}
		tmp[n]='\0';
		n=0; 
		printf("%s\t",tmp);fflush(stdout);
		

		while(strcmp(tmp,table[i++].mor)){
			if(i>=MAX && *(buffer+1)!='\0'){
				printf(" %s : CANNOT find it!\n", tmp);
				exit(1);
			}
		}

		fputc(table[--i].letter,outfp);
		printf("%c\t",table[i].letter);fflush(stdout);
		i=0;
		buffer++;
	}
	fclose(outfp);
	printf("The translated file is created.\n");
	fflush(stdout);
}

void t2m()
{
	char *buffer;
	int fnum,i=0;

	/* Read all of the data from srcfile to buffer.*/
	fnum=file_size(infp);

	buffer=make_buf(fnum+1);
	if((fread(buffer,sizeof(char),fnum,infp))!=fnum){
		printf("\nSomething wrong about reading file!\n");
		exit(1);
	}
	*(buffer+fnum)='\0';
	fclose(infp);

	printf("%s %d\n", buffer,(int)(*buffer));fflush(stdout);

	while(*buffer!='\0'){
		/* find the MorseCode according to character.*/
		while(*buffer!=table[i].letter){
			
			i++;
			fflush(stdout);
			if(i>MAX && *buffer!=EOF){
				printf(" %c %d: Bad character\n", *buffer,(int)(*buffer));
				exit(1);
			}
		}
		buffer++;
		printf("%c-->%s\t\n",table[i].letter,table[i].mor);fflush(stdout);

		fputs(table[i].mor,outfp);
		fputc(' ',outfp);
		i=0;
	}
	fclose(outfp);
	printf("The translated file is created.\n");
	fflush(stdout);
}

int main(int argc,char *argv[])
{
	if (argc!=4){
		printf("Usage: trans [-R/-S] srcfile outfile\n");
		printf("\n\t -r translate Morse to English.");
		printf("\n\t -s translate English to Morse.");
		printf("\n\t -h show this help information.\n");
		fflush(stdout);
		return 1;
	}

	if (!strcmp(argv[1],"-r") || !strcmp(argv[1],"-R")){
		check_file(argv[2],argv[3]);
		m2t();
	}
	else if (!strcmp(argv[1],"-s") || !strcmp(argv[1],"-S")){
		check_file(argv[2],argv[3]);
		t2m();
	}else{
		printf("You input wrong arguments!\n");
		printf("Please type \"trans -h\".\n");
		fflush(stdout);
	}
	return 0;
}
Dec 16

公布期末设计Smallshell的完整源代码:

 

/* *************************************************
 *
 *          Small shell on Unix/Linux
 *
 *   This shell finished all the functions which 
 *   are required. And I added new inner functions
 *   "help" and "exit" by myself.
 *  
 *   Enjoy it!
 *
 *   author: Longqianzhi 용성지 
 *   Stu_ID: 12094817
 *   data:   Dec/27/2010
 *
 * *************************************************/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

#define MAX_CMD_ARG 10
#define MAX_CMD_LIST 10

const char *prompt = "# ";

char* cmdlist[MAX_CMD_LIST];
char* cmdargs[MAX_CMD_ARG];
char  cmdline[BUFSIZ];

void fatal(char *str);
void execute_cmd(char *cmd);
void execute_cmdline(char* cmdline);
int makeargv(char *s, const char *delimiters, 
	             char** argvp, int MAX_LIST);
void help();
void cd(char *path);
void catchint(int);
void join();                    /* Use one pipe to communication.*/
int join2();                    /* Use two pipe to communication.*/
int dpipe_test();               /* It's useless.Just for test.*/
void parse_filter(char *cmd);   /* A filter for argument*/ 


int main(int argc, char**argv){
	int i=0;
	static struct sigaction act;

	/*Cope with the signal*/

	act.sa_handler=catchint;
	sigfillset(&(act.sa_mask));
	sigaction(SIGINT,&act,NULL);
	sigaction(SIGQUIT,&act,NULL);

	while (1) {     
		fputs(prompt, stdout);
		fgets(cmdline, BUFSIZ, stdin);
		cmdline[ strlen(cmdline) -1] ='\0';

		execute_cmdline(cmdline);
		printf("\n");
	}
	return 0;
}

void fatal(char *str){
	perror(str);
	exit(1);
}

void execute_cmdline(char* cmdline){
	int count = 0;
	int i=0;
	count = makeargv(cmdline, "!", cmdlist, MAX_CMD_LIST);

    /* Execute the commands with different way.*/   

	/*Just a single command.*/
	if(count==1){
	
		/* First of all,try to make sure whether
		 * the command is "cd".
		 */
		if(cmdlist[0][0]=='c'&&cmdlist[0][1]=='d'){
			parse_filter(cmdlist[0]);  
			count = makeargv(cmdlist[0], " \t", cmdargs, MAX_CMD_ARG);
			if(!strcmp("cd",cmdargs[0])){
				if(chdir(cmdargs[1]))  fatal("cd");
				return;
			}
		}
	
		/* Fork a child process to run every
		 * commands except "cd" 
		*/
		 
		switch(fork())
		{
		case -1: fatal("fork error");
		case  0: execute_cmd(cmdlist[0]);
		default:
			wait(NULL);
			fflush(stdout);
		}
	}
	
	/*Execute two programs with a pipe.*/
	if(count==2){
		join();
	}

	/*Execute three programs with two pipes.*/
	if(count==3){
		join2();
	}

	/*There are too many commands*/
	if(count>=4){
		printf("Too many pipes!\n");
		return;
	}
}

/* *****************************************
 * Execute a single commands with arguments.
 *
 * *****************************************/
void execute_cmd(char *cmd){
	int i=0; 
	int count = 0;
	
	parse_filter(cmd);  
	count = makeargv(cmd, " \t", cmdargs, MAX_CMD_ARG);

	/* 
	 * Recognize some inner functions 
	 * like cd,help,exit and so on.
	 * Also you can add some new inner
	 * functions by yourself here.
	 *
	 */
	if(!strcmp("help",cmdargs[0])){
		help();
		return ;
	}

	if(!strcmp("exit",cmdargs[0])){
		kill(getppid(),SIGKILL); /*kill parent process*/
		raise(SIGKILL); /*kill myself*/
		exit(0);
	}

	execvp(cmdargs[0], cmdargs);
	fatal("exec error");
}

/* *****************************************
 *  Count the arguments'number in a command.
 *
 * ***************************************/
int makeargv(char *s, const char *delimiters, 
   					char** argvp, int MAX_LIST) {

	int i = 0;
	int numtokens = 0;
	char *snew = NULL;

	if( (s==NULL) || (delimiters==NULL) ) return -1;

	snew = s + strspn(s, delimiters);	
	if( (argvp[numtokens]=strtok(snew, delimiters)) == NULL )
	return numtokens;
	
	numtokens = 1;
	while(1){
		if( (argvp[numtokens]=strtok(NULL, delimiters)) == NULL)
			break;
		if(numtokens == (MAX_LIST-1)) return -1;
			numtokens++;
	}
	return numtokens;
}

/* *********************************
 * Inner fnuction: help().
 * Show some infomations to the stdin
 *
 ***********************************/
void help(){
	printf("\n  * *************************************** *");
	printf("\n  *                                         *");
	printf("\n  *         WELCOME TO SMALL SHELL !        *");
	printf("\n  *                                         *");
	printf("\n  * *************************************** *");
	printf("\n  *                                         *");
	printf("\n  *  There are 3 inner functions in shell.  *");
	printf("\n  *                                         *");
	printf("\n  *  1) cd :Change the current directory.   *");
	printf("\n  *  2) exit :Quit from the small shell.    *");
	printf("\n  *  3) help :Show this message for help.   *"); 
	printf("\n  *                                         *");
	printf("\n  *        IF YOU FIND ANY BUGS OR          *");
	printf("\n  *          HAVE ANY QUESTIONS             *");
	printf("\n  *                                         *");
	printf("\n  *    mail to me:longqianzhi@gmail.com     *");
	printf("\n  *                                         *");
	printf("\n  * *************************************** *\n");
	exit(0);
}


/* ***************************
 * Inner function:cd().
 * Change the current directory.
 *
 * ***************************/
 
void cd(char *path){
	if(chdir(path))
		fatal("cd");
}


/* ************************************
 * The function about act.sa_handler
 * If press the Ctrl+c, resume the shell.
 *
 * ************************************/
 
void catchint(int signo){
	printf("\nReceive a signo=%d\n",signo);
	printf("Returning to the shell\n");

	/* Init the cmdline Array.
	 * If not,the shell will try to run 
	 * commands in the memory.
	 */
	cmdline[0]='\0';
}


/* ************************************
 * An easy way to use double pipe.
 *
 * But this function is just for test and   
 * debug in the project,because I wrote  
 * a new one by myself. The new one is 
 * called "join2".
 *
 * ***********************************/

int dpipe_test(){

	/*build command string with normal format.*/

	char newstr[128];
	strcpy(newstr,cmdlist[0]);
	strcat(newstr,"|");
	strcat(newstr,cmdlist[1]);
	strcat(newstr,"|");
	strcat(newstr,cmdlist[2]);
	
	/*call system shell to run the commmands*/
	system(newstr);
	return 0;
}


/* **************************************
 * Delete special character from argument.
 * If there is any special charater,
 * this function will change them to '\32'
 *
 * ***************************************/
 
void parse_filter(char *cmd){
	int i=0;
	int CMAX=strlen(cmd);
	
	while(cmd[i]!=' '&&i<CMAX) i++;
	
	if((++i)<CMAX){
		if (cmd[i++]=='-')	{	
			while(cmd[i]!=' '&&i<CMAX){
			
				if(cmd[i]<'0'||(cmd[i]>'9'&&cmd[i]<'A')||
					(cmd[i]>'Z'&&cmd[i]<'a')||cmd[i]>'z'){

					char tmp=cmd[i-1];			
					cmd[i]=tmp;	
				}
				i++;
			}
		}
	}
	
}

/* ***********************************
 * Link the child process's stdout to
 * grandchild process's stdin with pipe.
 *
 * ***********************************/
 
void join(){
	int p[2],status;

	switch (fork()){
		case -1:fatal("1st fork call in join()");
		case 0:break;
		default:wait(&status);
				return;
	}
	
	/* Try to make a new pipe.*/
	if(pipe(p)==-1) fatal("pipe call in join()");

	switch(fork()){
		case -1:fatal("2nd fork call in join()");
		case 0:
				dup2(p[1],1);
				close(p[0]);
				close(p[1]);
				execute_cmd(cmdlist[0]);
				fatal("1st execvp call in join()");
		default:
				dup2(p[0],0);
				close(p[0]);
				close(p[1]);
				execute_cmd(cmdlist[1]);
				fatal("2nd execvp call in join()");
	}
}



/* *************************************
 * Link three child/grandchild processes 
 * one by one with two pipes.
 *
 * ************************************/

int join2(){
	int status,p1[2],p2[2];
	
	/*Test the double pipe.*/	
	if(dpipe_test()==0) return 0;  

	/* Grandparent process */
	switch(fork()){
		case -1:fatal("1st fork call");
		case 0:break;
		default:
			   wait(&status);
			   return status;
	}


	/* Parent process.Run the last command.*/

	if(pipe(p1)<0) fatal ("pipe call"); /*make a pipe.*/

	switch(fork()){
		case -1:fatal("2nd fork call");
		case 0:break;
		default:
			   dup2(p1[0],0);
			   close(p1[0]);
			   close(p1[1]);

			   execute_cmd(cmdlist[2]);
			   fatal("1st exec call");
	}
	
	/* Try to make a new pipe.*/

	if(pipe(p2)<0) fatal("pipe call"); 

	/* Child process.Run the second command.*/
	
	switch(fork()){
		case -1:fatal("3th fork call");
		case 0:break;
		default:
			   dup2(p1[1],1);
			   dup2(p2[0],0);
			   close(p1[0]);
			   close(p1[1]);
			   close(p2[0]);
			   close(p2[1]);

			   execute_cmd(cmdlist[1]);
			   fatal("2nd exec call");
	}

	/* Grandchild process.Run the first command.*/
	
	dup2(p2[1],1);
	close(p2[0]);
	close(p2[1]);

	execute_cmd(cmdlist[0]);
	fatal("3th exec call");

}

 

Jul 16

    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);
}