c语言实现more命令简单功能
 
程序功能简述
        利用linux下的curses库,用c语言实现了linux环境下的more命令的功能子集,能够在24*80的终端(窗口)屏幕全屏翻屏。
        键入mmore filename 后(mMore.c源文件编译成可执行文件mmore),mmore先初始化自己的窗口,然后分屏显示文件内容。
        键盘按键:
                n/N往下翻屏(无需回车,直接接收,屏幕不显示所按键对应字符)
                b/B 往回翻屏(无需回车,直接接收,屏幕不显示所按键对应字符)
                q/Q 退出more并关闭窗口,回到终端。(无需回车,直接接收,屏幕不显示所按键对应字符)
 
编程要点
       1.需要知道curses库中常用函数,会使用这些函数。
       2.文件需要读到缓冲(buffer)中,以方便频繁换屏显示时读取所需内容。
       3.建立数据结构,存储每屏显示开始点在buffer中的确切位置,当需显示该屏内容时,及时找到起始点读取并显示。
       4.处理长于80byie的行恰好位于前后两屏显示的中间时的情况。(比如一行有90字节,则前80字节在一屏结束行显示,后10字节在接下去一屏的开始行显示。)
       5.编译时不要忘记连接ncurses库。(我用:gcc mMore.c –o mmore –l ncurses)
 
实现结果
程序流程图

(附)程序代码


///////////////////////////////

///more 功能的c语言实现

///02101231 Gary

///

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <curses.h>

 

#define SCREEN_LINES 22     //show (0->SCREEN_LINES)SCREEN_LINES+1 lines

int getoneline(char * a);   //得到一行的长度

 

int main(int argc, char * argv[])

{

     FILE *fp;

     char filename[20];

     long filelength, pointer;

     char *buffer;          //文件缓冲

     char CLine[512], key;

     int linenum, curline;

     int i,len, *points,p;

     int curX,curY, preY;        //光标在屏幕中的坐标(Y为行,X为列)

 

     if(argc < 2)

     {

         fprintf(stderr, "usage: %s filename\n",argv[0]);

         exit(1);

     }

 

     strcpy(filename, argv[1]);

 

     if((fp = fopen(filename, "r")) == NULL)   //打开文件

     {

         fprintf(stderr,"file %s can not be opened!\n", filename);

         exit(2);

     }

 

     filelength = 0L;

     fseek(fp, 0L, SEEK_END);

     filelength = ftell(fp);              //得到文件长度

 

     if((buffer = (char*)malloc(filelength+1)) == NULL)

     {

         fprintf(stderr,"not enough memery for store the file!\n");

         exit(3);

     }

 

     memset(buffer,0×00,filelength+1);

 

     fseek(fp, 0l, SEEK_SET);

 

     linenum = 0;

     pointer = 0L;

 

     while(!feof(fp))   //文件进缓冲

     {

         memset(CLine,0×00,512);

         fgets(CLine,512,fp);        //Cline 可能越界,不过前面memset0了,因该可以。

         len = strlen(CLine);

         strncat(buffer + pointer, CLine, strlen(CLine));

         pointer += strlen(CLine);

         if( len/80>0 && len%80>0 )

              linenum += len/80+1;

         else if(len>80 && len%80==0)

              linenum += len/80;

         else

              linenum++;

     }

 

     for(i = 0; i<filelength+1; i++)      //有些文件的行末不光一个‘\n’,而以"\r\n"结束,去‘\r’

     {                                    //否则addstr(str),或printw(format,str)对它不能正常显示

         if(*(buffer+i)==’\r’&&*(buffer+i+1)==’\n’)

              *(buffer+i)=’ ‘;

     }

 

     if( (points = (int *)malloc((linenum/SCREEN_LINES +1)*sizeof(int))) == NULL )//每屏始点记录数组

     {

         fprintf(stderr,"not enough memery!");

         exit(3);

     }

 

     pointer = 0l;

     curline = 0;

     p = -1;

 

     curX = curY = preY = 0;

     initscr();         //初始化窗口

     cbreak();     //除了 DELETE CTRL 等仍被视为特殊控制字元外一切输入的字元将立刻被一一读取

     noecho();     //屏幕上不显示在终端上

     intrflush(stdscr,FALSE);    //??不是很清楚。。。

     keypad(stdscr,TRUE);        //可以使用键盘上的一些特殊字元, 如上下左右等方向键

     refresh();         //首次使用,清屏

     while(1)

     {

         move(curY,curX);

         if(curline == 0)

         {

              //record the point that may return;

              points[++p] = pointer;

         }

         len = getoneline(buffer + pointer);

         memset(CLine,0×00,512);

         strncpy(CLine,buffer + pointer, len);

         printw("%s",CLine);         //在窗口屏幕中输出CLine

         preY = curY;

         getyx(stdscr,curY,curX);//得到当前的光标坐标

         if(curY>SCREEN_LINES)  //长行跨屏显示时,pointer记录下一屏的起始点的正确地点

         {

              if(len<=(SCREEN_LINES+1-preY)*80)

                   pointer += len;

              else

                   pointer += (SCREEN_LINES+1 – preY )*80;

         }

         else                   //一般情况下的pointer

              pointer += len;

         curline = curY;

         if(curY>SCREEN_LINES || p*(SCREEN_LINES+1)+curY+1>=linenum )//屏幕显示满,或文件终结

         {

              mvprintw(SCREEN_LINES+1,0,"                                                                                ");

              attron(A_REVERSE);

              mvprintw(SCREEN_LINES+1,0,"  —This is Gary(02101231)’s mmore!—  [ b/B: back, n/N: next, q/Q: quit ]   ");

              attroff(A_REVERSE);

              move(SCREEN_LINES+1,79);

              refresh();         //显示屏幕给用户看

wait:

              key = getch();     //得到按键命令[ b/B: back, n/N: next, q/Q: quit ]

              switch(key)

              {

              case ‘b’:

              case ‘B’:

                   if(p>0)       //得到需要的起始点,points数组中已存

                   {

                       pointer = points[--p];//point at SCREEN_LINES or n lines before

                       p–;

                   }

                   else

                   {

                       pointer = 0;

                       p–;

                   }

                   curY=curX=0;

                   curline = 0;

                   clear();      //清屏

                   break;

              case ‘n’:

              case ‘N’:

                   if(p*(SCREEN_LINES+1)+curY+1 >= linenum)//文件终结,不能下翻页

                   {

                       goto wait;

                   }

                   curY=curX=0;

                   curline = 0;

                   clear();      //清屏

                   break;

              case ‘q’:

              case ‘Q’:

                   endwin();     //结束,关闭窗口,回到终端。

                   exit(0);

                   break;

              default :

                   goto wait;

                   break;

              }

         }

     }

 

     endwin();

     fclose(fp);

     free(points);

 

     return 0;

}

 

////////////////////////////

///getoneline

///

int getoneline(char * a)

{

     int lenofline = 0;

     while(*a != ‘\n’ && *a != ‘\0′)

     {

         lenofline++;

         a++;

     }

     if(*a == ‘\n’)

         lenofline++;

     return lenofline;

}


评论

该日志第一篇评论

发表评论

评论也有版权!