25、数据结构笔记之二十五串应用之文本编辑
“正如恶劣的品质可以在幸运中暴露一样,最美好的品质也是在厄运中被显示的。 -- 培根”
由于前段时间一直出差在外,间断了半个月,今天开始继续学习数据结构。
1. 文本编辑
本文编辑程序是一个面向用户的系统服务程序,广泛用于源程序的输入和修改,甚至用于报刊和书籍的编辑排版以及办公室的公文书信的起草和润色。
一般包括串的查找、插入和删除等基本操作。
对用户来讲,一个文本(文件)可以包括若干页,每页包括若干行,每行包括若干文字。
对文本编辑程序来讲,可把整个文本看成一个长字符串,称文本串,页是文本串的子串,行又是页的子串。为简化程序复杂程度,可简单地把文本分成若干行。
例:下面的一段源程序可以看成一个文本串,
main(){ float a,b,max; scanf("%f,%f",&a,&b); if (a>b) max=a; else max=b; }; |
这个文本串在内存中的存储映像可为:
m | a | i | n | ( | ) | { | \n |
|
| f | l | o | a | t |
| a | , | b | , |
m | a | x | ; | \n |
|
| s | c | a | n | f | ( | " | % | f | , | % | f | " |
, | & | a | , | & | b | ) | ; | \n |
|
| i | f |
| a | > | b |
|
| m |
a | x | = | a | ; | \n |
|
| e | l | s | e |
|
| m | a | x | = | b | ; |
\n | } | \n |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在编辑时,为指示当前编辑位置,程序中要设立页指针、行指针、字符指针,分别指示当前页,当前行,当前字符。因此程序中要设立页表、行表便于查找。
在编辑时,为指示当前编辑位置,程序中要设立页指针、行指针、字符指针,分别指示当前页,当前行,当前字符。因此程序中要设立页表、行表便于查找。
以上内容摘自严蔚敏老师的《数据结构C语言版》
2. 代码实现
2.1 定义结构体
定义一个结构体,每个结构体表示一行,文本的字符串也是以行的形式存放的。
typedefstructLINE {
chartext[szLINE]; /*文本内容*/
structLINE *next; /*链表指针*/
} L;
其他定义为方便编程如
typedefunsignedintU;
一行最长的字节
#defineszLINE252
文本编辑器命令数量
#defineCMDS12
定义行编辑命令的标准格式
typedefvoid(*FUNC)(L**, char*);
2.2 定义编辑命令
就像我们使用VI或者EMAC一样,必须要有类似w,q,x这样的命令的,我们也需要定义这样的一些命令。
定义编辑命令函数的数组如下:
FUNC functions[CMDS]={
exec_quit,exec_help, exec_load, exec_save,
exec_view,exec_count, exec_append, exec_insert,
exec_erase,exec_edit, exec_lookup, exec_replace
};/*endfunctions*/
2.2.1 exec_quit
退出程序。
void exec_quit(L** lines, char *line){exit(0);}
2.2.2 exec_replace
执行文本替换命令
void exec_replace(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = "",key[szLINE]="";
/*从命令行提取新旧关键字*/
sscanf(line, "%s%s %s", cmd, key, text);
/*执行文本替换命令*/
replace(*lines,key, text);
}/*end replace*/
2.2.3 exec_edit
执行文本编辑命令
void exec_edit(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = ""; Uindex = 0;
/*从命令行提取目标行号*/
sscanf(line, "%s%d", cmd, &index);
/*在命令之后另起新行用于录入文本*/
gets(text);strcat(text, "\n");
/*执行文本编辑命令*/
edit(*lines,text, index);
}/*end edit*/
2.2.4 exec_load
执行加载文本文件命令
void exec_load(L** lines, char *line)
{
charcmd[szLINE] = "",file[szLINE] = "";
/*分析命令行,提取文件名*/
sscanf(line, "%s%s", cmd, file);
/*执行加载命令*/
load(lines,file);
}/*end exec_load*/
2.2.5 exec_save
执行文本保存命令
void exec_save(L** lines, char *line)
{
charcmd[szLINE] = "",file[szLINE] = "";
/*分析命令行,提取文件名*/
sscanf(line, "%s%s", cmd, file);
/*执行保存命令*/
save(*lines,file);
}/*end exec_save*/
2.2.6 exec_view
执行文本查看命令
void exec_view(L** lines, char *line)
{
charcmd[szLINE] = ""; Ufrom = 0, to = 0;
/*分析命令行,提取目标要查看的起始行号和终止行号*/
sscanf(line, "%s%u %u", cmd, &from, &to);
/*如果起始行号和终止行号大小相反,则根据起始行号显示一页*/
if(to< from) to = from + 24;
/*执行查看命令*/
view(*lines, stdout,from, to);
}/*end exec_view*/
2.2.7 exec_account
执行行数统计命令
void exec_count(L** lines, char *line)
{
fprintf(stderr, "%dlines in mem.\n", view(*lines, 0, 0,0));
}/*end count*/
2.2.8 exec_append
执行文本追加命令
void exec_append(L** lines, char *line)
{
chartext[szLINE] = "";
/*在命令之后另起新行用于录入文本*/
gets(text);strcat(text, "\n");
/*执行文本追加命令*/
insert(lines,text, -1);
}/*end exec_append*/
2.2.9 exec_Insert
执行文本插入命令
void exec_insert(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = ""; Uindex = 0;
/*从命令行提取目标插入点的行号*/
sscanf(line, "%s%d", cmd, &index);
/*在命令之后另起新行用于录入文本*/
gets(text);strcat(text, "\n");
/*执行文本插入命令*/
insert(lines,text, index);
}/*end insert*/
2.2.10 exec_erase
执行文本删除命令
void exec_erase(L** lines, char *line)
{
charcmd[szLINE] = ""; Uindex = 0;
/*从命令行提取目标行号*/
sscanf(line, "%s%d", cmd, &index);
/*执行文本删除命令*/
erase(lines,index);
}/*end erase*/
2.2.11 exec_lookup
执行文本检索命令
void exec_lookup(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = "";
/*从命令行提取关键字*/
sscanf(line, "%s%s", cmd, text);
/*执行文本检索命令*/
lookup(*lines,text);
}/*end lookup*/
2.2.12 exec_help
执行在线帮助命令
void exec_help(L** lines, char *line)
{printf("\tcommands:\n\thelp\n\tquit\n\
\tload [file.txt]\n\
\tsave [file.txt]\n\
\tview [from line] [to line]\n\
\tcount\n\
\tappend [return + text]\n\
\tinsert [line number] [return + text]\n\
\terase [line number]\n\
\tedit [line number] [return + text]\n\
\tlookup [text]\n\
\treplace [keyword] [replacement]\n");
}/*end help*/
2.3 其他函数
这里的函数很多是直接被编辑命令调用的。
2.3.1 identified
该函数实现行字符串中的关键字识别。有两个参数,第一个参数是行字符串指针,第二个参数是一个编辑命令的字符串指针。然后通过memcmp函数来比较两个字符串是否相等,相等返回0.
int identified(char *command, char *key)
{
intln = 0, r = 0;
if(!command|| !key) return0;
ln = strlen(key);
r = memcmp(command, key,ln);
returnr==0;
}
2.3.2 save
将链表保存到指定的文本文件
int save(L *lines, char *file)
{
FILE *f = 0; L * t = lines;
inttotal = 0;
if(!lines|| !file) return0;
/*打开文件*/
f = fopen(file, "w");
if(!f){
fprintf(stderr, "%sis bad.\n", file);
return0;
}/*endif*/
t = lines;
while(t){/*逐个文件写入*/
fprintf(f, "%s",t->text );
t =t->next ;
total ++;
}/*endwhile*/
fclose(f);
fprintf(stderr, "[%s]%d lines saved.\n", file,total);
/*返回总行数*/
returntotal;
}/*save*/
2.3.3 load
将文件整个装入链表。
int load(L** lines, char *file)
{
FILE *f = 0; char line[szLINE]="";
inttotal = 0;
if(!lines|| !file) return0;
clear(lines);/*首先清空链表*/
/*打开文件*/
f = fopen(file, "r");
if(!f){
fprintf(stderr, "%sis bad.\n", file);
return0;
}/*endif*/
/*逐行读入内存并插入表尾*/
while(!feof(f)){
memset(line,0, szLINE);
fgets(line, szLINE -1, f);
insert(lines,line, -1);
total ++;
}/*endwhile*/
fclose(f);
fprintf(stderr, "[%s]%d lines loaded.\n", file,total);
/*返回总行数*/
returntotal;
}/*end load*/
2.3.4 edit
根据行号和新录入文本替换原有行
void edit(L *lines, char *line, Uindex)
{
L *t = locate(lines, index-1);
if(!t)return ;
if(line)strcpy(t->text , line);
}/*end edit*/
2.3.5 erase
根据行号删除一行文本。
Lines是整个文本的指针。Index是需要删除的行号。
void erase(L** lines, Uindex)
{
L *a = 0, * b = 0, * c = 0;
if(!lines) return ;
/*index-1 表示目标行,index-2表示目标行的前一行*/
a = locate(*lines, index-2);
b = locate(*lines, index-1);
if(!b)return ;
if(a)/*如果前一行存在则删除目标行*/
a->next =b->next;
else/*否则表示表头删除*/
*lines =b->next ;
/*endif*/
/*释放内存*/
free(b);
}/*end erase*/
2.3.6 insert
根据行号插入一行新文本,如果行号小于零则将文本追加至链表尾。
临时变量s 开始指向文本开始。T为新增加文本。Index是需要增加到的行所在位置。
void insert(L** lines, char *line, intindex)
{
L *t = 0, * s = 0; int i = 0;
if(!lines|| !line) return ;
/*首先为新文本分配一个链表节点*/
t = (L*)malloc(sizeof(L));
memset(t, 0, sizeof(L));
strcpy(t->text , line);
if(index== 0 || !*lines) {/*如果链表为空则以新节点为起点定义链表*/
t->next =*lines;
*lines =t;
return ;
}/*endif*/
s = *lines;
if(index> 0)/*如果行号为正整数,则将链表指针指向行号之前*/
for(i= 0; i < index-2; i++) {
if(!s->next) break;
s =s->next ;
}/*next*/
else/*否则链表指针指向表尾*/
while(s->next) s = s->next ;
/*endif*/
/*完成链表插入操作*/
if(s->next) t->next = s->next ;
s->next = t;
}
2.3.7 replace
全文替换,会调用rpc函数。
void replace(L *lines, char *string, char *replacement)
{
L *t = 0; U index = 0;
if(!string|| !lines || !replacement) return ;
t = lines;
while(t){
index ++;
if(strstr(t->text, string)) {
printf("[BEFORE]%d: %s", index, t->text );
rpc(t->text, string, replacement);
printf("[AFTER] %d: %s", index, t->text );
}/*endif*/
t=t->next;
}/*endwhile*/
}/*end replace*/
2.3.8 rpc
在一行文本中执行替换命令,把所有关键字替换为新关键字。
参数string为行字符串
参数key为旧关键词
参数replacement为新关键词,用于替换就关键词。
这个函数比较长,开始将string的地址赋给x,然后在内存中开辟一个空间分配给fine,在赋值给y。对比过程就是x与y进行,不断自增。中间如果匹配则通过y指针直接操作fine的空间,最后将fine空间赋值给x,起到替换效果。
void rpc(char *string, char *key, char *replacement)
{
charfine[szLINE], * x = 0, * y = 0, * z = 0;
intla = 0, lb = 0, r = 0;
if(!string|| !key || !replacement) return ;
memset(fine,0, szLINE);
x = string;y = fine;
/*首先记录新旧关键字长度*/
la = strlen(key);
lb = strlen(replacement);
do {
/*用指针逐个比较*/
r =memcmp(x, key, la);
if(r){/*如果关键字不匹配则复制字符串*/
*y = *x;
x++; y++;
}else{/*如果关键字匹配则替换字符串*/
memcpy(y, replacement,lb);
x += la; y+= lb;
}/*endif*/
}while(*x);
/*将替换完成的结果返回*/
memcpy(string,fine, szLINE);
}/*end rpc*/
2.3.9 lookup
在当前文档中根据关键字进行搜索,并将搜索结果打印出来。
打印行数和该行的字符串。
void lookup(L *lines, char *string)
{
L *t = 0; U index = 0;
if(!string) return ;
t = lines;
while(t){
index ++;
if(strstr(t->text, string)) printf("%d:%s", index, t->text );
t=t->next;
}/*endwhile*/
}/*end lookup*/
2.3.10 view
浏览命令,如果f存在则以带行号格式保存文件(如果f==stdout则打印到屏幕上),
浏览范围为from到to(行号)。view(lines, 0, 0, 0)表示统计已加载到内存的文本行数量
int view(L *lines, FILE *f, Ufrom, Uto)
{
L *t = lines; Uindex = 0;
while(t){
index ++;
if(f&& index >= from&& index <= to) fprintf(f, "%d:%s", index, t->text);
t =t->next;
}/*endwhile*/
returnindex;
}/*end view*/
2.3.11 locate
在链表中根据行号index调出指定的行,如果行为空说明文本文件为空,则返回。如果index大于当前最大的行则返回当前最后一行。
L * locate(L *lines, Uindex)
{
L *t = lines; U i= 0;
if(!t)return0;
if(index== 0) return t;
for(i= 0; i < index; i++) {
t =t->next;
if(!t)return0;
}/*next*/
returnt;
}/*end locate*/
2.3.12 clear
clear命令,清空整个行链表,就以为这清空了整个文件,是不是很快捷,类似VI中的dG命令。借用了两个局部变量*a,*b.
/*清空链表操作*/
void clear(L** lines)
{
L *a = 0, * b = 0;
if(!lines) return ;
a = *lines;
while(a){
b =a->next ;
free(a);
a = b;
}/*endwhile*/
*lines =0;
}/*end clear*/
2.4 Main函数
输入欢迎信息,然后根据函数是否带参数进行处理。
如果带参数则进行相应处理。可以是—help参数或者/h则输出帮助并退出,如果不是则尝试加载文本。
如果没有参数则进行主循环,每次先输出当前共有几行(通过views函数来实现)。
然后通过memset函数进行申请的内存做初始化工作, 其返回值为指向行的指针。然后通过gets函数来获取输入。其中需要根据命令行扫描关键词代码表,根据代码表取得执行函数的地址,再根据执行函数地址调用行编辑命令,以此往复,直到输入quit命令,然后程序调用quit函数退出。
int main(intargc, char *argv[])
{
L *lines = NULL; charline[szLINE]=""; int a= 0, b = 0, i = 0; FUNC fun = 0;
printf("Welcometo TEXT EDITOR\nplease input [help] for help.\n");
if(argc> 1) {
a = strcmp(argv[1],"--help");
b = strcmp(argv[1],"/h");
if(a&& b)
load(&lines, argv[1]);
else{
exec_help(0, 0);
return0;
}
}
/*主命令循环*/
for(;;){
printf("\n<%d>",view(lines, 0, 0, 0));
memset(line,0, szLINE);
gets(line);
/*根据命令行扫描关键词代码表,根据代码表取得执行函数的地址,再根据执行函数地址调用行编辑命令*/
for(i= 0; i < CMDS; i++) {
if(identified(line,keywords[i])) {
fun =functions[i];
(*fun)(&lines, line);
break;
}
}
}
return0;
}/*end main*/
执行如下图1:
3. 源码
#include<stdio.h>/*标准文件流操作,这里使用了fopen/fclose/fprintf/printf/scanf/gets函数*/
#include<stdlib.h>/*标准系统库,这里使用了malloc/free/exit*/
#include<string.h>/*标准字符串库,这里使用strlen/strcpy/memcpy/memset*/
#defineszLINE252 /*定义一行字符串最长为252字节*/
#defineCMDS12 /*定义12个标准行编辑命令*/
/*采用链表存储文本*/
typedefstructLINE {
chartext[szLINE]; /*文本内容*/
structLINE *next; /*链表指针*/
} L;
typedefunsignedintU;
/*定义12个行编辑命令的标准格式*/
typedefvoid(*FUNC)(L**, char*);
/*定义12个标准行编辑命令的关键字*/
char keywords[CMDS][8]={
"quit", "help", "load", "save",
"view", "count", "append", "insert",
"erase", "edit", "lookup", "replace"
};/*end keywords*/
/*清空链表操作*/
void clear(L** lines)
{
L *a = 0, * b = 0;
if(!lines) return ;
a = *lines;
while(a){
b =a->next ;
free(a);
a = b;
}/*endwhile*/
*lines =0;
}/*end clear*/
/*在链表中根据行号index调出指定的行*/
L * locate(L *lines, Uindex)
{
L *t = lines; U i= 0;
if(!t)return0;
if(index== 0) return t;
for(i= 0; i < index; i++) {
t =t->next;
if(!t)return0;
}/*next*/
returnt;
}/*end locate*/
/*浏览命令,如果f存在则以带行号格式保存文件(如果f==stdout则打印到屏幕上),
浏览范围为from到to(行号)。view(lines,0, 0, 0)表示统计已加载到内存的文本行数量*/
int view(L *lines, FILE *f, Ufrom, Uto)
{
L *t = lines; Uindex = 0;
while(t){
index ++;
if(f&& index >= from&& index <= to) fprintf(f, "%d:%s", index, t->text);
t =t->next;
}/*endwhile*/
returnindex;
}/*end view*/
/*在当前文档中根据关键字进行搜索,并将搜索结果打印出来*/
void lookup(L *lines, char *string)
{
L *t = 0; U index = 0;
if(!string) return ;
t = lines;
while(t){
index ++;
if(strstr(t->text, string)) printf("%d:%s", index, t->text );
t=t->next;
}/*endwhile*/
}/*end lookup*/
/*在一行文本中执行替换命令,把所有关键字替换为新关键字*/
void rpc(char *string, char *key, char *replacement)
{
charfine[szLINE], * x = 0, * y = 0, * z = 0;
intla = 0, lb = 0, r = 0;
if(!string|| !key || !replacement) return ;
memset(fine,0, szLINE);
x = string;y = fine;
/*首先记录新旧关键字长度*/
la = strlen(key);
lb = strlen(replacement);
do {
/*用指针逐个比较*/
r =memcmp(x, key, la);
if(r){/*如果关键字不匹配则复制字符串*/
*y = *x;
x++; y++;
}else{/*如果关键字匹配则替换字符串*/
memcpy(y, replacement,lb);
x += la; y+= lb;
}/*endif*/
}while(*x);
/*将替换完成的结果返回*/
memcpy(string,fine, szLINE);
}/*end rpc*/
/*全文替换*/
void replace(L *lines, char *string, char *replacement)
{
L *t = 0; U index = 0;
if(!string|| !lines || !replacement) return ;
t = lines;
while(t){
index ++;
if(strstr(t->text, string)) {
printf("[BEFORE]%d: %s", index, t->text );
rpc(t->text, string, replacement);
printf("[AFTER] %d: %s", index, t->text );
}/*endif*/
t=t->next;
}/*endwhile*/
}/*end replace*/
/*根据行号插入一行新文本,如果行号小于零则将文本追加至链表尾*/
void insert(L** lines, char *line, intindex)
{
L *t = 0, * s = 0; int i = 0;
if(!lines|| !line) return ;
/*首先为新文本分配一个链表节点*/
t = (L*)malloc(sizeof(L));
memset(t, 0, sizeof(L));
strcpy(t->text , line);
if(index== 0 || !*lines) {/*如果链表为空则以新节点为起点定义链表*/
t->next =*lines;
*lines =t;
return ;
}/*endif*/
s = *lines;
if(index> 0)/*如果行号为正整数,则将链表指针指向行号之前*/
for(i= 0; i < index-2; i++) {
if(!s->next) break;
s =s->next ;
}/*next*/
else/*否则链表指针指向表尾*/
while(s->next) s = s->next ;
/*endif*/
/*完成链表插入操作*/
if(s->next) t->next = s->next ;
s->next =t;
}/*end insert*/
/*根据行号删除一行文本*/
void erase(L** lines, Uindex)
{
L *a = 0, * b = 0, * c = 0;
if(!lines) return ;
/*index-1 表示目标行,index-2表示目标行的前一行*/
a = locate(*lines, index-2);
b = locate(*lines, index-1);
if(!b)return ;
if(a)/*如果前一行存在则删除目标行*/
a->next =b->next;
else/*否则表示表头删除*/
*lines =b->next ;
/*endif*/
/*释放内存*/
free(b);
}/*end erase*/
/*根据行号和新录入文本替换原有行*/
void edit(L *lines, char *line, Uindex)
{
L *t = locate(lines, index-1);
if(!t)return ;
if(line)strcpy(t->text , line);
}/*end edit*/
/*将文件整个装入链表*/
int load(L** lines, char *file)
{
FILE *f = 0; char line[szLINE]="";
inttotal = 0;
if(!lines|| !file) return0;
clear(lines);/*首先清空链表*/
/*打开文件*/
f = fopen(file, "r");
if(!f){
fprintf(stderr, "%sis bad.\n", file);
return0;
}/*endif*/
/*逐行读入内存并插入表尾*/
while(!feof(f)){
memset(line,0, szLINE);
fgets(line, szLINE -1, f);
insert(lines,line, -1);
total ++;
}/*endwhile*/
fclose(f);
fprintf(stderr, "[%s]%d lines loaded.\n", file,total);
/*返回总行数*/
returntotal;
}/*end load*/
/*将链表保存到指定的文本文件*/
int save(L *lines, char *file)
{
FILE *f = 0; L * t = lines;
inttotal = 0;
if(!lines|| !file) return0;
/*打开文件*/
f = fopen(file, "w");
if(!f){
fprintf(stderr, "%sis bad.\n", file);
return0;
}/*endif*/
t = lines;
while(t){/*逐个文件写入*/
fprintf(f, "%s",t->text );
t =t->next ;
total ++;
}/*endwhile*/
fclose(f);
fprintf(stderr, "[%s]%d lines saved.\n", file,total);
/*返回总行数*/
returntotal;
}/*save*/
/*执行加载文本文件命令*/
void exec_load(L** lines, char *line)
{
charcmd[szLINE] = "",file[szLINE] = "";
/*分析命令行,提取文件名*/
sscanf(line, "%s%s", cmd, file);
/*执行加载命令*/
load(lines,file);
}/*end exec_load*/
/*执行文本保存命令*/
void exec_save(L** lines, char *line)
{
charcmd[szLINE] = "",file[szLINE] = "";
/*分析命令行,提取文件名*/
sscanf(line, "%s%s", cmd, file);
/*执行保存命令*/
save(*lines,file);
}/*end exec_save*/
/*执行文本查看命令*/
void exec_view(L** lines, char *line)
{
charcmd[szLINE] = ""; Ufrom = 0, to = 0;
/*分析命令行,提取目标要查看的起始行号和终止行号*/
sscanf(line, "%s%u %u", cmd, &from, &to);
/*如果起始行号和终止行号大小相反,则根据起始行号显示一页*/
if(to< from) to = from + 24;
/*执行查看命令*/
view(*lines, stdout,from, to);
}/*end exec_view*/
/*执行行数统计命令*/
void exec_count(L** lines, char *line)
{
fprintf(stderr, "%dlines in mem.\n", view(*lines, 0, 0,0));
}/*end count*/
/*执行文本追加命令*/
void exec_append(L** lines, char *line)
{
chartext[szLINE] = "";
/*在命令之后另起新行用于录入文本*/
gets(text);strcat(text, "\n");
/*执行文本追加命令*/
insert(lines,text, -1);
}/*end exec_append*/
/*执行文本插入命令*/
void exec_insert(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = ""; Uindex = 0;
/*从命令行提取目标插入点的行号*/
sscanf(line, "%s%d", cmd, &index);
/*在命令之后另起新行用于录入文本*/
gets(text);strcat(text, "\n");
/*执行文本插入命令*/
insert(lines,text, index);
}/*end insert*/
/*执行文本删除命令*/
void exec_erase(L** lines, char *line)
{
charcmd[szLINE] = ""; Uindex = 0;
/*从命令行提取目标行号*/
sscanf(line, "%s%d", cmd, &index);
/*执行文本删除命令*/
erase(lines,index);
}/*end erase*/
/*执行文本编辑命令*/
void exec_edit(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = ""; Uindex = 0;
/*从命令行提取目标行号*/
sscanf(line, "%s%d", cmd, &index);
/*在命令之后另起新行用于录入文本*/
gets(text);strcat(text, "\n");
/*执行文本编辑命令*/
edit(*lines,text, index);
}/*end edit*/
/*执行文本检索命令*/
void exec_lookup(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = "";
/*从命令行提取关键字*/
sscanf(line, "%s%s", cmd, text);
/*执行文本检索命令*/
lookup(*lines,text);
}/*end lookup*/
/*执行在线帮助命令*/
void exec_help(L** lines, char *line)
{printf("\tcommands:\n\thelp\n\tquit\n\
\tload [file.txt]\n\
\tsave [file.txt]\n\
\tview [from line] [to line]\n\
\tcount\n\
\tappend [return + text]\n\
\tinsert [line number] [return + text]\n\
\terase [line number]\n\
\tedit [line number] [return + text]\n\
\tlookup [text]\n\
\treplace [keyword] [replacement]\n");
}/*end help*/
/*执行文本替换命令*/
void exec_replace(L** lines, char *line)
{
charcmd[szLINE] = "",text[szLINE] = "",key[szLINE]="";
/*从命令行提取新旧关键字*/
sscanf(line, "%s%s %s", cmd, key, text);
/*执行文本替换命令*/
replace(*lines,key, text);
}/*end replace*/
/*执行退出命令*/
void exec_quit(L** lines, char *line){exit(0);}
/*行编辑命令执行函数,顺序与关键字表keywords一一对应*/
FUNC functions[CMDS]={
exec_quit,exec_help, exec_load, exec_save,
exec_view,exec_count, exec_append, exec_insert,
exec_erase,exec_edit, exec_lookup, exec_replace
};/*end functions*/
/*从行输入中识别关键字,相当于parse*/
int identified(char *command, char *key)
{
intln = 0, r = 0;
if(!command|| !key) return0;
ln = strlen(key);
r = memcmp(command, key,ln);
returnr==0;
}/*end identified*/
/*主函数*/
int main(intargc, char *argv[])
{
L *lines = NULL; charline[szLINE]=""; int a= 0, b = 0, i = 0; FUNC fun = 0;
/*打印欢迎信息*/
printf("Welcometo TEXT EDITOR\nplease input [help] for help.\n");
/*如果带主函数带参数,则可以用于打印帮助,或者根据该参数加载一个文本文件*/
if(argc> 1) {
a = strcmp(argv[1],"--help");
b = strcmp(argv[1],"/h");
if(a&& b)
load(&lines, argv[1]);
else{
exec_help(0, 0);
return0;
}/*endif*/
}/*endif*/
/*主命令循环*/
for(;;){
/*命令提示符中间是表示当前载入的文档总共有多少行的意思*/
printf("\n<%d>",view(lines, 0, 0, 0));
/*从键盘输入一个命令行*/
memset(line,0, szLINE);
gets(line);
/*根据命令行扫描关键词代码表,根据代码表取得执行函数的地址,再根据执行函数地址调用行编辑命令*/
for(i= 0; i < CMDS; i++) {
if(identified(line,keywords[i])) {
fun =functions[i];
(*fun)(&lines, line);
break;
}/*endif*/
}/*next*/
}/*next*/
return0;
}/*end main*/