absmiddle EViewer 原始程式碼


[版主] 此為台大電機 Maxwell BBS 前站長 Ra 參考 BBS 原始碼寫作而得. #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <time.h> #include <string.h> #include <ctype.h> #include <sys/stat.h> #define KEY_LEFT 1075 #define KEY_RIGHT 1077 #define KEY_UP 1072 #define KEY_DOWN 1080 #define KEY_PGUP 1073 #define KEY_PGDN 1081 #define ESC 27 #define ENTER 13 #define MAXITEMS 1024 #define PATHLEN 256 #define A_PAGESIZE (t_lines - 6) #define STRLEN 80 typedef struct { char title[ 72 ]; char fname[ 40 ]; } ITEM; const int t_lines = 24; char genbuf[256]; int a_fmode = 2; typedef struct { ITEM *item[ MAXITEMS ]; char mtitle[ STRLEN ]; char *path; int num, page, now; } MENU; int egetch() { int c; c = getch(); if (c == 0) c = getch() + 1000; return c; } void ansimore (char *fname) { FILE *fptr; int i; int ch; fptr = fopen(fname,"r"); clrscr(); for (i=0 ; fgets(genbuf,sizeof(genbuf),fptr) != NULL ; i++){ printf("%s",genbuf); if ( i == 23 ) { cprintf("Enter: down a line | other keys: down a page\r"); if ((ch = egetch()) == ESC || ch == KEY_LEFT) { printf("\033[m"); fclose(fptr); return; } delline(); if (ch == ENTER) i = 22; else i = 0; } } fclose(fptr); if (i != 1) { printf("\033[m"); printf("[Press any key...]"); egetch(); } } int dashf( char *fname ) { struct stat st; return ( stat( fname, &st ) == 0 && st.st_mode & S_IFREG); } int dashd( char *fname ) { struct stat st; return ( stat( fname, &st ) == 0 && st.st_mode & S_IFDIR ); } void lfn2sfn ( char *str ) { // Only support ??????~1.??? // Does not support ??????~2.??? ??????~3.??? , etc char tmpstr[40]; char *dotptr, *ptr; int i=0; int xfr = 0; strcpy(tmpstr, str); dotptr = strrchr(tmpstr,'.'); ptr=tmpstr; while(1){ if (*ptr == '.') if (ptr != dotptr){ xfr = 1; i--; } else { if (strlen(ptr+1) > 3) xfr = 1; if (xfr){ if (i <= 6) sprintf(str+i,"~1.%.3s",ptr+1); else if (i == 7 || i == 8) sprintf(str+6,"~1.%.3s",ptr+1); } else strcpy(str+i,ptr); break; } else if ( i == 8 && *ptr != '\0' ){ strcpy(str+6,"~1"); if (dotptr != NULL) sprintf(str+8,".%.3s",dotptr+1); break; }else if ( *ptr == '\0' ){ if (xfr) if (i <= 6) strcpy(str+i,"~1"); else strcpy(str+6,"~1"); else str[i] = '\0'; break; }else if ( *ptr == ']' || *ptr == '['){ str[i] = '_'; xfr = 1; }else if ( isalnum(*ptr) || strchr("@-_",*ptr) != NULL) str[i] = *ptr; i++; ptr++; } } int valid_fname( char *str ) { strcpy(genbuf,str); lfn2sfn(genbuf); return !strcmp(genbuf,str); } void a_showmenu( MENU *pm ) { struct stat st; char title[ STRLEN ]; char fname[ STRLEN ]; char ch; time_t mtime; int n; clrscr(); printf( " %s\n", pm->mtitle ); printf( " =============================================================================\n" ); printf( " 編號 標 題" ); if( a_fmode ) printf( "%64s", a_fmode == 1 ? " 檔案名稱 " : "上次修改日期" ); printf( "\n" ); if( pm->num == 0 ) printf( " No article in this group !!\n" ); for( n = pm->page; n < pm->page + 18 && n < pm->num; n++ ) { strcpy( title, pm->item[n]->title ); if( a_fmode ) { strcpy( fname, pm->item[n]->fname ); sprintf( genbuf, "%s/%s", pm->path, fname ); if( a_fmode == 1 ) { ch = (dashf( genbuf ) ? ' ' : (dashd( genbuf ) ? '/' : '^')); } else { if( dashf( genbuf ) ) { stat( genbuf, &st ); mtime = st.st_mtime; strftime ( fname, 11, "<%d/%m/%y>", localtime(&mtime)); } else if( dashd( genbuf ) ) { strcpy( fname, "< 目 錄 >" ); } else { strcpy( fname, "<錯誤檔名>" ); } ch = ' '; } title[ 60 ] = '\0'; sprintf( genbuf, "%-59s %s%c", title, fname, ch ); strcpy( title, genbuf ); } title[ 72 ] = '\0'; printf( " %3d %s\n", n+1, title ); } gotoxy( 1, t_lines-1 ); printf( "[功\能鍵] 說明 h │ 離開 q,← │ "); } void a_showhelp() { clrscr(); printf( " 精華區公佈欄 使用說明\n" ); printf( "\ [按鍵] [說明]\n\ h 本使用說明\n\ q ← 離開到上一層目錄\n\ k ↑ 移到前一個選項\n\ j ↓ 移到後一個選項\n\ PgUp 跳至前一頁選單\n\ PgDn 跳至後一頁選單\n\ r Rtn → 進入下一層目錄 / 讀取文章\n\ m 移動檔案順序\n\ t 更改選項敘述\n\ f 查詢檔案名稱\n"); egetch(); } void a_additem( MENU *pm, char *title, char *fname ) { ITEM *newitem; if( pm->num < MAXITEMS ) { newitem = (ITEM *) malloc( sizeof(ITEM) ); strcpy( newitem->title, title ); strcpy( newitem->fname, fname ); pm->item[ (pm->num)++ ] = newitem; } } int a_loadnames( MENU *pm ) { FILE *fn; ITEM litem; char buf[ PATHLEN ], *ptr; pm->num = 0; sprintf( buf, "%s/Names~1", pm->path ); if( (fn = fopen( buf, "r" )) == NULL ) return 0; while( fgets( buf, sizeof(buf), fn ) != NULL ) { if( (ptr = strchr( buf, '\n' )) != NULL ) buf[ptr-buf] = '\0'; if( strncmp( buf, "Name=", 5 ) == 0 ) { strncpy( litem.title, buf + 5, sizeof(litem.title) ); } else if( strncmp( buf, "Path=~/", 7 ) == 0 ) { strncpy( litem.fname, buf + 7, sizeof(litem.fname) ); lfn2sfn( litem.fname ); // VFAT file name -> DOS short file name a_additem( pm, litem.title, litem.fname ); } else if( strncmp( buf, "# Title=", 8 ) == 0 ) strcpy( pm->mtitle, buf + 8 ); } fclose( fn ); return 1; } void a_savenames( MENU *pm ) { FILE *fn; ITEM *item; char fpath[ PATHLEN ]; int n; sprintf( fpath, "%s/Names~1", pm->path ); if( (fn = fopen( fpath, "w" )) == NULL ) return; fprintf( fn, "#\n" ); fprintf( fn, "# Title=%s\n", pm->mtitle ); fprintf( fn, "#\n" ); for( n = 0; n < pm->num; n++ ) { item = pm->item[n]; fprintf( fn, "Name=%s\n", item->title ); fprintf( fn, "Path=~/%s\n", item->fname ); fprintf( fn, "Numb=%d\n", n+1 ); fprintf( fn, "#\n" ); } fclose( fn ); } void a_prompt( int bot, char *pmt, char *buf ) { gotoxy( 1, t_lines+bot+1 ); printf("%s",pmt); gets(buf); } void a_moveitem( pm ) MENU *pm; { ITEM *tmp; char newnum[ STRLEN ]; int num, n; sprintf( genbuf, "請輸入第 %d 項的新次序: ", pm->now+1 ); a_prompt( -2, genbuf, newnum ); num = (newnum[0] == '$') ? 9999 : atoi( newnum ) - 1; if( num >= pm->num ) num = pm->num-1; else if( num < 0 ) num = 0; tmp = pm->item[ pm->now ]; if( num > pm->now ) { for( n = pm->now; n < num; n++ ) pm->item[ n ] = pm->item[ n+1 ]; } else { for( n = pm->now; n > num; n-- ) pm->item[ n ] = pm->item[ n-1 ]; } pm->item[ num ] = tmp; pm->now = num; a_savenames( pm ); } void a_manager( MENU *pm, int ch ) { ITEM *item; char fpath[ PATHLEN ]; if( pm->num > 0 ) { item = pm->item[ pm->now ]; sprintf( fpath, "%s/%s", pm->path, item->fname ); } if( pm->num > 0 ) switch( ch ) { case 'f': if( ++a_fmode >= 3 ) a_fmode = 0; pm->page = 9999; break; case 'm': a_moveitem( pm ); pm->page = 9999; break; case 't': a_prompt( -2, "新標題: ", genbuf ); if( *genbuf ) strcpy( item->title, genbuf ); a_savenames( pm ); pm->page = 9999; break; } } void a_menu( char *path ) { MENU me; char fname[ PATHLEN ]; int ch; char lbuf[11]; int lbc; me.path = path; me.mtitle[0] = '\0'; a_loadnames( &me ); me.page = 9999; me.now = 0; lbc = 0; while( 1 ) { if( me.now >= me.num && me.num > 0 ) { me.now = me.num - 1; } else if( me.now < 0 ) { me.now = 0; } if( me.now < me.page || me.now >= me.page + A_PAGESIZE ) { me.page = me.now - (me.now % A_PAGESIZE); a_showmenu( &me ); } gotoxy( 1, 4 + me.now - me.page ); printf( "->" ); ch = egetch(); gotoxy( 1, 4 + me.now - me.page ); printf( " " ); if( ch == 'Q' || ch == 'q' || ch == KEY_LEFT || ch == EOF || ch == ESC) break; if ( ch >= '0' && ch <= '9' ){ if( lbc < 9 ) lbuf[ lbc++ ] = ch; continue; } else if ( lbc > 0 && (ch == '\n' || ch == '\r') ) { lbuf[ lbc ] = '\0'; lbc = atoi( lbuf ); if ( lbc >= me.num ) lbc = me.num; me.now = lbc - 1; lbc = 0; continue; } lbc = 0; switch( ch ) { case KEY_UP: case 'k': if( --me.now < 0 ) me.now = me.num-1; break; case KEY_DOWN: case 'j': if( ++me.now >= me.num ) me.now = 0; break; case KEY_PGUP: if( me.now >= A_PAGESIZE ) me.now -= A_PAGESIZE; else if( me.now > 0 ) me.now = 0; else me.now = me.num - 1; break; case KEY_PGDN: case ' ': if( me.now < me.num-A_PAGESIZE) me.now += A_PAGESIZE; else if( me.now < me.num - 1 ) me.now = me.num - 1; else me.now = 0; break; case 'h': a_showhelp(); me.page = 9999; break; case 'R': case 'r': case '\n': case '\r': case KEY_RIGHT: if( me.now < me.num ) { sprintf( fname, "%s/%s", path, me.item[ me.now ]->fname ); if( dashf(fname) ) { ansimore( fname ); } else if( dashd(fname) ) { a_menu( fname ); } me.page = 9999; } break; } a_manager( &me, ch ); } for( ch = 0; ch < me.num; ch++ ) free( me.item[ ch ] ); } int main() { a_menu( "." ); clrscr(); }
上一層目錄