summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2008-04-16 01:08:07 +0800
committerpiaip <piaip@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2008-04-16 01:08:07 +0800
commita38ce8fbc7b7b18ad75f86278fe25fd85ba485d2 (patch)
tree5a227cdba379a203155bbaf91b8b2323a2130a3c
parentdb9187feb31e50ed2fbe78f7fd73bf8d37bf0edc (diff)
downloadpttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.tar
pttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.tar.gz
pttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.tar.bz2
pttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.tar.lz
pttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.tar.xz
pttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.tar.zst
pttbbs-a38ce8fbc7b7b18ad75f86278fe25fd85ba485d2.zip
- (internal) visio: add columned output API.
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@4170 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r--common/sys/string.c44
-rw-r--r--include/cmsys.h1
-rw-r--r--include/visio.h24
-rw-r--r--mbbsd/visio.c204
4 files changed, 273 insertions, 0 deletions
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 <limits.h>
// 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");
+}
+