1 /*
2 * Copyright (C) 2016 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <sys/types.h>
12 #include <sys/time.h>
13
14 #include "c.h"
15 #include "nls.h"
16 #include "strutils.h"
17 #include "xalloc.h"
18
19 #include "libsmartcols.h"
20
21 #define TIME_PERIOD 3.0 /* seconds */
22
23 enum { COL_NUM, COL_DATA, COL_TIME };
24
25 static double time_diff(struct timeval *a, struct timeval *b)
26 {
27 return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6;
28 }
29
30 /* add columns to the @tb */
31 static void setup_columns(struct libscols_table *tb)
32 {
33 scols_table_enable_maxout(tb, 1);
34 if (!scols_table_new_column(tb, "#NUM", 0.1, SCOLS_FL_RIGHT))
35 goto fail;
36 if (!scols_table_new_column(tb, "DATA", 0.7, 0))
37 goto fail;
38 if (!scols_table_new_column(tb, "TIME", 0.2, 0))
39 goto fail;
40 return;
41 fail:
42 scols_unref_table(tb);
43 err(EXIT_FAILURE, "failed to create output columns");
44 }
45
46 static struct libscols_line *add_line(struct libscols_table *tb, size_t i)
47 {
48 char *p;
49 struct libscols_line *ln = scols_table_new_line(tb, NULL);
50
51 if (!ln)
52 err(EXIT_FAILURE, "failed to create output line");
53
54 xasprintf(&p, "%zu", i);
55 if (scols_line_refer_data(ln, COL_NUM, p))
56 goto fail;
57
58 xasprintf(&p, "data-%02zu-%02zu-%02zu-end", i + 1, i + 2, i + 3);
59 if (scols_line_refer_data(ln, COL_DATA, p))
60 goto fail;
61
62 return ln;
63 fail:
64 scols_unref_table(tb);
65 err(EXIT_FAILURE, "failed to create output line");
66 }
67
68 int main(int argc, char *argv[])
69 {
70 struct libscols_table *tb;
71 size_t i;
72 const size_t timecellsz = sizeof(stringify_value(UINT_MAX));
73 struct timeval last;
74
75 scols_init_debug(0);
76
77 tb = scols_new_table();
78 if (!tb)
79 err(EXIT_FAILURE, "failed to create output table");
80
81 setup_columns(tb);
82 gettimeofday(&last, NULL);
83
84 for (i = 0; i < 10; i++) {
85 struct libscols_line *line;
86 struct timeval now;
87 int done = 0;
88 char *timecell = xmalloc( timecellsz );
89
90 line = add_line(tb, i);
91
92 /* Make a reference from cell data to the buffer, then we can
93 * update cell data without any interaction with libsmartcols
94 */
95 if (scols_line_refer_data(line, COL_TIME, timecell) != 0)
96 err(EXIT_FAILURE, "failed to add data to table");
97
98 do {
99 double diff;
100
101 gettimeofday(&now, NULL);
102 diff = time_diff(&now, &last);
103
104 if (now.tv_sec == last.tv_sec + (long) TIME_PERIOD)
105 done = 1;
106 else
107 xusleep(100000);
108
109 /* update "TIME" cell data */
110 snprintf(timecell, timecellsz, "%f [%3d%%]", diff,
111 done ? 100 : (int)(diff / (TIME_PERIOD / 100.0)));
112
113 /* Note that libsmartcols don't print \n for last line
114 * in the table, but if you print a line somewhere in
115 * the midle of the table you need
116 *
117 * scols_table_enable_nolinesep(tb, !done);
118 *
119 * to disable line breaks. In this example it's
120 * unnecessary as we print the latest line only.
121 */
122
123 /* print the line */
124 scols_table_print_range(tb, line, NULL);
125
126 if (!done) {
127 /* terminal is waiting for \n, fflush() to force output */
128 fflush(scols_table_get_stream(tb));
129 /* move to the begin of the line */
130 fputc('\r', scols_table_get_stream(tb));
131 } else
132 fputc('\n', scols_table_get_stream(tb));
133 } while (!done);
134
135 last = now;
136 }
137
138 scols_unref_table(tb);
139 return EXIT_SUCCESS;
140 }