From a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2 Mon Sep 17 00:00:00 2001 From: piaip Date: Tue, 15 Apr 2008 17:08:07 +0000 Subject: - (internal) visio: add columned output API. git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4170 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- common/sys/string.c | 44 ++++++++++++ include/cmsys.h | 1 + include/visio.h | 24 +++++++ mbbsd/visio.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 273 insertions(+) diff --git a/common/sys/string.c b/common/sys/string.c index b152ac63..881a0e04 100644 --- a/common/sys/string.c +++ b/common/sys/string.c @@ -134,6 +134,50 @@ strip_ansi(char *dst, const char *src, enum STRIP_FLAG mode) return count; } +/** + * query the offset of nth non-ANSI element in s + * if string is less then nth, return missing blanks in negative value. + */ +int +strat_ansi(int count, const char *s) +{ + register int mode = 0; + const char *os = s; + + for (; count > 0 && *s; ++s) + { + // 0 - no ansi, 1 - [, 2 - param+cmd + switch (mode) + { + case 0: + if (*s == ESC_CHR) + mode = 1; + else + count --; + break; + + case 1: + if (*s == '[') + mode = 2; + else + mode = 0; // unknown command + break; + + case 2: + if (isEscapeParam(*s)) + continue; + else if (isEscapeCommand(*s)) + mode = 0; + else + mode = 0; + break; + } + } + if (count > 0) + return -count; + return s - os; +} + int strlen_noansi(const char *s) { diff --git a/include/cmsys.h b/include/cmsys.h index 14d3c1ba..0401da26 100644 --- a/include/cmsys.h +++ b/include/cmsys.h @@ -80,6 +80,7 @@ extern void str_lower(char *t, const char *s); extern void trim(char *buf); extern void chomp(char *src); extern int strlen_noansi(const char *s); +extern int strat_ansi(int count, const char *s); extern int strip_blank(char *cbuf, char *buf); extern int strip_ansi(char *buf, const char *str, enum STRIP_FLAG flag); extern void strip_nonebig5(unsigned char *str, int maxlen); diff --git a/include/visio.h b/include/visio.h index 986be0df..af8cf4dd 100644 --- a/include/visio.h +++ b/include/visio.h @@ -9,6 +9,7 @@ #include "bbs.h" #include "ansi.h" // we need it. +#include // THEME DEFINITION ---------------------------------------------------- #define VCLR_HEADER ANSI_COLOR(1;37;46) // was: TITLE_COLOR @@ -30,10 +31,28 @@ #define VMSG_HDR_PREFIX "【 " #define VMSG_HDR_POSTFIX " 】" +// CONSTANT DEFINITION ------------------------------------------------- +#define VCOL_ALIGN_LEFT (0) +#define VCOL_ALIGN_RIGHT (1) +// #define VCOL_ALIGN_MIDDLE (2) +#define VCOL_MAXW (INT16_MAX) + // DATATYPE DEFINITION ------------------------------------------------- typedef void * VREFSCR; typedef long VREFCUR; +typedef short VCOLW; +typedef struct { + char *caption; + char *attr; // default attribute + VCOLW minw; // minimal width + VCOLW maxw; // max width + char has_ansi; // support ANSI escape sequence + char align; // alignment + char usewhole; // draw entire column, not leaving borders + char flag; // reserved +} VCOL; + // API DEFINITION ---------------------------------------------------- // int vans(char *prompt); // prompt at bottom and return y/n in lower case. // void vs_bar(char *title); // like stand_title @@ -56,6 +75,11 @@ void vs_header (const char *title, const char *mid, const char *right); // vs_ void vs_hdr (const char *title); // vs_bar, stand_title void vs_footer (const char *caption, const char *prompt); +// columned output +void vs_cols_layout (const VCOL* cols, VCOLW *ws, int n); +void vs_cols_hdr (const VCOL* cols, const VCOLW *ws, int n); +void vs_cols (const VCOL* cols, const VCOLW *ws, int n, ...); + // compatible macros #define stand_title vs_hdr diff --git a/mbbsd/visio.c b/mbbsd/visio.c index 5f71645f..43b9ff3e 100644 --- a/mbbsd/visio.c +++ b/mbbsd/visio.c @@ -49,6 +49,26 @@ nblank(int n) outnc(n, ' '); } +inline void +fillns(int n, const char *s) +{ + while (n > 0 && *s) + outc(*s++), n--; + if (n > 0) + outnc(n, ' '); +} + +inline void +fillns_ansi(int n, char *s) +{ + int d = strat_ansi(n, s); + if (d < 0) { + outs(s); nblank(-d); + } else { + outns(s, d); + } +} + // ---- VREF API -------------------------------------------------- /** @@ -493,3 +513,187 @@ vs_footer(const char *caption, const char *msg) outs(ANSI_RESET); } +/** + * vs_cols_layout(cols, ws, n): 依據 cols (大小寫 n) 的定義計算適合的行寬於 ws + */ + +void +vs_cols_layout(const VCOL *cols, VCOLW *ws, int n) +{ + int i, tw, d = 0; + memset(ws, 0, sizeof(VCOLW) * n); + + // first run, calculate minimal size + for (i = 0, tw = 0; i < n; i++) + { + // drop any trailing if required + if (tw + cols[i].minw > MAX_COL) + break; + ws[i] = cols[i].minw; + tw += ws[i]; + } + + // try to iterate through all. + while (tw < MAX_COL) { + char run = 0; + d++; + for (i = 0; i < n; i++) + { + // increase fields if still ok. + if (cols[i].maxw - cols[i].minw < d) + continue; + ws[i] ++; + if (++tw >= MAX_COL) break; + run ++; + } + // if no more fields... + if (!run) break; + } +} + +/** + * vs_cols_hdr: 依照已經算好的欄位輸出標題列 + */ +void +vs_cols_hdr (const VCOL* cols, const VCOLW *ws, int n) +{ + int i; + char *s; + + outs(ANSI_COLOR(5)); // TODO use theme color? + for (i = 0; i < n; i++, cols++, ws++) + { + int w = *ws; + + s = cols->caption; + if (!s) s = ""; + + if (!cols->usewhole) + w--; + + if (w > 0) { + switch(cols->align) + { + case VCOL_ALIGN_LEFT: + fillns(w, s); + break; + + case VCOL_ALIGN_RIGHT: + { + int l = strlen(s); + + if (l >= w) + l = w; + else + nblank(w - l); + + // simular to left align + fillns(l, s); + } + break; + + default: + assert(0); + } + } + + // only drop if w < 0 (no space for whole) + if (!cols->usewhole && w >= 0) + outc(' '); + } + outs(ANSI_RESET "\n"); +} + +/** + * vs_cols: 依照已經算好的欄位大小進行輸出 + */ +void +vs_cols(const VCOL *cols, const VCOLW *ws, int n, ...) +{ + int i = 0, w = 0; + char *s = NULL; + char ovattr = 0; + + va_list ap; + va_start(ap, n); + + for (i = 0; i < n; i++, cols++, ws++) + { + s = va_arg(ap, char*); + + // quick check input. + if (!s) + { + s = ""; + } + else if (*s == ESC_CHR && !cols->has_ansi) // special rule to escape + { + outs(s); i--; // one more parameter! + ovattr = 1; + continue; + } + + if (cols->attr && !ovattr) + outs(cols->attr); + + w = *ws; + + if (!cols->usewhole) + w--; + + // render value if field has enough space. + if (w > 0) { + switch (cols->align) + { + case VCOL_ALIGN_LEFT: + if (cols->has_ansi) + fillns_ansi(w, s); + else + fillns(w, s); + break; + + case VCOL_ALIGN_RIGHT: + // complex... + { + int l = 0; + if (cols->has_ansi) + l = strlen_noansi(s); + else + l = strlen(s); + + if (l >= w) + l = w; + else + nblank(w - l); + + // simular to left align + if (cols->has_ansi) + fillns_ansi(l, s); + else + fillns(l, s); + } + break; + + default: + assert(0); + break; + } + } + + // only drop if w < 0 (no space for whole) + if (!cols->usewhole && w >= 0) + outc(' '); + + if (cols->attr || cols->has_ansi || ovattr) + { + if (ovattr) + ovattr = 0; + outs(ANSI_RESET); + } + } + va_end(ap); + + // end line + outs(ANSI_RESET "\n"); +} + -- cgit v1.2.3