/* $Id$ */ #include "bbs.h" /* * more.c * a mini pager in 130 lines of code, or stub of the huge pager pmore. * Author: Hung-Te Lin (piaip), April 2008. * * Copyright (c) 2008 Hung-Te Lin * All rights reserved. * Distributed under BSD license (GPL compatible). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. */ #ifdef USE_PMORE /* use new pager: piaip's more. */ int more(const char *fpath, int promptend) { int r = pmore(fpath, promptend); switch(r) { case RET_DOSYSOPEDIT: r = FULLUPDATE; if (!HasUserPerm(PERM_SYSOP) || strcmp(fpath, "etc/ve.hlp") == 0) break; #ifdef BN_SECURITY if (strcmp(currboard, BN_SECURITY) == 0) break; #endif // BN_SECURITY log_filef("log/security", LOG_CREAT, "%u %s %d %s admin edit file=%s\n", (int)now, Cdate(&now), getpid(), cuser.userid, fpath); veditfile(fpath); break; case RET_SELECTBRD: r = FULLUPDATE; if (HasUserPerm(PERM_BASIC)) { if (currstat == READING) return Select(); } break; case RET_COPY2TMP: r = FULLUPDATE; if (HasUserPerm(PERM_BASIC)) { char buf[PATHLEN]; getdata(b_lines - 1, 0, "把這篇文章收入到暫存檔?[y/N] ", buf, 4, LCECHO); if (buf[0] != 'y') break; setuserfile(buf, ask_tmpbuf(b_lines - 1)); Copy(fpath, buf); } break; case RET_DOCHESSREPLAY: r = FULLUPDATE; if (HasUserPerm(PERM_BASIC)) { ChessReplayGame(fpath); } break; #if defined(USE_BBSLUA) && !defined(DISABLE_BBSLUA_IN_PAGER) case RET_DOBBSLUA: r = FULLUPDATE; if (HasUserPerm(PERM_BASIC)) { bbslua(fpath); } else { vmsg("抱歉,此帳號無權限執行 BBS-Lua 程式。"); } break; #endif } return r; } #else // !USE_PMORE // minimore: a mini pager in exactly 130 lines #define PAGER_MAXLINES (2048) int more(const char *fpath, int promptend) { FILE *fp = fopen(fpath, "rt"); int lineno = 0, lines = 0, oldlineno = -1; int i = 0, abort = 0, showall = 0, colorize = 0; int lpos[PAGER_MAXLINES] = {0}; // line position char buf [ANSILINELEN]; if (!fp) return -1; clear(); if (promptend == NA) { // quick print one page for (i = 0; i < t_lines-1; i++) if (!fgets(buf, sizeof(buf), fp)) break; else outs(buf); fclose(fp); return 0; } // YEA mode: pre-read while (lines < PAGER_MAXLINES-1 && fgets(buf, sizeof(buf), fp) != NULL) lpos[++lines] = ftell(fp); rewind(fp); while (!abort) { if (oldlineno != lineno) // seek and print { clear(); showall = 0; oldlineno = lineno; fseek(fp, lpos[lineno], SEEK_SET); for (i = 0, buf[0] = 0; i < t_lines-1; i++, buf[0] = 0) { if (!showall) { fgets(buf, sizeof(buf), fp); if (lineno + i == 0 && (strncmp(buf, STR_AUTHOR1, strlen(STR_AUTHOR1))==0 || strncmp(buf, STR_AUTHOR2, strlen(STR_AUTHOR2))==0)) colorize = 1; } if (!buf[0]) { outs("\n"); showall = 1; } else { // dirty code to render heeader if (colorize && lineno+i < 4 && *buf && *buf != '\n' && strchr(buf, ':')) { char *q1 = strchr(buf, ':'); int l = t_columns - 2 - strlen(buf); char *q2 = strstr(buf, STR_POST1); chomp(buf); if (q2 == NULL) q2 = strstr(buf, STR_POST2); if (q2) { *(q2-1) = 0; q2 = strchr(q2, ':'); } else q2 = q1; *q1++ = 0; *q2++ = 0; if (q1 == q2) q2 = NULL; outs(ANSI_COLOR(34;47) " "); outs(buf); outs(" " ANSI_REVERSE); outs(q1); prints("%*s", l, ""); q1 += strlen(q1); if (q2) { outs(ANSI_COLOR(0;34;47) " "); outs(q1+1); outs(" " ANSI_REVERSE); outs(q2); } outs(ANSI_RESET"\n"); } else outs(buf); } } if (lineno + i >= lines) showall = 1; // print prompt bar snprintf(buf, sizeof(buf), " 瀏覽 P.%d ", 1 + (lineno / (t_lines-2))); vs_footer(buf, " (→↓[PgUp][PgDn][Home][End])游標移動\t(←/q)結束"); } // process key switch(vkey()) { case KEY_UP: case 'k': case Ctrl('P'): if (lineno == 0) abort = READ_PREV; lineno--; break; case KEY_PGUP: case Ctrl('B'): if (lineno == 0) abort = READ_PREV; lineno -= t_lines-2; break; case KEY_PGDN: case Ctrl('F'): case ' ': case KEY_RIGHT: if (showall) abort = READ_NEXT; lineno += t_lines-2; break; case KEY_DOWN: case 'j': case Ctrl('N'): if (showall) abort = READ_NEXT; lineno++; break; case KEY_HOME: case Ctrl('A'): lineno = 0; break; case KEY_END: case Ctrl('E'): lineno = lines - (t_lines-1); break; case KEY_LEFT: case 'q': abort = FULLUPDATE; break; case 'b': abort = READ_PREV; break; case 'f': abort = READ_NEXT; break; } if (lineno + (t_lines-1) >= lines) lineno = lines-(t_lines-1); if (lineno < 0) lineno = 0; } fclose(fp); return abort > 0 ? abort : 0; } #endif // !USE_PMORE