summaryrefslogtreecommitdiff
path: root/examples/table-sort.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'examples/table-sort.cxx')
-rw-r--r--examples/table-sort.cxx168
1 files changed, 115 insertions, 53 deletions
diff --git a/examples/table-sort.cxx b/examples/table-sort.cxx
index f979693f9..94c885ffa 100644
--- a/examples/table-sort.cxx
+++ b/examples/table-sort.cxx
@@ -31,9 +31,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#include <string>
-#include <vector>
-#include <algorithm> // STL sort
#define MARGIN 20
@@ -43,7 +40,8 @@
// /-C -- disable 1000's separator in file sizes
// /A-D -- don't show directories
# define DIRCMD "dir /-C /A-D"
- static std::vector<std::string> G_header = { "Date", "Time", "Size", "Filename" };
+ static const char *G_header[] = { "Date", "Time", "Size", "Filename" };
+ static int G_header_count = 4;
# ifdef _MSC_VER
# define popen _popen
# define pclose _pclose
@@ -51,7 +49,8 @@
#else /* _WIN32 */
// UNIX
# define DIRCMD "ls -l"
- static std::vector<std::string> G_header = { "Perms", "#L", "Own", "Group", "Size", "Date", "", "", "Filename" };
+ static const char *G_header[] = { "Perms", "#L", "Own", "Group", "Size", "Date", "", "", "Filename" };
+ static int G_header_count = 9;
#endif /* _WIN32 */
// Font face/sizes for header and rows
@@ -61,38 +60,81 @@
#define ROW_FONTSIZE 16
// A single row of columns
-class Row {
-public:
- std::vector<std::string> cols;
+struct Row {
+ char **cols;
+ int cols_count;
+ int cols_alloc;
};
-// Sort class to handle sorting column using std::sort
-class SortColumn {
- int _col, _reverse;
-public:
- SortColumn(int col, int reverse) {
- _col = col;
- _reverse = reverse;
+static void row_init(Row *r) {
+ r->cols = 0;
+ r->cols_count = 0;
+ r->cols_alloc = 0;
+}
+
+static void row_free(Row *r) {
+ int i;
+ for (i = 0; i < r->cols_count; i++) {
+ free(r->cols[i]);
}
- bool operator()(const Row &a, const Row &b) {
- const char *ap = ( _col < (int)a.cols.size() ) ? a.cols[_col].c_str() : "",
- *bp = ( _col < (int)b.cols.size() ) ? b.cols[_col].c_str() : "";
- if ( isdigit(*ap) && isdigit(*bp) ) { // cheezy detection of numeric data
- // Numeric sort
- int av=0; sscanf(ap, "%d", &av);
- int bv=0; sscanf(bp, "%d", &bv);
- return( _reverse ? av < bv : bv < av );
- } else {
- // Alphabetic sort
- return( _reverse ? strcmp(ap, bp) > 0 : strcmp(ap, bp) < 0 );
- }
+ free(r->cols);
+ r->cols = 0;
+ r->cols_count = 0;
+ r->cols_alloc = 0;
+}
+
+static void row_push(Row *r, const char *s) {
+ if (r->cols_count >= r->cols_alloc) {
+ int new_alloc = r->cols_alloc ? r->cols_alloc * 2 : 16;
+ r->cols = (char **)realloc(r->cols, new_alloc * sizeof(char *));
+ r->cols_alloc = new_alloc;
}
-};
+ r->cols[r->cols_count++] = strdup(s);
+}
+
+static void row_append_last(Row *r, const char *s) {
+ if (r->cols_count > 0) {
+ char *old = r->cols[r->cols_count - 1];
+ size_t oldlen = strlen(old);
+ size_t slen = strlen(s);
+ char *newstr = (char *)malloc(oldlen + 1 + slen + 1);
+ memcpy(newstr, old, oldlen);
+ newstr[oldlen] = ' ';
+ memcpy(newstr + oldlen + 1, s, slen + 1);
+ free(old);
+ r->cols[r->cols_count - 1] = newstr;
+ }
+}
+
+// Global sort state for qsort
+static int g_sort_col = 0;
+static int g_sort_reverse = 0;
+
+static int row_compare(const void *a, const void *b) {
+ const Row *ra = (const Row *)a;
+ const Row *rb = (const Row *)b;
+ const char *ap = (g_sort_col < ra->cols_count) ? ra->cols[g_sort_col] : "";
+ const char *bp = (g_sort_col < rb->cols_count) ? rb->cols[g_sort_col] : "";
+ int result;
+ if (isdigit((unsigned char)*ap) && isdigit((unsigned char)*bp)) {
+ // Numeric sort
+ int av = 0, bv = 0;
+ sscanf(ap, "%d", &av);
+ sscanf(bp, "%d", &bv);
+ result = bv - av;
+ } else {
+ // Alphabetic sort
+ result = strcmp(ap, bp);
+ }
+ return g_sort_reverse ? -result : result;
+}
// Derive a custom class from Fl_Table_Row
class MyTable : public Fl_Table_Row {
private:
- std::vector<Row> rowdata_; // data in each row
+ Row *rowdata_;
+ int rowdata_count_;
+ int rowdata_alloc_;
int sort_reverse_;
int sort_lastcol_;
@@ -101,19 +143,28 @@ private:
protected:
void draw_cell(TableContext context, int R=0, int C=0, // table cell drawing
- int X=0, int Y=0, int W=0, int H=0) FL_OVERRIDE;
+ int X=0, int Y=0, int W=0, int H=0);
void sort_column(int col, int reverse=0); // sort table by a column
void draw_sort_arrow(int X,int Y,int W,int H);
public:
// Ctor
MyTable(int x, int y, int w, int h, const char *l=0) : Fl_Table_Row(x,y,w,h,l) {
+ rowdata_ = 0;
+ rowdata_count_ = 0;
+ rowdata_alloc_ = 0;
sort_reverse_ = 0;
sort_lastcol_ = -1;
end();
callback(event_callback, (void*)this);
}
- ~MyTable() { } // Dtor
+ ~MyTable() {
+ int i;
+ for (i = 0; i < rowdata_count_; i++) {
+ row_free(&rowdata_[i]);
+ }
+ free(rowdata_);
+ }
void load_command(const char *cmd); // Load the output of a command into table
void autowidth(int pad); // Automatically set column widths to data
void resize_window(); // Resize parent window to size of table
@@ -121,7 +172,9 @@ public:
// Sort a column up or down
void MyTable::sort_column(int col, int reverse) {
- std::sort(rowdata_.begin(), rowdata_.end(), SortColumn(col, reverse));
+ g_sort_col = col;
+ g_sort_reverse = reverse;
+ qsort(rowdata_, rowdata_count_, sizeof(Row), row_compare);
redraw();
}
@@ -152,16 +205,16 @@ void MyTable::draw_sort_arrow(int X,int Y,int W,int H) {
// Handle drawing all cells in table
void MyTable::draw_cell(TableContext context, int R, int C, int X, int Y, int W, int H) {
const char *s = "";
- if ( R < (int)rowdata_.size() && C < (int)rowdata_[R].cols.size() )
- s = rowdata_[R].cols[C].c_str();
+ if ( R < rowdata_count_ && C < rowdata_[R].cols_count )
+ s = rowdata_[R].cols[C];
switch ( context ) {
case CONTEXT_COL_HEADER:
fl_push_clip(X,Y,W,H); {
fl_draw_box(FL_THIN_UP_BOX, X,Y,W,H, FL_BACKGROUND_COLOR);
- if ( C < (int)G_header.size() ) {
+ if ( C < G_header_count ) {
fl_font(HEADER_FONTFACE, HEADER_FONTSIZE);
fl_color(FL_BLACK);
- fl_draw(G_header[C].c_str(), X+2,Y,W,H, FL_ALIGN_LEFT, 0, 0); // +2=pad left
+ fl_draw(G_header[C], X+2,Y,W,H, FL_ALIGN_LEFT, 0, 0); // +2=pad left
// Draw sort arrow
if ( C == sort_lastcol_ ) {
draw_sort_arrow(X,Y,W,H);
@@ -190,17 +243,17 @@ void MyTable::draw_cell(TableContext context, int R, int C, int X, int Y, int W,
// Automatically set column widths to widest data in each column
void MyTable::autowidth(int pad) {
- int w, h;
+ int w, h, c, r;
// Initialize all column widths to header width
fl_font(HEADER_FONTFACE, HEADER_FONTSIZE);
- for ( int c = 0; c < (int)G_header.size(); c++ ) {
- w=0; fl_measure(G_header[c].c_str(), w, h, 0); // pixel width of header text
+ for ( c = 0; c < G_header_count; c++ ) {
+ w=0; fl_measure(G_header[c], w, h, 0); // pixel width of header text
col_width(c, w+pad);
}
fl_font(ROW_FONTFACE, ROW_FONTSIZE);
- for ( int r=0; r<(int)rowdata_.size(); r++ ) {
- for ( int c=0; c<(int)rowdata_[r].cols.size(); c++ ) {
- w=0; fl_measure(rowdata_[r].cols[c].c_str(), w, h, 0); // pixel width of row text
+ for ( r=0; r<rowdata_count_; r++ ) {
+ for ( c=0; c<rowdata_[r].cols_count; c++ ) {
+ w=0; fl_measure(rowdata_[r].cols[c], w, h, 0); // pixel width of row text
if ( (w + pad) > col_width(c)) col_width(c, w + pad);
}
}
@@ -210,9 +263,10 @@ void MyTable::autowidth(int pad) {
// Resize parent window to size of table
void MyTable::resize_window() {
+ int t;
// Determine exact outer width of table with all columns visible
int width = 2; // width of table borders
- for ( int t=0; t<cols(); t++ ) width += col_width(t); // total width of all columns
+ for ( t=0; t<cols(); t++ ) width += col_width(t); // total width of all columns
width += vscrollbar->w(); // include width of scrollbar
width += MARGIN*2;
if ( width < 200 || width > Fl::w() ) return;
@@ -222,9 +276,10 @@ void MyTable::resize_window() {
// Load table with output of 'cmd'
void MyTable::load_command(const char *cmd) {
char s[512];
+ int line;
FILE *fp = popen(cmd, "r");
cols(0);
- for ( int line=0; fgets(s, sizeof(s)-1, fp); line++ ) {
+ for ( line=0; fgets(s, sizeof(s)-1, fp); line++ ) {
#ifdef _WIN32
// WINDOWS
if (s[0] == '\n' || s[0] == ' ') continue; // ignore header/footer lines
@@ -233,30 +288,37 @@ void MyTable::load_command(const char *cmd) {
if ( line==0 && strncmp(s,"total ",6)==0) continue;
#endif
// Add a new row
- Row newrow; rowdata_.push_back(newrow);
- std::vector<std::string> &rc = rowdata_.back().cols;
+ if (rowdata_count_ >= rowdata_alloc_) {
+ int new_alloc = rowdata_alloc_ ? rowdata_alloc_ * 2 : 64;
+ rowdata_ = (Row *)realloc(rowdata_, new_alloc * sizeof(Row));
+ rowdata_alloc_ = new_alloc;
+ }
+ row_init(&rowdata_[rowdata_count_]);
+ rowdata_count_++;
+ Row *rc = &rowdata_[rowdata_count_ - 1];
// Break line into separate word 'columns'
char *ss;
+ int t;
const char *delim = " \t\n";
- for(int t=0; (t==0)?(ss=strtok(s,delim)):(ss=strtok(NULL,delim)); t++) {
+ for(t=0; (t==0)?(ss=strtok(s,delim)):(ss=strtok(0,delim)); t++) {
#ifdef _WIN32
// DIR: Some systems show meridiem field, some don't (24hr time)
if (t==2 && (strcmp(ss,"AM")==0 || strcmp(ss,"PM")==0)) {
- rc.back() = rc.back() + std::string(" ") + std::string(ss);
- continue;
+ row_append_last(rc, ss);
+ continue;
}
#endif
- rc.push_back(ss); // char* -> std::string
+ row_push(rc, ss);
}
// Keep track of max # columns
- if ( (int)rc.size() > cols() ) {
- cols((int)rc.size());
+ if ( rc->cols_count > cols() ) {
+ cols(rc->cols_count);
}
}
pclose(fp);
// How many rows we loaded
- rows((int)rowdata_.size());
+ rows(rowdata_count_);
// Auto-calculate widths, with 20 pixel padding
autowidth(20);
}