程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言基礎知識 >> 全屏幕編輯軟件的編寫(C語言)01

全屏幕編輯軟件的編寫(C語言)01

編輯:C語言基礎知識

這是一個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();                          /* 清提示區 */
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved