2 * Copyright (c) 2010, Christof Hanke,
3 * RZG, Max-Planck-Institut f. Plasmaphysik.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <afsconfig.h>
29 #include <afs/param.h>
33 #include <sys/types.h>
35 #include <afs/afsutil.h>
36 #include <afs/tabular_output.h>
39 /* private structures */
41 struct util_TableRow {
47 int numColumns,sortByColumn;
48 int numRows, numAllocatedRows;
51 int *ColumnContentTypes;
52 int RowLength; /* number of character per Row */
53 /* Basic subentities */
54 struct util_TableRow *Header;
55 struct util_TableRow **Body;
56 struct util_TableRow *Footer;
57 /* output methods provided for this table */
58 int (*printHeader) (struct util_Table *Table);
59 int (*printFooter) (struct util_Table *Table);
60 int (*printBody) (struct util_Table *Table);
61 int (*printRow) (struct util_Table *, struct util_TableRow *);
64 /* private functions */
66 struct util_TableRow* newTableRow(struct util_Table *);
67 int printTableFooter_CSV(struct util_Table* Table);
68 int printTableHeader_CSV(struct util_Table* Table);
69 int printTableRow_CSV(struct util_Table* Table, struct util_TableRow *aTableRow);
70 int printTableFooter_ASCII(struct util_Table* Table);
71 int printTableHeader_ASCII(struct util_Table* Table);
72 int printTableRow_ASCII(struct util_Table* Table, struct util_TableRow *aTableRow);
73 int printTableFooter_HTML(struct util_Table* Table);
74 int printTableHeader_HTML(struct util_Table* Table);
75 int printTableRow_HTML(struct util_Table* Table, struct util_TableRow *aTableRow);
76 int findRowIndex(struct util_Table* Table, struct util_TableRow *aRow);
77 int do_setTableRow(struct util_Table *Table, struct util_TableRow *aRow, char **Contents);
85 util_setTableBodyRow(struct util_Table *Table, int RowIndex, char **Contents) {
86 struct util_TableRow *aRow;
88 if (RowIndex >= Table->numRows) {
91 aRow=Table->Body[RowIndex];
92 return do_setTableRow(Table,aRow,Contents);
95 int util_setTableFooter(struct util_Table * Table, char ** Contents) {
96 return do_setTableRow(Table,Table->Footer,Contents);
100 int util_setTableHeader(struct util_Table *Table, char ** Contents) {
101 return do_setTableRow(Table,Table->Header,Contents);
105 util_addTableBodyRow(struct util_Table *Table, char **Contents) {
106 struct util_TableRow *aRow;
110 /* Allocate more Rows if required. */
111 if (Table->numRows >= Table->numAllocatedRows) {
112 Table->numAllocatedRows += UTIL_T_NUMALLOC_ROW;
113 Table->Body=realloc(Table->Body,\
114 Table->numAllocatedRows*sizeof(struct util_TableRow*));
115 for (i=0;i<UTIL_T_NUMALLOC_ROW;i++) {
116 Table->Body[Table->numRows+i]=newTableRow(Table);
119 aRow=newTableRow(Table);
120 do_setTableRow(Table,aRow,Contents);
121 if (Table->sortByColumn >= 0) {
122 indx=findRowIndex(Table,aRow);
123 for (row=Table->numRows;row>indx;row--) {
124 for (col=0;col<Table->numColumns;col++) {
125 strncpy(Table->Body[row]->CellContents[col],
126 Table->Body[row-1]->CellContents[col],
127 UTIL_T_MAX_CELLCONTENT_LEN);
134 for (i=0;i<Table->numColumns;i++) {
135 strncpy(Table->Body[indx]->CellContents[i],Contents[i],\
136 UTIL_T_MAX_CELLCONTENT_LEN);
137 thisRowLength += min(strlen(Contents[i]),UTIL_T_MAX_CELLCONTENT_LEN);
139 if (thisRowLength > Table->RowLength)
140 Table->RowLength = thisRowLength;
141 return Table->numRows-1;
145 util_printTableBody(struct util_Table *Table) {
148 for (i=0;i<Table->numRows;i++)
149 Table->printRow(Table,Table->Body[i]);
154 util_printTable(struct util_Table *Table) {
155 Table->printHeader(Table);
156 Table->printBody(Table);
157 Table->printFooter(Table);
162 util_printTableHeader(struct util_Table *Table) {
163 Table->printHeader(Table);
168 util_printTableFooter(struct util_Table *Table) {
169 Table->printFooter(Table);
173 /* private functions */
176 do_setTableRow(struct util_Table *Table, struct util_TableRow *aRow, char **Contents) {
179 if ( Contents == NULL )
181 for (i=0;i<Table->numColumns;i++) {
182 strcpy(aRow->CellContents[i],Contents[i]);
183 thisRowLength += min(strlen(Contents[i]),UTIL_T_MAX_CELLCONTENT_LEN);
185 if (thisRowLength > Table->RowLength)
186 Table->RowLength = thisRowLength;
191 /* ASCII output functions */
194 printTableRow_ASCII(struct util_Table *Table, struct util_TableRow *aRow) {
200 printf("%c",UTIL_T_CELLSEPARATOR);
202 for (i=0;i< Table->numColumns-1;i++) {
203 if ( Table->ColumnContentTypes[i] == UTIL_T_CONTENTTYPE_STRING)
204 printf("%-*s%c",Table->ColumnWidths[i],aRow->CellContents[i],\
205 UTIL_T_CELLSEPARATOR);
207 printf("%*s%c",Table->ColumnWidths[i],aRow->CellContents[i],\
208 UTIL_T_CELLSEPARATOR);
210 if ( Table->ColumnContentTypes[i] == UTIL_T_CONTENTTYPE_STRING)
211 printf("%-*s %c\n",Table->ColumnWidths[i],aRow->CellContents[i],\
212 UTIL_T_CELLSEPARATOR);
214 printf("%*s %c\n",Table->ColumnWidths[i],aRow->CellContents[i],UTIL_T_CELLSEPARATOR);
219 printTableHeader_ASCII(struct util_Table *Table) {
222 printf("%c",UTIL_T_CELLSEPARATOR);
223 for(i=0;i<Table->RowLength;i++)
224 printf("%c",UTIL_T_ROWSEPARATOR);
225 printf("%c\n",UTIL_T_CELLSEPARATOR);
227 printTableRow_ASCII(Table,Table->Header);
229 printf("%c",UTIL_T_CELLSEPARATOR);
230 for(i=0;i<Table->RowLength;i++)
231 printf("%c",UTIL_T_ROWSEPARATOR);
232 printf("%c",UTIL_T_CELLSEPARATOR);
239 printTableFooter_ASCII(struct util_Table *Table) {
242 printf("%c",UTIL_T_CELLSEPARATOR);
243 for(i=0;i<Table->RowLength;i++)
244 printf("%c",UTIL_T_ROWSEPARATOR);
245 printf("%c",UTIL_T_CELLSEPARATOR);
248 printTableRow_ASCII(Table,Table->Footer);
249 printf("%c",UTIL_T_CELLSEPARATOR);
250 for(i=0;i<Table->RowLength;i++)
251 printf("%c",UTIL_T_ROWSEPARATOR);
252 printf("%c",UTIL_T_CELLSEPARATOR);
258 /* HTML output functions */
261 printTableRow_HTML(struct util_Table *Table, struct util_TableRow *aRow) {
267 if (aRow == Table->Header)
268 printf("\t\t<th>\n");
270 printf("\t\t<tr>\n");
272 for (i=0;i< Table->numColumns;i++) {
274 printf("%s",aRow->CellContents[i]);
275 printf("\t\t</td>\n");
277 if (aRow == Table->Header)
278 printf("\t\t</th>\n");
280 printf("\t\t</tr>\n");
286 printTableFooter_HTML(struct util_Table *Table) {
288 printf("</tbody>\n");
290 printf("<tfooter>\n");
291 printTableRow_HTML(Table,Table->Footer);
292 printf("</tfooter>\n");
294 printf("</table>\n");
299 printTableHeader_HTML (struct util_Table *Table) {
303 printTableRow_HTML(Table,Table->Header);
304 printf("</thead>\n");
310 /* CSV output functions */
313 printTableRow_CSV(struct util_Table *Table, struct util_TableRow *aRow) {
318 for (i=0;i<Table->numColumns-1;i++) {
319 printf("%s,",aRow->CellContents[i]);
321 printf("%s\n",aRow->CellContents[i]);
326 printTableHeader_CSV (struct util_Table *Table) {
327 return printTableRow_CSV(Table,Table->Header);
331 printTableFooter_CSV (struct util_Table *Table) {
332 return printTableRow_CSV(Table,Table->Footer);
339 util_newCellContents(struct util_Table* Table) {
340 char **CellContents=NULL;
343 if ( (CellContents=(char **) malloc( sizeof(char *) * Table->numColumns))\
345 fprintf(stderr,"Internal Error. Cannot allocate memory for new CellContents-array.\n");
348 for (i=0;i<Table->numColumns;i++) {
349 if ( (CellContents[i]=(char *) malloc(UTIL_T_MAX_CELLCONTENT_LEN)) == NULL) {
351 "Internal Error. Cannot allocate memory for new CellContents-array.\n");
354 CellContents[i][0]='\0';
361 util_newTable(int Type, int numColumns, char **ColumnHeaders, int *ColumnContentTypes, int *ColumnWidths, int sortByColumn) {
362 struct util_Table *Table=NULL;
365 if ( (Table=malloc(sizeof(struct util_Table))) == NULL) {
367 "Internal Error. Cannot allocate memory for new Table.\n");
371 Table->numColumns=numColumns;
373 if (sortByColumn < 0 || sortByColumn > numColumns) {
374 fprintf(stderr,"Invalid Table Sortkey: %d.\n", sortByColumn);
378 if (sortByColumn > 0 )
379 Table->sortByColumn=sortByColumn-1; /* externally, we treat the first
380 column as 1, internally as 0 */
381 Table->ColumnHeaders=ColumnHeaders;
382 Table->ColumnContentTypes=ColumnContentTypes;
383 Table->ColumnWidths=ColumnWidths;
385 for (i=0; i< numColumns;i++)
386 Table->RowLength += ColumnWidths[i]+1;
387 switch (Table->Type) {
388 case UTIL_T_TYPE_ASCII :
389 Table->printHeader=printTableHeader_ASCII;
390 Table->printFooter=printTableFooter_ASCII;
391 Table->printRow=printTableRow_ASCII;
393 case UTIL_T_TYPE_CSV :
394 Table->printHeader=printTableHeader_CSV;
395 Table->printFooter=printTableFooter_CSV;
396 Table->printRow=printTableRow_CSV;
398 case UTIL_T_TYPE_HTML :
399 Table->printHeader=printTableHeader_HTML;
400 Table->printFooter=printTableFooter_HTML;
401 Table->printRow=printTableRow_HTML;
404 fprintf(stderr,"Error. Invalid TableType: %d.\n", Table->Type);
408 Table->printBody=util_printTableBody;
409 Table->Header=newTableRow(Table);
410 do_setTableRow(Table,Table->Header,ColumnHeaders);
417 /* private Constructors */
419 struct util_TableRow*
420 newTableRow(struct util_Table* Table) {
421 struct util_TableRow *aRow =NULL;
423 if ( (aRow= (struct util_TableRow*) malloc(sizeof(struct util_TableRow))) == NULL) {
425 "Internal Error. Cannot allocate memory for new TableRow.\n");
428 aRow->CellContents=util_newCellContents(Table);
433 freeTableRow( struct util_Table* Table, struct util_TableRow *aRow) {
436 for (i=0;i<Table->numColumns;i++) {
437 free(aRow->CellContents[i]);
439 free(aRow->CellContents);
444 util_freeTable(struct util_Table *Table) {
447 freeTableRow(Table, Table->Header);
448 freeTableRow(Table, Table->Footer);
449 for(i=0;i<Table->numRows;i++) {
450 freeTableRow(Table, Table->Body[i]);
458 compareBodyRow(struct util_Table *Table, int RowIndx, struct util_TableRow *aRow) {
460 afs_int64 value1,value2;
461 if (Table->ColumnContentTypes[Table->sortByColumn] == UTIL_T_CONTENTTYPE_STRING) {
462 return strncmp(Table->Body[RowIndx]->CellContents[Table->sortByColumn],\
463 aRow->CellContents[Table->sortByColumn],UTIL_T_MAX_CELLCONTENT_LEN);
465 util_GetInt64(Table->Body[RowIndx]->CellContents[Table->sortByColumn],\
467 util_GetInt64(aRow->CellContents[Table->sortByColumn],&value2);
468 return ( value1 - value2 );
472 /* find correct index for new row by bi-secting the table */
474 findRowIndex(struct util_Table* Table, struct util_TableRow *aRow){
475 int cmp,best,lower,middle,upper;
478 if (Table->numRows == 0) {
481 /* Entry smaller than smallest so far */
482 if (compareBodyRow(Table,0,aRow) > 0) {
485 /* Entry larger than largest so far */
486 if (compareBodyRow(Table,Table->numRows-1,aRow) < 0) {
487 return Table->numRows;
491 upper= Table->numRows-1;
494 middle=(upper-lower)/2+lower;
495 cmp=compareBodyRow(Table,middle,aRow);
507 if (upper - lower < 2) {
508 if ( compareBodyRow(Table,lower,aRow) < 0 )