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 <afs/afsutil.h>
34 #include <afs/tabular_output.h>
36 /* private structures */
38 struct util_TableRow
{
44 int numColumns
,sortByColumn
;
45 int numRows
, numAllocatedRows
;
48 int *ColumnContentTypes
;
49 int RowLength
; /* number of character per Row */
50 /* Basic subentities */
51 struct util_TableRow
*Header
;
52 struct util_TableRow
**Body
;
53 struct util_TableRow
*Footer
;
54 /* output methods provided for this table */
55 int (*printHeader
) (struct util_Table
*Table
);
56 int (*printFooter
) (struct util_Table
*Table
);
57 int (*printBody
) (struct util_Table
*Table
);
58 int (*printRow
) (struct util_Table
*, struct util_TableRow
*);
61 /* private functions */
63 struct util_TableRow
* newTableRow(struct util_Table
*);
64 int printTableFooter_CSV(struct util_Table
* Table
);
65 int printTableHeader_CSV(struct util_Table
* Table
);
66 int printTableRow_CSV(struct util_Table
* Table
, struct util_TableRow
*aTableRow
);
67 int printTableFooter_ASCII(struct util_Table
* Table
);
68 int printTableHeader_ASCII(struct util_Table
* Table
);
69 int printTableRow_ASCII(struct util_Table
* Table
, struct util_TableRow
*aTableRow
);
70 int printTableFooter_HTML(struct util_Table
* Table
);
71 int printTableHeader_HTML(struct util_Table
* Table
);
72 int printTableRow_HTML(struct util_Table
* Table
, struct util_TableRow
*aTableRow
);
73 int findRowIndex(struct util_Table
* Table
, struct util_TableRow
*aRow
);
74 int do_setTableRow(struct util_Table
*Table
, struct util_TableRow
*aRow
, char **Contents
);
82 util_setTableBodyRow(struct util_Table
*Table
, int RowIndex
, char **Contents
) {
83 struct util_TableRow
*aRow
;
85 if (RowIndex
>= Table
->numRows
) {
88 aRow
=Table
->Body
[RowIndex
];
89 return do_setTableRow(Table
,aRow
,Contents
);
92 int util_setTableFooter(struct util_Table
* Table
, char ** Contents
) {
93 if (Table
->Footer
!= NULL
)
94 Table
->Footer
= newTableRow(Table
);
95 return do_setTableRow(Table
,Table
->Footer
,Contents
);
99 int util_setTableHeader(struct util_Table
*Table
, char ** Contents
) {
100 return do_setTableRow(Table
,Table
->Header
,Contents
);
104 util_addTableBodyRow(struct util_Table
*Table
, char **Contents
) {
105 struct util_TableRow
*aRow
;
109 /* Allocate more Rows if required. */
110 if (Table
->numRows
>= Table
->numAllocatedRows
) {
111 Table
->numAllocatedRows
+= UTIL_T_NUMALLOC_ROW
;
112 Table
->Body
=realloc(Table
->Body
,\
113 Table
->numAllocatedRows
*sizeof(struct util_TableRow
*));
114 for (i
=0;i
<UTIL_T_NUMALLOC_ROW
;i
++) {
115 Table
->Body
[Table
->numRows
+i
]=newTableRow(Table
);
118 aRow
=newTableRow(Table
);
119 do_setTableRow(Table
,aRow
,Contents
);
120 if (Table
->sortByColumn
>= 0) {
121 indx
=findRowIndex(Table
,aRow
);
122 for (row
=Table
->numRows
;row
>indx
;row
--) {
123 for (col
=0;col
<Table
->numColumns
;col
++) {
124 strncpy(Table
->Body
[row
]->CellContents
[col
],
125 Table
->Body
[row
-1]->CellContents
[col
],
126 UTIL_T_MAX_CELLCONTENT_LEN
);
133 for (i
=0;i
<Table
->numColumns
;i
++) {
134 strncpy(Table
->Body
[indx
]->CellContents
[i
],Contents
[i
],\
135 UTIL_T_MAX_CELLCONTENT_LEN
);
136 thisRowLength
+= min(strlen(Contents
[i
]),UTIL_T_MAX_CELLCONTENT_LEN
);
138 if (thisRowLength
> Table
->RowLength
)
139 Table
->RowLength
= thisRowLength
;
140 return Table
->numRows
-1;
144 util_printTableBody(struct util_Table
*Table
) {
147 for (i
=0;i
<Table
->numRows
;i
++)
148 Table
->printRow(Table
,Table
->Body
[i
]);
153 util_printTable(struct util_Table
*Table
) {
154 Table
->printHeader(Table
);
155 Table
->printBody(Table
);
156 Table
->printFooter(Table
);
161 util_printTableHeader(struct util_Table
*Table
) {
162 Table
->printHeader(Table
);
167 util_printTableFooter(struct util_Table
*Table
) {
168 Table
->printFooter(Table
);
172 /* private functions */
175 do_setTableRow(struct util_Table
*Table
, struct util_TableRow
*aRow
, char **Contents
) {
178 if ( Contents
== NULL
)
180 for (i
=0;i
<Table
->numColumns
;i
++) {
181 strcpy(aRow
->CellContents
[i
],Contents
[i
]);
182 thisRowLength
+= min(strlen(Contents
[i
]),UTIL_T_MAX_CELLCONTENT_LEN
);
184 if (thisRowLength
> Table
->RowLength
)
185 Table
->RowLength
= thisRowLength
;
190 /* ASCII output functions */
193 printTableRow_ASCII(struct util_Table
*Table
, struct util_TableRow
*aRow
) {
199 printf("%c",UTIL_T_CELLSEPARATOR
);
201 for (i
=0;i
< Table
->numColumns
-1;i
++) {
202 if ( Table
->ColumnContentTypes
[i
] == UTIL_T_CONTENTTYPE_STRING
)
203 printf("%-*s%c",Table
->ColumnWidths
[i
],aRow
->CellContents
[i
],\
204 UTIL_T_CELLSEPARATOR
);
206 printf("%*s%c",Table
->ColumnWidths
[i
],aRow
->CellContents
[i
],\
207 UTIL_T_CELLSEPARATOR
);
209 if ( Table
->ColumnContentTypes
[i
] == UTIL_T_CONTENTTYPE_STRING
)
210 printf("%-*s %c\n",Table
->ColumnWidths
[i
],aRow
->CellContents
[i
],\
211 UTIL_T_CELLSEPARATOR
);
213 printf("%*s %c\n",Table
->ColumnWidths
[i
],aRow
->CellContents
[i
],UTIL_T_CELLSEPARATOR
);
218 printTableHeader_ASCII(struct util_Table
*Table
) {
221 printf("%c",UTIL_T_CELLSEPARATOR
);
222 for(i
=0;i
<Table
->RowLength
;i
++)
223 printf("%c",UTIL_T_ROWSEPARATOR
);
224 printf("%c\n",UTIL_T_CELLSEPARATOR
);
226 printTableRow_ASCII(Table
,Table
->Header
);
228 printf("%c",UTIL_T_CELLSEPARATOR
);
229 for(i
=0;i
<Table
->RowLength
;i
++)
230 printf("%c",UTIL_T_ROWSEPARATOR
);
231 printf("%c",UTIL_T_CELLSEPARATOR
);
238 printTableFooter_ASCII(struct util_Table
*Table
) {
241 printf("%c",UTIL_T_CELLSEPARATOR
);
242 for(i
=0;i
<Table
->RowLength
;i
++)
243 printf("%c",UTIL_T_ROWSEPARATOR
);
244 printf("%c",UTIL_T_CELLSEPARATOR
);
247 printTableRow_ASCII(Table
,Table
->Footer
);
248 printf("%c",UTIL_T_CELLSEPARATOR
);
249 for(i
=0;i
<Table
->RowLength
;i
++)
250 printf("%c",UTIL_T_ROWSEPARATOR
);
251 printf("%c",UTIL_T_CELLSEPARATOR
);
257 /* HTML output functions */
260 printTableRow_HTML(struct util_Table
*Table
, struct util_TableRow
*aRow
) {
266 if (aRow
== Table
->Header
)
267 printf("\t\t<th>\n");
269 printf("\t\t<tr>\n");
271 for (i
=0;i
< Table
->numColumns
;i
++) {
273 printf("%s",aRow
->CellContents
[i
]);
274 printf("\t\t</td>\n");
276 if (aRow
== Table
->Header
)
277 printf("\t\t</th>\n");
279 printf("\t\t</tr>\n");
285 printTableFooter_HTML(struct util_Table
*Table
) {
287 printf("</tbody>\n");
289 printf("<tfooter>\n");
290 printTableRow_HTML(Table
,Table
->Footer
);
291 printf("</tfooter>\n");
293 printf("</table>\n");
298 printTableHeader_HTML (struct util_Table
*Table
) {
302 printTableRow_HTML(Table
,Table
->Header
);
303 printf("</thead>\n");
309 /* CSV output functions */
312 printTableRow_CSV(struct util_Table
*Table
, struct util_TableRow
*aRow
) {
317 for (i
=0;i
<Table
->numColumns
-1;i
++) {
318 printf("%s,",aRow
->CellContents
[i
]);
320 printf("%s\n",aRow
->CellContents
[i
]);
325 printTableHeader_CSV (struct util_Table
*Table
) {
326 return printTableRow_CSV(Table
,Table
->Header
);
330 printTableFooter_CSV (struct util_Table
*Table
) {
331 return printTableRow_CSV(Table
,Table
->Footer
);
338 util_newCellContents(struct util_Table
* Table
) {
339 char **CellContents
=NULL
;
342 if ( (CellContents
=malloc( sizeof(char *) * Table
->numColumns
))== NULL
) {
343 fprintf(stderr
,"Internal Error. Cannot allocate memory for new CellContents-array.\n");
346 for (i
=0;i
<Table
->numColumns
;i
++) {
347 if ( (CellContents
[i
]=malloc(UTIL_T_MAX_CELLCONTENT_LEN
)) == NULL
) {
349 "Internal Error. Cannot allocate memory for new CellContents-array.\n");
352 CellContents
[i
][0]='\0';
359 util_newTable(int Type
, int numColumns
, char **ColumnHeaders
, int *ColumnContentTypes
, int *ColumnWidths
, int sortByColumn
) {
360 struct util_Table
*Table
=NULL
;
363 if ( (Table
=malloc(sizeof(struct util_Table
))) == NULL
) {
365 "Internal Error. Cannot allocate memory for new Table.\n");
369 Table
->numColumns
=numColumns
;
371 Table
->numAllocatedRows
=0;
372 if (sortByColumn
< 0 || sortByColumn
> numColumns
) {
373 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
);
409 Table
->printBody
=util_printTableBody
;
410 Table
->Header
=newTableRow(Table
);
411 do_setTableRow(Table
,Table
->Header
,ColumnHeaders
);
418 /* private Constructors */
420 struct util_TableRow
*
421 newTableRow(struct util_Table
* Table
) {
422 struct util_TableRow
*aRow
=NULL
;
424 if ( (aRow
= malloc(sizeof(struct util_TableRow
))) == NULL
) {
426 "Internal Error. Cannot allocate memory for new TableRow.\n");
429 aRow
->CellContents
=util_newCellContents(Table
);
434 freeTableRow( struct util_Table
* Table
, struct util_TableRow
*aRow
) {
437 for (i
=0;i
<Table
->numColumns
;i
++) {
438 free(aRow
->CellContents
[i
]);
440 free(aRow
->CellContents
);
445 util_freeTable(struct util_Table
*Table
) {
448 freeTableRow(Table
, Table
->Header
);
449 freeTableRow(Table
, Table
->Footer
);
450 for(i
=0;i
<Table
->numRows
;i
++) {
451 freeTableRow(Table
, Table
->Body
[i
]);
459 compareBodyRow(struct util_Table
*Table
, int RowIndx
, struct util_TableRow
*aRow
) {
461 afs_int64 value1
,value2
;
462 if (Table
->ColumnContentTypes
[Table
->sortByColumn
] == UTIL_T_CONTENTTYPE_STRING
) {
463 return strncmp(Table
->Body
[RowIndx
]->CellContents
[Table
->sortByColumn
],\
464 aRow
->CellContents
[Table
->sortByColumn
],UTIL_T_MAX_CELLCONTENT_LEN
);
466 util_GetInt64(Table
->Body
[RowIndx
]->CellContents
[Table
->sortByColumn
],\
468 util_GetInt64(aRow
->CellContents
[Table
->sortByColumn
],&value2
);
469 return ( value1
- value2
);
473 /* find correct index for new row by bi-secting the table */
475 findRowIndex(struct util_Table
* Table
, struct util_TableRow
*aRow
){
476 int cmp
,lower
,middle
,upper
;
479 if (Table
->numRows
== 0) {
482 /* Entry smaller than smallest so far */
483 if (compareBodyRow(Table
,0,aRow
) > 0) {
486 /* Entry larger than largest so far */
487 if (compareBodyRow(Table
,Table
->numRows
-1,aRow
) < 0) {
488 return Table
->numRows
;
492 upper
= Table
->numRows
-1;
494 middle
=(upper
-lower
)/2+lower
;
495 cmp
=compareBodyRow(Table
,middle
,aRow
);
505 if (upper
- lower
< 2) {
506 if ( compareBodyRow(Table
,lower
,aRow
) < 0 )
512 AFS_UNREACHED(return(0));