2015-07-29 晴 成都
more指令的简单实现
遇到的问题和我的处理
1. 问题:换行时,“--more()--”提示输入指令这行会多次不停的向屏幕上方移动。
处理:每次都从进行满屏输出,不管是翻页还是换行,总是将“--more--”挤到屏幕的最下方。
iCurrentLine = iCurrentLine - (sliPageLen-1) + reply;
等式右边
iCurrentLine当前显示到的行数,每次计算的时候先减去一页的行数(sliPageLen - 1),再加上用户响应的行数reply,就得出如果满屏显示应该从哪一行开始显示
2. 问题:从问题1中引发了一个新的问题——不知道终端一屏是多少行,多少列
处理:可以使用stty-a或者ioctl( STDIN_FILENO, TIOCGSIZE, ... )[ or ioctl( STDIN_FILENO,TIOCGWINZE, ... ) ]获取。
<pre name="code" class="cpp"><pre name="code" class="cpp">fp = popen("stty-a","r"); while( fgets(caLine,LINELEN,fp) != NULL ) { /* ** fetch the rows */ cpStart = strstr(caLine,"rows"); cpEnd = strstr(caLine,"columns"); if( cpStart != NULL && cpEnd!=NULL ) { strncpy(caPart,cpStart,cpEnd-cpStart); caPart[cpEnd-cpStart]='\0'; sscanf(caPart,"%*s%[^;]",caAim); *iRows=atoi(caAim); /* ** fetch the cols */ cpStart=strstr(caLine,"columns"); cpEnd =strstr(caLine,"line" ); strncpy(caPart,cpStart,cpEnd-cpStart); caPart[cpEnd-cpStart]='\0'; sscanf(caPart,"%*s%[^;]",caAim); *iCols=atoi(caAim); }/* end if( cpStart != NULL&& cpEnd != NULL ) */ }/* end while( fgets(caLine, LINELEN, fp ) != NULL ) */
3. 问题:问题1引发的第二问题,要想控制文件从哪一个显示,需要记录每一行的起始位置。
处理:设计一个简单的可随机访问的数据结构记录每一个显示行的起始位置
4. 问题:问题3连带一个新的问题,一个文件行可能需要占用终端的多个行来进行显示,如果按照换行符的标准进行行输出,可能会造成某些内容被挤到终端外而无法显示。/* ** st_line_node* init_line_manager( long liLineNum ); ** precondition: liLineNum > 0 ** postcondition: generate a dynamic array whose length ** is liLineNum ** ** intfree_line_manager( st_line_node *stpLine ); ** precondition: stpLine not NULL ** postcondition: free the dynamic array, success returns true ** otherwise returns false ** ** TOOLKIT of the line manager ** voidinsert_line_node( st_line_node *stpLine, long liLineNo, long liOffset ); ** precondition: liLineNo andliOffset both greater than zero, and ** liLineNo is less than the maximum line no ** postcondition: insert the line node into the array ** ** long fetch_line_offset(st_line_node *stpLine, long liLineNo ); ** precondition: liLineNo greaterthan zero and less than the maximum ** line no ** postcondition: return the specific offset ** ** intis_filled( st_line_node *stpLine, long liLineNo ); ** precondition: liLineNo greaterthan zero and less than the maximum ** line no ** postcondition: the current line no has a offset, return true; otherwise ** respond a false ** */
处理:所以不能依靠换行符来进行分行,而应该依靠终端的列数作为行的划分
5. 问题:在接受用户的指令时,需要无回显和立即响应long get_file_lines_base_len(FILE*fp,intiLineLen) { longliLines=0; charcaLine[iLineLen]; while(fgets(caLine,iLineLen,fp)!=NULL) { ++liLines; } returnliLines; }/* end get_file_lines_depond_len( FILE *fp,int iLineLen ) */
处理:控制终端属性来达到需求
6.问题:系统more在显示提示的时候会显示当前显示内容大约处于文件什么位置(百分比),e.g--more(%12)--/* 关闭回显 */ term.c_lflag&=~ECHO; /* 关闭终端缓存,每次接收一个字符就马上反应 */ term.c_lflag&=~ICANON; term.c_cc[VMIN]=1; /* one character one time*/
处理:由于已经记录了当前显示行的位置,只需要知道整个文件的字节数,即可求得当前显示行所处的百分比
7. 问题:编写Makefile时候,将终端操作、文件操作和more操作的内容分别打成了对应的静态库,再最终编译的时候,报错了。long get_file_bytes(FILE*fp) { longliAllBytes=0; if(fseek(fp,0,SEEK_END)==-1) { fprintf(stderr,"fseek error\n"); return-1; }/* end if( fseek( fp, 0,SEEK_END ) == -1 ) */ liAllBytes=ftell(fp); /* all the bytes from thebyte 0 */ if(fseek(fp,0,SEEK_SET)==-1) /* rewind the file */ { fprintf(stderr,"fseek error\n"); return-1; }/* end if( fseek( fp, 0,SEEK_SET ) == -1 ) */ returnliAllBytes; }/* end get_file_bytes( FILE *fp ) */
处理:出错原因是libmoremanager.a这个库需要依赖于libfilemanager.a和libtermmanager.a,所以应该将libmoremanager.a放在前面。应该是:
8. make文件包括两个文件,一个定义变量的文件Make.defines,一个是用于编译的Makefile文件。在Makefile文件中通过include将Make.defines中定义的变量引入,其中ROOT是Make.defines文件相对Makefile文件的文件路径。
最后整个程序的目录和Makefile如下:
Make.defines的内容如下:
Makefile文件内容如下:
9. 源代码ROOT=../.. include $(ROOT)/Make.defines CINCLUDE+= -I./include VPATH+= include src obj lib CLDIR+= -L./lib -L./src CLIBS+= -lmoremanager -lfilemanager-ltermmanager ARFLAGS+= TMPFILE+= ./lib/*.a ./obj/*.o *.a # PRGS= more4 more5 more6 more7 PRGS= more9 define AR_CMD $(AR)$(ARFLAGS) $@ $< $(MV)$< ./obj $(MV)$@ ./lib endef .PHONY=all all: $(PRGS) %: %.c libfilemanager.a libtermmanager.alibmoremanager.a $(CC)$(CFLAGS) -DDEBUG $(CINCLUDE) $(CLDIR) -o $@ $< $(CLIBS) libfilemanager.a: file_manager.ofile_manager.h $(AR_CMD) libtermmanager.a: term_manager.oterm_manager.h $(AR_CMD) libmoremanager.a: more_manager.omore_manager.h $(AR_CMD) # generate the .o file %.o: %.c %.h $(CC)$(CINCLUDE) -DDEBUG -c $^ .PHONY=clean clean: $(RM) $(TMPFILE) $(PRGS)