這是一個DOS下的全屏幕編輯軟件,整個程序功能齊全,但代碼並不多,可以制表格,打印、搜索、塊復制,有點類似DOS下的WPS。這個程序作為學習C語言編程的參考是很好的,假如能夠仔細閱讀該程序,並加以理解,那麼你的編程能力會有很大提高。
/* BJ.C 全屏幕編輯軟件 (Turbo_C 2.0) */
/* 用 tcc -mc bj 編譯 */
#include <stdio.h>
#include <dir.h>
#include <dos.h>
#include <ctype.h>
#include <alloc.h>
#define BLCK_COLOR 0x1E /* 字塊色彩 */
#define TEXT_COLOR 0x02 /* 文本字符色彩 */
#define PROM_COLOR 0x5F /* 提示及提問行色彩 */
#define CHAR_COLOR 0x03 /* 行末示意符色彩 */
#define HH 24 /* 屏幕最大行坐標 */
#define H1 (HH-1) /* 序號、文件名信息行行坐標 */
#define H2 (HH-2) /* 標尺行行坐標 */
#define H3 (HH-3) /* 編輯文本顯示最下行行坐標 */
#define ZS 76 /* 每行顯示文本的字數 */
#define BP (ZS/2) /* 每次移屏字節數 */
#define FH (ZS+3) /* 行末示意符列坐標 */
#define QB 400 /* 編輯數組可容納的總行數 */
#define Q1 (QB/2) /* 編輯數組中間值 */
#define Q2 (QB*3/5) /* 第一次讀入編輯數組的行數 */
#define Q3 (QB*2/5) /* 每次讀寫臨時文件的行數 */
#define SZ 1000 /* 臨時文件每次讀寫地址數組最大下標 */
#define HC 255 /* 編輯數組每行最大字節數控制值 */
#define KK 32000 /* 字塊允許的最大字節數 */
#define PG ((HH-16)*6) /* 顯示文件目錄時,每頁可顯示目錄數 */
long xx=0; /* 當前行在文本中的絕對行號 */
int yy=0; /* 當前列的文本列號,也是編輯數組列號 */
int ss_max=0; /* 編輯數組實用最大行號 */
int x=0,y=0; /* 當前行在顯示屏幕上的行、列坐標 */
int ss_x=0; /* 當前行在編輯數組中的行號 */
int m=0; /* 左右移屏屏號,首屏為 0 */
int fp_end=0; /* 老文件是否讀完的標志變量 */
int old=1; /* 區別新、老文件的標志變量 */
int ins=0; /* 是否為插入狀態的標志變量 */
int vid=0; /* 區別圖形和字符顯示方式的標志變量 */
int tab=0; /* 中文表格線開關變量 */
int blck=0; /* 是否已定義字塊的標志變量 */
int enq=HC-4; /* 排版行寬,初值設為 HC-4 */
long ksx=-1; /* 塊首行號,未定義塊時置 -1 */
int ksy=-1; /* 塊首列號,未定義塊時置 -1 */
long kwx=-1; /* 塊尾行號,未定義塊時置 -1 */
int kwy=-1; /* 塊尾列號,未定義塊時置 -1 */
long txx,tyy; /* 字塊操作時保存原 xx,yy 坐標的變量 */
int chg=0; /* 文件是否已修改過的標志變量 */
int first=0; /* 字塊中首行長度字節數 */
int oa=0,ob=0; /* 數組 wra[ ] 和 wrb[ ] 的標號變量 */
long wra[SZ],wrb[SZ]; /* 記錄臨時文件讀寫地址的數組 */
long fp_rd; /* fp_rd 為 fp 已讀出行的最大行號 */
long ttl_x=0xFFFFFFFL; /* 文末行行號,先設一大數,fp 全部讀完後,
用已讀出行最大行號 fp_rd 代替 */
long ser=0; /* 當前光標處的字序數 */
long vw=0; /* 臨時存盤時,保存正文文件讀指針的變量 */
long vv=0; /* 讀塊時,存放讀入塊的字節數 */
unsigned char z1,z2,a1,a2; /* 為判斷標點符號設置的變量 */
unsigned char *ss[QB]; /* 編輯緩沖區數組(簡稱編輯數組) */
char *mfile,*bfile; /* 分別存放源文件名和後備文件名 */
char *file1,*file2; /* 分別存放臨時文件 1、2 的文件名 */
char far *mem, far *mmm; /* 長城字符方式顯存基本區和擴展區地址指針 */
char *ddd,*dd; /* ddd 為讀入塊的指針變量,dd 為保存ddd串首的指針 */
char *hsz; /* 提問時輸入字符串的指針變量 */
char *fnd; /* 存放要搜索的字符串 */
char two; /* 存放全角制表符第二字節的字符變量 */
char qq; /* 全角制表符第二字節的標志變量 */
char da[]={0x0D,0x0A,0}; /* 只有硬回車換行符的字符串 */
char ra[]={0x8D,0x0A,0}; /* 只有軟回車換行符的字符串 */
struct ffblk pt[1]; /* 讀文件目錄用的結構 */
union REGS r; /* 中斷調用函數用的聯合 */
union inkey { /* 存放按鍵值的聯合 */
unsigned char ch[2]; /* ch[0] 為高位字節, ch[1] 為低位字節 */
int ii;
} cc;
FILE *fp,*fopen(); /* fp 為老文件 mfile 的文件指針 */
FILE *fp1,*fp2; /* 臨時文件 1、2 的文件指針 */
FILE *fp3; /* 讀入的外部文件和字塊寫盤的文件指針 */
main(int argc,char *argv[]) /* 主控函數 */
{
int i;
clss(0,HH); /* 清全部屏幕 */
mod(); /* 測顯示模式 */
for(i=0;i<QB;i++) { /* 為給編輯數組分配內存建的循環 */
ss[i]=malloc(HC); /* 逐行分配內存空間 */
*ss[i]=0; /* 數組行清為空串 */
}
mfile=malloc(16); /* 為編輯文件名字符串分配內存空間 */
*mfile=0; /* 字符串清為空串 */
if(argc>1) mfile=argv[1]; /* 如進入 BJ 時帶命令行參數,放入 mfile */
filename(); /* 輸入文件名,建臨時文件名,老文件讀入 */
hsz=malloc(HC); /* 為指針變量 hsz 分配內存空間 */
fnd=malloc(HC); /* 為搜索字符串變量分配內存空間 */
disp_t(); /* 顯示編輯屏幕 */
Ins(); /* 置初始狀態為“插入”狀態 */
while(1) { /* 編輯主循環 */
xh(); /* 在信息行顯示當前行、列、序號 */
coord(); /* 在標尺行顯示標尺 */
goto_xy(x,y); /* 定屏幕文本光標位置 */
cc.ii=bioskey(0); /* 將按鍵值讀入一聯合中 */
clear_prompt(); /* 清提示區 */
if(cc.ch[0]) { /* 如果低位字節不為 0 */
switch(cc.ch[0]) { /* 判斷低位字節 */
case 13: Enter(); /* 如為回車鍵,輸入回車鍵操作 */
break; /* 跳出開關語句 */
case 8: Del(); /* 如為退格鍵,刪字操作 */
break; /* 跳出開關語句 */
case 14: Ctrl_N(); /* Ctrl+N 在當前行前插入一空行 */
break; /* 跳出開關語句 */
case 25: Ctrl_Y(1); /* Ctrl+Y 刪除當前行 */
break; /* 跳出開關語句 */
case 20: Ctrl_T(1); /* Ctrl+T 刪至行尾 */
break; /* 跳出開關語句 */
case 5: Ctrl_E(1); /* Ctrl+E 刪至行首 */
break; /* 跳出開關語句 */
case 6: Ctrl_F(1); /* Ctrl+F 移至塊首 */
break; /* 跳出開關語句 */
case 22: Ctrl_V(); /* Ctrl+V 字塊移動 */
break; /* 跳出開關語句 */
case 11: Ctrl_K(); /* Ctrl+K 字塊拷貝 */
break; /* 跳出開關語句 */
case 23: Ctrl_W(); /* Ctrl+W 字塊存盤 */
break; /* 跳出開關語句 */
case 4: Ctrl_D(); /* Ctrl+D 刪除字塊 */
break; /* 跳出開關語句 */
case 16: Ctrl_P(); /* Ctrl+P 打印當前編輯的文本文件 */
break; /* 跳出開關語句 */
case 18: Ctrl_R(); /* Ctrl+R 外部文件插入當前位置 */
break; /* 跳出開關語句 */
case 27: Esc(); /* Esc 鍵 不存盤退出 */
break; /* 跳出開關語句 */
case 3: bk(); /* Ctrl+C 退回 DOS 系統 */
default: Chr(); /* 如為字符鍵,輸入字符 */
}
}
else { /* 如果低位字節為 0 */
switch(cc.ch[1]) { /* 判斷高位字節 */
case 81: PgDn(); /* PgDn 鍵,向下翻屏 */
break; /* 跳出開關語句 */
case 73: PgUp(); /* PgUp 鍵,向上翻屏 */
break; /* 跳出開關語句 */
case 59: F1(1); /* F1 存盤並退出 */
break; /* 跳出開關語句 */
case 84: Shift_F1(); /* Shift+F1,存盤,不退出 */
break; /* 跳出開關語句 */
case 60: F2(); /* F2 移到指定行 */
break; /* 跳出開關語句 */
case 61: F3(); /* F3 輸入格式文件排版行寬 */
break; /* 跳出開關語句 */
case 62: F4(); /* F4 段排版 */
break; /* 跳出開關語句 */
case 87: Shift_F4(); /* Shift+F4 從當前光標行排版至文末 */
break; /* 跳出開關語句 */
case 63: F5(); /* F5 搜索字符串 */
break; /* 跳出開關語句 */
case 88: Shift_F5(); /* Shift+F5 繼續搜索 */
break; /* 跳出開關語句 */
case 64: F6(); /* F6 字符串的替代 */
break; /* 跳出開關語句 */
case 65: F7(); /* F7 定義塊首 */
break; /* 跳出開關語句 */
case 66: F8(); /* F8 定義塊尾 */
break; /* 跳出開關語句 */
case 90: /* Shift+F7 */
case 91: Shift_F7(); /* Shift+F8 取消塊定義 */
break; /* 跳出開關語句 */
case 67: F9(); /* F9 光標移到文首 */
break; /* 跳出開關語句 */
case 92: Shift_F9(); /* Shift+F9 光標移到文末 */
break; /* 跳出開關語句 */
case 68: F10(); /* F10 表格線功能開關 */
break; /* 跳出開關語句 */
case 77: Right(); /* → 鍵 右移光標 */
break; /* 跳出開關語句 */
case 75: Left(); /* ← 鍵 左移光標 */
break; /* 跳出開關語句 */
case 72: Up(); /* ↑ 鍵 上移一行 */
break; /* 跳出開關語句 */
case 80: Down(); /* ↓ 鍵 下移一行 */
break; /* 跳出開關語句 */
case 82: Ins(); /* Ins 插入狀態轉換 */
break; /* 跳出開關語句 */
case 83: Del(); /* Del 同退格鍵 */
break; /* 跳出開關語句 */
case 71: Home(); /* Home 光標移到行首 */
break; /* 跳出開關語句 */
case 79: End(); /* End 光標移到行末 */
break; /* 跳出開關語句 */
}
}
}
}
mark() /* 軟件標志 */
{
int i;
for(i=1;i<8;i++) { /* 顯示一塊彩色 */
write_space(i,2,23,0x10); /* 藍底色 */
if(i!=1) write_string(i,25," ",0x30); /* 右部淺藍色影子 */
}
for(i=4;i<27;i++) write_char(8,i,32,0x30); /* 下部淺藍色影子 */
write_string(3,6,"BJ全屏幕編輯工具",0x1E); /* 顯示軟件名稱 */
write_string(4,10,"Ver1.0",0x1E); /* 顯示版本號 */
write_string(5,9,"沈 建 威",0x1E); /* 顯示設計者姓名 */
}
filename() /* 輸入要編輯的文件名 */
{
int i,k,tatol,page=1; /* tatol 目錄總頁數, page 目錄顯示頁號 */
if(!*mfile) { /* 如未帶命令行參數,mfile 為空串 */
mark(); /* 顯示軟件標志 */
write_string(11,20,"請輸入要編輯的文件名:",0x0A);
tatol=make_dir(); /* 建目錄數組,總頁數放入 tatol */
while(1) { /* 為目錄翻屏設置的循環 */
disp_dir(page); /* 顯示目錄清單 */
write_space(11,42,20,0x0A); /* 用 20 個空格清文件名輸入區屏幕 */
if((k=key_string(11,42,mfile,0x0A))>0) break;/* 輸入文件名,成功跳出循環*/
if(k==-1 || k==0) bk(); /* 如為空串或按 ESC 退出至 DOS 下 */
if(k==-4 && page>1) page--; /* 如按 PgUP,如不在首頁,顯示上頁目錄 */
if(k==-5 && page<tatol) page++; /* 按 PgDn,如不在最後頁,顯示下頁目錄*/
}
}
clss(0,HH); /* 清全部屏幕 */
for(i=0;i<QB;i++) *ss[i]=0; /* 清編輯數組 */
if((fp=fopen(mfile,"rb"))==NULL) { /* 用只讀方式打開文件,如失敗為新文件 */
old=0; /* old=0 為新文件 */
fp_rd=0; /* 已從 fp 中讀入行最大行號置為 0 */
write_string(H1,40,"新",0x05); /* 在信息行提示新文件 */
}
else fp_rd=read_from(0,Q2,fp)-1; /* 如為老文件,讀 Q2 行到編輯數組 */
write_string(H1,42,"文件名:",0x05); /* 在信息行提示 */
write_string(H1,50,mfile,0x07); /* 在信息行顯示文件名 */
if(fp_rd<Q2-1) { /* 如讀入不足 Q2 行, fp 已讀完 */
ttl_x=fp_rd; /* 定文末總行號 */
fp_end=1; /* fp 已讀完標志置 1 */
}
ss_max=fp_rd; /* 定編輯數組實用最大行號 */
f_name(); /* 建輔助文件名 */
}
int make_dir() /* 找當前目錄中合適的文件名記入數組 */
{
int i=0;
if(findfirst("*.*",pt,0)==0 && compare()) /* 尋找第一個文件名並比較 */
strcpy(ss[i++],pt[0].ff_name); /* 如不是要忽略的文件,將它賦給數組 */
while(findnext(pt)==0) { /* 為繼續找文件設的循環 */
if(compare()) /* 比較找到的文件名 */
strcpy(ss[i++],pt[0].ff_name); /* 如比較為真,記入數組 */
}
return (i-1)/PG+1; /* 返回可供顯示頁數 */
}
int compare() /* 如擴展名為 EXE 等可忽略的文件名,返回 0,否則返回 1 */
{
if(strstr(pt[0].ff_name,".EXE") || strstr(pt[0].ff_name,".COM")
|| strstr(pt[0].ff_name,".OV") || strstr(pt[0].ff_name,".OBJ")
|| strstr(pt[0].ff_name,".LIB") || strstr(pt[0].ff_name,".BAK")
|| strstr(pt[0].ff_name,".FOX") || strstr(pt[0].ff_name,".DBF")
|| strstr(pt[0].ff_name,".IDX"))
return 0;
return 1;
}
disp_dir(int a) /* 顯示目錄,a 為頁號 */
{
int i=16,j=1,k; /* i 為行坐標,j 為列坐標 */
for(k=0;k<80;k++)
write_char(14,k,'_',TEXT_COLOR); /* 在屏幕第 14 行畫一橫線,區分目錄區 */
clss(15,HH); /* 清目錄顯示區 */
k=(a-1)*PG; /* 根據頁號確定數組顯示的起始項 */
while(k<a*PG) { /* 為顯示一頁建的循環 */
write_string(i,j,ss[k++],0x0E); /* 顯示一個文件名 */
j+=13; /* 右移 13 列 */
if(j>67) { /* 如列號大於 67 */
++i; /* 下移一行 */
j=1; /* 列號置 1 */
}
}
}
f_name() /* 建臨時文件和後備文件名 */
{
int i;
bfile=malloc(16); /* 為後備文件名字符串分配內存空間 */
file1=malloc(16); /* 為臨時文件名字符串分配內存空間 */
file2=malloc(16); /* 為臨時文件名字符串分配內存空間 */
for(i=0;*(mfile+i)!='.' && *(mfile+i);i++) *(bfile+i)=*(mfile+i);
/* 截取文件名“.”前的部分,放入 bfile */
*(bfile+i)=0; /* bfile 字符串以 '\0' 結尾 */
strcpy(file1,bfile); /* bfile 中字符串拷入 file1 */
strcpy(file2,bfile); /* bfile 中字符串拷入 file2 */
strcat(bfile,".BAK"); /* bfile 加後綴.BAK */
strcat(file1,".$1$"); /* 臨時文件 1 加後綴.$1$ */
strcat(file2,".$2$"); /* 臨時文件 2 加後綴.$2$ */
fp1=fopen(file1,"wb+"); /* 打開臨時文件 1 */
fp2=fopen(file2,"wb+"); /* 打開臨時文件 2 */
}
bk() /* 退出運行,至 DOS 下 */
{
fcloseall(); /* 關閉所有打開的文件 */
remove(file1); /* 刪除臨時文件 1 */
remove(file2); /* 刪除臨時文件 2 */
clss(0,HH); /* 清屏 */
goto_xy(0,0); /* 光標置屏幕左上角 */
exit(0); /* 退出運行 */
}
write_prompt(char a) /* 在屏幕提示區顯示提示,a 為提示項數組下標 */
{
char *prom[]= { /* 存放提示的數組 */
"請稍候.....",
"請先定義塊!",
"塊太大!",
"行寬超過250!",
"必須輸入數字!",
"只允許輸入 Y 或 N!",
"文件未找到!",
"排版超寬!",
"未設定排版寬度!"
};
int g;
g=80-strlen(prom[a]); /* 顯示起始列 */
if(a) putchar(7); /* 除第一項提示外,其余各項響鈴警告 */
write_string(HH,g,prom[a],PROM_COLOR); /* 在提示區顯示提示 */
}
write_ques(char a) /* 在屏幕提問區顯示提問,a 為提問項數組下標 */
{
char *ques[]= { /* 存放提問的數組 */
"是否放棄並退出編輯?(Y/N) ",
"請輸入字塊存盤的文件名: ",
"已有同名文件,是否復蓋?(Y/N) ",
"請輸入要插入的文件名: ",
"請輸入排版行寬: ",
"請輸入要找的字符串: ",
"請輸入要移到的行號: ",
"尋找: 換成: 換否? ",
"請輸入每頁打印的行數: ",
"打印機未准備好,請准備好打印機,按任一鍵繼續。",
"請調好打印紙,按任一鍵開始打印。",
"正在打印.....",
"請輸入頁號打印列號: ",
"請輸入起始頁號: "
};
clear_ques(); /* 清提問區 */
write_string(HH,0,ques[a],PROM_COLOR); /* 在提問區顯示提問 */
}
clear_prompt() /* 清提示區 */
{
write_space(HH,60,20,TEXT_COLOR); /* 用空格復蓋提示區 */
}
clear_ques() /* 清提問區 */
{
write_space(HH,0,60,TEXT_COLOR); /* 用空格復蓋提問區 */
}
int read_from(int a,int b,FILE *f) /* 從文件 f 讀入 b 行放入數組的第 a 行起 */
{
int i,j;
write_prompt(0); /* 提示“請稍候...” */
for(i=a;i<a+b;i++) { /* 為逐行讀出設的循環 */
if(fgets(ss[i],HC,f)==NULL) { /* 從 f 讀出一行,如已超出文末 */
j=0; /* j 置初值 */
while(ss[i-1][j]) { /* 檢查文末行各字節 */
if(ss[i-1][j]==0x1A) { /* 文件結束符用 '\0' 替代 */
ss[i-1][j]=0;
break;
}
j++; /* 下移一字節 */
}
break; /* 跳出 for 循環 */
}
}
clear_prompt(); /* 清提示區 */
return i-a; /* 返回讀出行數 */
}
write_to(int a,int b,FILE *f) /* 把編輯數組第 a 行起的 b 行寫入文件 f */
{
int i;
write_prompt(0); /* 提示“請稍候...” */
for(i=a;i<a+b;i++) fputs(ss[i],f); /* 逐行將字符串寫入文件 f */
clear_prompt(); /* 清提示區 */
}