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)