1ad9b42bfSMasatake YAMATO /*
2ad9b42bfSMasatake YAMATO * Copyright (c) 2017 Masatake YAMATO
3ad9b42bfSMasatake YAMATO *
4ad9b42bfSMasatake YAMATO * This source code is released for free distribution under the terms of the
5ad9b42bfSMasatake YAMATO * GNU General Public License version 2 or (at your option) any later version.
6ad9b42bfSMasatake YAMATO *
7ad9b42bfSMasatake YAMATO */
8ad9b42bfSMasatake YAMATO #include "general.h" /* must always come first */
9ad9b42bfSMasatake YAMATO
10c2a93c9fSMasatake YAMATO #include "colprint_p.h"
11ad9b42bfSMasatake YAMATO #include "ptrarray.h"
12ad9b42bfSMasatake YAMATO #include "routines.h"
13ad9b42bfSMasatake YAMATO #include "strlist.h"
14ad9b42bfSMasatake YAMATO #include "vstring.h"
15ad9b42bfSMasatake YAMATO
16ad9b42bfSMasatake YAMATO #include <stdarg.h>
17ad9b42bfSMasatake YAMATO #include <stdio.h>
18ad9b42bfSMasatake YAMATO #include <string.h>
19ad9b42bfSMasatake YAMATO
20ad9b42bfSMasatake YAMATO
21ad9b42bfSMasatake YAMATO enum colprintJustification {
22ad9b42bfSMasatake YAMATO COLPRINT_LEFT, /* L:... */
23ad9b42bfSMasatake YAMATO COLPRINT_RIGHT, /* R:... */
24ad9b42bfSMasatake YAMATO COLPRINT_LAST,
25ad9b42bfSMasatake YAMATO };
26ad9b42bfSMasatake YAMATO
27ad9b42bfSMasatake YAMATO struct colprintHeaderColumn {
28ad9b42bfSMasatake YAMATO vString *value;
29ad9b42bfSMasatake YAMATO enum colprintJustification justification;
30ad9b42bfSMasatake YAMATO unsigned int maxWidth;
31ad9b42bfSMasatake YAMATO bool needPrefix;
32ad9b42bfSMasatake YAMATO };
33ad9b42bfSMasatake YAMATO
34ad9b42bfSMasatake YAMATO struct colprintTable {
35ad9b42bfSMasatake YAMATO ptrArray *header;
36ad9b42bfSMasatake YAMATO ptrArray *lines;
37ad9b42bfSMasatake YAMATO };
38ad9b42bfSMasatake YAMATO
fillWithWhitespaces(int i,FILE * fp)39ad9b42bfSMasatake YAMATO static void fillWithWhitespaces (int i, FILE *fp)
40ad9b42bfSMasatake YAMATO {
41ad9b42bfSMasatake YAMATO while (i-- > 0)
42ad9b42bfSMasatake YAMATO {
43ad9b42bfSMasatake YAMATO fputc(' ', fp);
44ad9b42bfSMasatake YAMATO }
45ad9b42bfSMasatake YAMATO }
46ad9b42bfSMasatake YAMATO
colprintHeaderColumnNew(const char * spec)47ad9b42bfSMasatake YAMATO static struct colprintHeaderColumn * colprintHeaderColumnNew (const char* spec)
48ad9b42bfSMasatake YAMATO {
49ad9b42bfSMasatake YAMATO int offset = 2;
50ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *headerCol = xCalloc (1, struct colprintHeaderColumn);
51ad9b42bfSMasatake YAMATO
52ad9b42bfSMasatake YAMATO if (strstr(spec, "L:") == spec)
53ad9b42bfSMasatake YAMATO headerCol->justification = COLPRINT_LEFT;
54ad9b42bfSMasatake YAMATO else if (strstr(spec, "R:") == spec)
55ad9b42bfSMasatake YAMATO headerCol->justification = COLPRINT_RIGHT;
56ad9b42bfSMasatake YAMATO else
57ad9b42bfSMasatake YAMATO {
58ad9b42bfSMasatake YAMATO headerCol->justification = COLPRINT_LEFT;
59ad9b42bfSMasatake YAMATO offset = 0;
60ad9b42bfSMasatake YAMATO }
61ad9b42bfSMasatake YAMATO
62ad9b42bfSMasatake YAMATO headerCol->value = vStringNewInit(spec + offset);
63ad9b42bfSMasatake YAMATO headerCol->maxWidth = vStringLength(headerCol->value);
64ad9b42bfSMasatake YAMATO return headerCol;
65ad9b42bfSMasatake YAMATO }
66ad9b42bfSMasatake YAMATO
colprintHeaderColumnDelete(struct colprintHeaderColumn * headerCol)67ad9b42bfSMasatake YAMATO static void colprintHeaderColumnDelete (struct colprintHeaderColumn * headerCol)
68ad9b42bfSMasatake YAMATO {
69ad9b42bfSMasatake YAMATO vStringDelete (headerCol->value);
70ad9b42bfSMasatake YAMATO eFree (headerCol);
71ad9b42bfSMasatake YAMATO }
72ad9b42bfSMasatake YAMATO
colprintTableNew(const char * columnHeader,...)73ad9b42bfSMasatake YAMATO struct colprintTable *colprintTableNew (const char* columnHeader, ... /* NULL TERMINATED */)
74ad9b42bfSMasatake YAMATO {
75ad9b42bfSMasatake YAMATO char *tmp;
76ad9b42bfSMasatake YAMATO va_list ap;
77ad9b42bfSMasatake YAMATO struct colprintTable *table;
78ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *headerCol;
79ad9b42bfSMasatake YAMATO
80ad9b42bfSMasatake YAMATO
81ad9b42bfSMasatake YAMATO table = xCalloc (1, struct colprintTable);
82ad9b42bfSMasatake YAMATO table->header = ptrArrayNew ((ptrArrayDeleteFunc)colprintHeaderColumnDelete);
83ad9b42bfSMasatake YAMATO table->lines = ptrArrayNew ((ptrArrayDeleteFunc)stringListDelete);
84ad9b42bfSMasatake YAMATO
85ad9b42bfSMasatake YAMATO headerCol = colprintHeaderColumnNew(columnHeader);
86ad9b42bfSMasatake YAMATO ptrArrayAdd (table->header, headerCol);
87ad9b42bfSMasatake YAMATO
88ad9b42bfSMasatake YAMATO va_start(ap, columnHeader);
89ad9b42bfSMasatake YAMATO while (1)
90ad9b42bfSMasatake YAMATO {
91ad9b42bfSMasatake YAMATO tmp = va_arg(ap, char*);
92ad9b42bfSMasatake YAMATO if (tmp)
93ad9b42bfSMasatake YAMATO {
94ad9b42bfSMasatake YAMATO headerCol = colprintHeaderColumnNew(tmp);
95ad9b42bfSMasatake YAMATO ptrArrayAdd (table->header, headerCol);
96ad9b42bfSMasatake YAMATO }
97ad9b42bfSMasatake YAMATO else
98ad9b42bfSMasatake YAMATO break;
99ad9b42bfSMasatake YAMATO }
100ad9b42bfSMasatake YAMATO va_end(ap);
101ad9b42bfSMasatake YAMATO
102ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *last_col = ptrArrayLast (table->header);
103ad9b42bfSMasatake YAMATO if (last_col)
104ad9b42bfSMasatake YAMATO last_col->justification = COLPRINT_LAST;
105ad9b42bfSMasatake YAMATO
106ad9b42bfSMasatake YAMATO return table;
107ad9b42bfSMasatake YAMATO }
108ad9b42bfSMasatake YAMATO
colprintTableDelete(struct colprintTable * table)109ad9b42bfSMasatake YAMATO void colprintTableDelete (struct colprintTable *table)
110ad9b42bfSMasatake YAMATO {
111ad9b42bfSMasatake YAMATO ptrArrayDelete(table->header);
112ad9b42bfSMasatake YAMATO table->header = NULL;
113ad9b42bfSMasatake YAMATO
114ad9b42bfSMasatake YAMATO ptrArrayDelete(table->lines);
115ad9b42bfSMasatake YAMATO table->header = NULL;
116ad9b42bfSMasatake YAMATO
117ad9b42bfSMasatake YAMATO eFree (table);
118ad9b42bfSMasatake YAMATO }
119ad9b42bfSMasatake YAMATO
colprintColumnPrintGeneric(vString * column,struct colprintHeaderColumn * spec,bool machinable,FILE * fp)120ad9b42bfSMasatake YAMATO static void colprintColumnPrintGeneric (vString *column, struct colprintHeaderColumn *spec, bool machinable, FILE *fp)
121ad9b42bfSMasatake YAMATO {
122ad9b42bfSMasatake YAMATO int maxWidth = spec->maxWidth + (spec->needPrefix? 1: 0);
123ad9b42bfSMasatake YAMATO
124ad9b42bfSMasatake YAMATO if ((column == spec->value) && (spec->needPrefix))
125ad9b42bfSMasatake YAMATO {
126ad9b42bfSMasatake YAMATO fputc('#', fp);
127ad9b42bfSMasatake YAMATO maxWidth--;
128ad9b42bfSMasatake YAMATO }
129ad9b42bfSMasatake YAMATO
130ad9b42bfSMasatake YAMATO if (machinable)
131ad9b42bfSMasatake YAMATO {
132ad9b42bfSMasatake YAMATO fputs (vStringValue (column), fp);
133ad9b42bfSMasatake YAMATO if (spec->justification != COLPRINT_LAST)
134ad9b42bfSMasatake YAMATO fputc ('\t', fp);
135ad9b42bfSMasatake YAMATO }
136ad9b42bfSMasatake YAMATO else
137ad9b42bfSMasatake YAMATO {
138ad9b42bfSMasatake YAMATO int padLen = maxWidth - vStringLength (column);
139ad9b42bfSMasatake YAMATO if (spec->justification == COLPRINT_LEFT
140ad9b42bfSMasatake YAMATO || spec->justification == COLPRINT_LAST)
141ad9b42bfSMasatake YAMATO {
142ad9b42bfSMasatake YAMATO fputs (vStringValue (column), fp);
143ad9b42bfSMasatake YAMATO if (spec->justification != COLPRINT_LAST)
144ad9b42bfSMasatake YAMATO {
145ad9b42bfSMasatake YAMATO fillWithWhitespaces (padLen, fp);
146ad9b42bfSMasatake YAMATO fputc (' ', fp);
147ad9b42bfSMasatake YAMATO }
148ad9b42bfSMasatake YAMATO }
149ad9b42bfSMasatake YAMATO else
150ad9b42bfSMasatake YAMATO {
151ad9b42bfSMasatake YAMATO fillWithWhitespaces (padLen, fp);
152ad9b42bfSMasatake YAMATO fputs (vStringValue (column), fp);
153ad9b42bfSMasatake YAMATO fputc (' ', fp);
154ad9b42bfSMasatake YAMATO }
155ad9b42bfSMasatake YAMATO }
156ad9b42bfSMasatake YAMATO }
157ad9b42bfSMasatake YAMATO
colprintHeaderColumnPrint(struct colprintHeaderColumn * headerCol,bool machinable,FILE * fp)158ad9b42bfSMasatake YAMATO static void colprintHeaderColumnPrint (struct colprintHeaderColumn *headerCol, bool machinable, FILE* fp)
159ad9b42bfSMasatake YAMATO {
160ad9b42bfSMasatake YAMATO colprintColumnPrintGeneric (headerCol->value, headerCol, machinable, fp);
161ad9b42bfSMasatake YAMATO }
162ad9b42bfSMasatake YAMATO
colprintHeaderPrint(ptrArray * header,unsigned int startFrom,bool withHeader,bool machinable,FILE * fp)163*dda65607SColomban Wendling static void colprintHeaderPrint (ptrArray *header, unsigned int startFrom, bool withHeader, bool machinable, FILE *fp)
164ad9b42bfSMasatake YAMATO {
165ad9b42bfSMasatake YAMATO unsigned int i;
166ad9b42bfSMasatake YAMATO
167ad9b42bfSMasatake YAMATO if (!withHeader)
168ad9b42bfSMasatake YAMATO return;
169ad9b42bfSMasatake YAMATO
170ad9b42bfSMasatake YAMATO for (i = startFrom; i < ptrArrayCount(header); i++)
171ad9b42bfSMasatake YAMATO {
172ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *headerCol = ptrArrayItem (header, i);
173ad9b42bfSMasatake YAMATO colprintHeaderColumnPrint (headerCol, machinable, fp);
174ad9b42bfSMasatake YAMATO }
175ad9b42bfSMasatake YAMATO fputc('\n', fp);
176ad9b42bfSMasatake YAMATO }
177ad9b42bfSMasatake YAMATO
colprintLinePrint(stringList * line,unsigned int startFrom,ptrArray * header,bool machinable,FILE * fp)178*dda65607SColomban Wendling static void colprintLinePrint (stringList *line, unsigned int startFrom, ptrArray *header, bool machinable, FILE *fp)
179ad9b42bfSMasatake YAMATO {
180ad9b42bfSMasatake YAMATO unsigned int i;
181ad9b42bfSMasatake YAMATO
182ad9b42bfSMasatake YAMATO for (i = startFrom; i < stringListCount (line); i++)
183ad9b42bfSMasatake YAMATO {
184ad9b42bfSMasatake YAMATO vString *value = stringListItem(line, i);
185ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *spec = ptrArrayItem (header, i);
186ad9b42bfSMasatake YAMATO colprintColumnPrintGeneric(value, spec, machinable, fp);
187ad9b42bfSMasatake YAMATO }
188ad9b42bfSMasatake YAMATO }
colprintLinesPrint(ptrArray * lines,unsigned int startFrom,ptrArray * header,bool machinable,FILE * fp)189*dda65607SColomban Wendling static void colprintLinesPrint (ptrArray *lines, unsigned int startFrom, ptrArray *header, bool machinable, FILE *fp)
190ad9b42bfSMasatake YAMATO {
191ad9b42bfSMasatake YAMATO unsigned int i;
192ad9b42bfSMasatake YAMATO
193ad9b42bfSMasatake YAMATO for (i = 0; i < ptrArrayCount (lines); i++)
194ad9b42bfSMasatake YAMATO {
195ad9b42bfSMasatake YAMATO stringList *line = ptrArrayItem (lines, i);
196ad9b42bfSMasatake YAMATO colprintLinePrint (line, startFrom, header, machinable, fp);
197ad9b42bfSMasatake YAMATO fputc('\n', fp);
198ad9b42bfSMasatake YAMATO }
199ad9b42bfSMasatake YAMATO }
200ad9b42bfSMasatake YAMATO
colprintUpdateMaxWidths(ptrArray * header,ptrArray * lines,unsigned int startFrom)201ad9b42bfSMasatake YAMATO static void colprintUpdateMaxWidths (ptrArray *header, ptrArray *lines, unsigned int startFrom)
202ad9b42bfSMasatake YAMATO {
203ad9b42bfSMasatake YAMATO for (unsigned int c = 0; c < ptrArrayCount(header); c++)
204ad9b42bfSMasatake YAMATO {
205ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *spec = ptrArrayItem (header, c);
206ad9b42bfSMasatake YAMATO
207ad9b42bfSMasatake YAMATO if (c == startFrom)
208ad9b42bfSMasatake YAMATO spec->needPrefix = true;
209ad9b42bfSMasatake YAMATO else
210ad9b42bfSMasatake YAMATO spec->needPrefix = false;
211ad9b42bfSMasatake YAMATO }
212ad9b42bfSMasatake YAMATO
213ad9b42bfSMasatake YAMATO for (unsigned int c = 0; c < ptrArrayCount(header); c++)
214ad9b42bfSMasatake YAMATO {
215ad9b42bfSMasatake YAMATO struct colprintHeaderColumn *spec = ptrArrayItem (header, c);
216ad9b42bfSMasatake YAMATO
217ad9b42bfSMasatake YAMATO for (unsigned int l = 0; l < ptrArrayCount(lines); l++)
218ad9b42bfSMasatake YAMATO {
219ad9b42bfSMasatake YAMATO struct colprintLine *line = ptrArrayItem(lines, l);
220ad9b42bfSMasatake YAMATO vString *column = ptrArrayItem((ptrArray *)line, c);
221ad9b42bfSMasatake YAMATO if (spec->maxWidth < vStringLength(column))
222ad9b42bfSMasatake YAMATO spec->maxWidth = vStringLength(column);
223ad9b42bfSMasatake YAMATO }
224ad9b42bfSMasatake YAMATO }
225ad9b42bfSMasatake YAMATO }
226ad9b42bfSMasatake YAMATO
colprintTablePrint(struct colprintTable * table,unsigned int startFrom,bool withHeader,bool machinable,FILE * fp)227ad9b42bfSMasatake YAMATO void colprintTablePrint (struct colprintTable *table, unsigned int startFrom, bool withHeader, bool machinable, FILE *fp)
228ad9b42bfSMasatake YAMATO {
229ad9b42bfSMasatake YAMATO colprintUpdateMaxWidths (table->header, table->lines, startFrom);
230ad9b42bfSMasatake YAMATO
231ad9b42bfSMasatake YAMATO colprintHeaderPrint (table->header, startFrom, withHeader, machinable, fp);
232ad9b42bfSMasatake YAMATO colprintLinesPrint (table->lines, startFrom, table->header, machinable, fp);
233ad9b42bfSMasatake YAMATO }
234ad9b42bfSMasatake YAMATO
colprintTableSort(struct colprintTable * table,int (* compareFn)(struct colprintLine *,struct colprintLine *))235ad9b42bfSMasatake YAMATO void colprintTableSort (struct colprintTable *table, int (* compareFn) (struct colprintLine *, struct colprintLine *))
236ad9b42bfSMasatake YAMATO {
237ad9b42bfSMasatake YAMATO ptrArraySort (table->lines, (int (*) (const void *, const void *))compareFn);
238ad9b42bfSMasatake YAMATO }
239ad9b42bfSMasatake YAMATO
colprintTableGetNewLine(struct colprintTable * table)240ad9b42bfSMasatake YAMATO struct colprintLine *colprintTableGetNewLine (struct colprintTable *table)
241ad9b42bfSMasatake YAMATO {
242ad9b42bfSMasatake YAMATO stringList *line = stringListNew ();
243ad9b42bfSMasatake YAMATO
244ad9b42bfSMasatake YAMATO ptrArrayAdd (table->lines, line);
245ad9b42bfSMasatake YAMATO return (struct colprintLine *)line;
246ad9b42bfSMasatake YAMATO }
247ad9b42bfSMasatake YAMATO
colprintLineAppendColumn(struct colprintLine * line,vString * column)248ad9b42bfSMasatake YAMATO static void colprintLineAppendColumn (struct colprintLine *line, vString *column)
249ad9b42bfSMasatake YAMATO {
250ad9b42bfSMasatake YAMATO stringList *slist = (stringList *)line;
251ad9b42bfSMasatake YAMATO stringListAdd (slist, column);
252ad9b42bfSMasatake YAMATO }
253ad9b42bfSMasatake YAMATO
colprintLineAppendColumnCString(struct colprintLine * line,const char * column)254ad9b42bfSMasatake YAMATO void colprintLineAppendColumnCString (struct colprintLine *line, const char *column)
255ad9b42bfSMasatake YAMATO {
256ad9b42bfSMasatake YAMATO vString* vcol = vStringNewInit (column? column: "");
257ad9b42bfSMasatake YAMATO colprintLineAppendColumn (line, vcol);
258ad9b42bfSMasatake YAMATO }
259ad9b42bfSMasatake YAMATO
colprintLineAppendColumnVString(struct colprintLine * line,vString * column)260ad9b42bfSMasatake YAMATO void colprintLineAppendColumnVString (struct colprintLine *line, vString* column)
261ad9b42bfSMasatake YAMATO {
262ad9b42bfSMasatake YAMATO colprintLineAppendColumnCString(line, vStringValue (column));
263ad9b42bfSMasatake YAMATO }
264ad9b42bfSMasatake YAMATO
colprintLineAppendColumnChar(struct colprintLine * line,char column)265ad9b42bfSMasatake YAMATO void colprintLineAppendColumnChar (struct colprintLine *line, char column)
266ad9b42bfSMasatake YAMATO {
267ad9b42bfSMasatake YAMATO vString* vcol = vStringNew ();
268ad9b42bfSMasatake YAMATO vStringPut (vcol, column);
269ad9b42bfSMasatake YAMATO colprintLineAppendColumn (line, vcol);
270ad9b42bfSMasatake YAMATO }
271ad9b42bfSMasatake YAMATO
colprintLineAppendColumnInt(struct colprintLine * line,unsigned int column)272ad9b42bfSMasatake YAMATO void colprintLineAppendColumnInt (struct colprintLine *line, unsigned int column)
273ad9b42bfSMasatake YAMATO {
274ad9b42bfSMasatake YAMATO char buf[12];
275ad9b42bfSMasatake YAMATO
27659d98f39SMasatake YAMATO snprintf(buf, 12, "%u", column);
277ad9b42bfSMasatake YAMATO colprintLineAppendColumnCString (line, buf);
278ad9b42bfSMasatake YAMATO }
279ad9b42bfSMasatake YAMATO
colprintLineAppendColumnBool(struct colprintLine * line,bool column)280232cabfcSMasatake YAMATO void colprintLineAppendColumnBool (struct colprintLine *line, bool column)
281232cabfcSMasatake YAMATO {
282232cabfcSMasatake YAMATO colprintLineAppendColumnCString (line, column? "yes": "no");
283232cabfcSMasatake YAMATO }
284232cabfcSMasatake YAMATO
colprintLineGetColumn(struct colprintLine * line,unsigned int column)285ad9b42bfSMasatake YAMATO const char *colprintLineGetColumn (struct colprintLine *line, unsigned int column)
286ad9b42bfSMasatake YAMATO {
287ad9b42bfSMasatake YAMATO stringList *slist = (stringList *)line;
288ad9b42bfSMasatake YAMATO if (column <= stringListCount(slist))
289ad9b42bfSMasatake YAMATO {
290ad9b42bfSMasatake YAMATO vString *vstr = stringListItem (slist, column);
291ad9b42bfSMasatake YAMATO return vStringValue (vstr);
292ad9b42bfSMasatake YAMATO }
293ad9b42bfSMasatake YAMATO else
294ad9b42bfSMasatake YAMATO return NULL;
295ad9b42bfSMasatake YAMATO }
296