version 1.1, 2010/10/15 19:20:03 |
version 1.2, 2010/10/15 21:33:47 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> |
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> |
|
* Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
|
#include "out.h" |
|
#include "term.h" |
#include "tbl_extern.h" |
#include "tbl_extern.h" |
|
|
/* FIXME: `n' modifier doesn't always do the right thing. */ |
/* FIXME: `n' modifier doesn't always do the right thing. */ |
|
|
static void calc_data_literal(struct tbl_data *); |
static void calc_data_literal(struct tbl_data *); |
static void calc_data_number(struct tbl_data *); |
static void calc_data_number(struct tbl_data *); |
static void calc_data_spanner(struct tbl_data *); |
static void calc_data_spanner(struct tbl_data *); |
static inline void write_char(char, int); |
static inline void write_char(struct termp *, char, int); |
static void write_data(const struct tbl_data *, int); |
static void write_data(struct termp *, |
static void write_data_literal(const struct tbl_data *, int); |
const struct tbl_data *, int); |
static void write_data_number(const struct tbl_data *, int); |
static void write_data_literal(struct termp *, |
static void write_data_spanner(const struct tbl_data *, int); |
const struct tbl_data *, int); |
static void write_hframe(const struct tbl *); |
static void write_data_number(struct termp *, |
static void write_hrule(const struct tbl_span *); |
const struct tbl_data *, int); |
static void write_spanner(const struct tbl_head *); |
static void write_data_spanner(struct termp *, |
static void write_vframe(const struct tbl *); |
const struct tbl_data *, int); |
|
static void write_hframe(struct termp *, const struct tbl *); |
|
static void write_hrule(struct termp *, const struct tbl_span *); |
|
static void write_spanner(struct termp *, const struct tbl_head *); |
|
static void write_vframe(struct termp *, const struct tbl *); |
|
|
|
|
int |
int |
tbl_write_term(const struct tbl *tbl) |
tbl_write_term(struct termp *p, const struct tbl *tbl) |
{ |
{ |
const struct tbl_span *span; |
const struct tbl_span *span; |
const struct tbl_data *data; |
const struct tbl_data *data; |
|
|
* were set when tbl_calc_term was called. |
* were set when tbl_calc_term was called. |
*/ |
*/ |
|
|
|
term_newln(p); |
|
p->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; |
|
|
/* First, write out our head horizontal frame. */ |
/* First, write out our head horizontal frame. */ |
|
|
write_hframe(tbl); |
write_hframe(p, tbl); |
|
|
/* |
/* |
* Iterate through each span, and inside, through the global |
* Iterate through each span, and inside, through the global |
|
|
*/ |
*/ |
|
|
TAILQ_FOREACH(span, &tbl->span, entries) { |
TAILQ_FOREACH(span, &tbl->span, entries) { |
write_vframe(tbl); |
write_vframe(p, tbl); |
|
|
/* Accomodate for the horizontal rule. */ |
/* Accomodate for the horizontal rule. */ |
if (TBL_DATA_DHORIZ & span->flags || |
if (TBL_DATA_DHORIZ & span->flags || |
TBL_DATA_HORIZ & span->flags) { |
TBL_DATA_HORIZ & span->flags) { |
write_hrule(span); |
write_hrule(p, span); |
write_vframe(tbl); |
write_vframe(p, tbl); |
printf("\n"); |
term_flushln(p); |
continue; |
continue; |
} |
} |
|
|
|
|
case (TBL_HEAD_VERT): |
case (TBL_HEAD_VERT): |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case (TBL_HEAD_DVERT): |
case (TBL_HEAD_DVERT): |
write_spanner(head); |
write_spanner(p, head); |
break; |
break; |
case (TBL_HEAD_DATA): |
case (TBL_HEAD_DATA): |
write_data(data, head->width); |
write_data(p, data, head->width); |
if (data) |
if (data) |
data = TAILQ_NEXT(data, entries); |
data = TAILQ_NEXT(data, entries); |
break; |
break; |
|
|
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
} |
} |
write_vframe(tbl); |
write_vframe(p, tbl); |
printf("\n"); |
term_flushln(p); |
} |
} |
|
|
/* Last, write out our tail horizontal frame. */ |
/* Last, write out our tail horizontal frame. */ |
|
|
write_hframe(tbl); |
write_hframe(p, tbl); |
|
|
|
p->flags &= ~TERMP_NONOSPACE; |
|
|
return(1); |
return(1); |
} |
} |
|
|
|
|
|
|
|
|
static void |
static void |
write_hrule(const struct tbl_span *span) |
write_hrule(struct termp *p, const struct tbl_span *span) |
{ |
{ |
const struct tbl_head *head; |
const struct tbl_head *head; |
char c; |
char c; |
|
|
TAILQ_FOREACH(head, &span->tbl->head, entries) { |
TAILQ_FOREACH(head, &span->tbl->head, entries) { |
switch (head->pos) { |
switch (head->pos) { |
case (TBL_HEAD_DATA): |
case (TBL_HEAD_DATA): |
write_char(c, head->width); |
write_char(p, c, head->width); |
break; |
break; |
case (TBL_HEAD_DVERT): |
case (TBL_HEAD_DVERT): |
write_char('+', head->width); |
write_char(p, '+', head->width); |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case (TBL_HEAD_VERT): |
case (TBL_HEAD_VERT): |
write_char('+', head->width); |
write_char(p, '+', head->width); |
break; |
break; |
default: |
default: |
abort(); |
abort(); |
|
|
|
|
|
|
static void |
static void |
write_hframe(const struct tbl *tbl) |
write_hframe(struct termp *p, const struct tbl *tbl) |
{ |
{ |
const struct tbl_head *head; |
const struct tbl_head *head; |
|
|
|
|
*/ |
*/ |
|
|
if (TBL_OPT_DBOX & tbl->opts) { |
if (TBL_OPT_DBOX & tbl->opts) { |
printf("+"); |
term_word(p, "+"); |
TAILQ_FOREACH(head, &tbl->head, entries) |
TAILQ_FOREACH(head, &tbl->head, entries) |
write_char('-', head->width); |
write_char(p, '-', head->width); |
printf("+\n"); |
term_word(p, "+"); |
|
term_flushln(p); |
} |
} |
|
|
printf("+"); |
term_word(p, "+"); |
TAILQ_FOREACH(head, &tbl->head, entries) { |
TAILQ_FOREACH(head, &tbl->head, entries) { |
switch (head->pos) { |
switch (head->pos) { |
case (TBL_HEAD_DATA): |
case (TBL_HEAD_DATA): |
write_char('-', head->width); |
write_char(p, '-', head->width); |
break; |
break; |
default: |
default: |
write_char('+', head->width); |
write_char(p, '+', head->width); |
break; |
break; |
} |
} |
} |
} |
printf("+\n"); |
term_word(p, "+"); |
|
term_flushln(p); |
} |
} |
|
|
|
|
static void |
static void |
write_vframe(const struct tbl *tbl) |
write_vframe(struct termp *p, const struct tbl *tbl) |
{ |
{ |
/* Always just a single vertical line. */ |
/* Always just a single vertical line. */ |
|
|
if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)) |
if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)) |
return; |
return; |
printf("|"); |
term_word(p, "|"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
static void |
static void |
write_data_spanner(const struct tbl_data *data, int width) |
write_data_spanner(struct termp *p, const struct tbl_data *data, int width) |
{ |
{ |
|
|
/* |
/* |
|
|
* layout) or as data. |
* layout) or as data. |
*/ |
*/ |
if (TBL_DATA_HORIZ & data->flags) |
if (TBL_DATA_HORIZ & data->flags) |
write_char('-', width); |
write_char(p, '-', width); |
else if (TBL_DATA_DHORIZ & data->flags) |
else if (TBL_DATA_DHORIZ & data->flags) |
write_char('=', width); |
write_char(p, '=', width); |
else if (TBL_CELL_HORIZ == data->cell->pos) |
else if (TBL_CELL_HORIZ == data->cell->pos) |
write_char('-', width); |
write_char(p, '-', width); |
else if (TBL_CELL_DHORIZ == data->cell->pos) |
else if (TBL_CELL_DHORIZ == data->cell->pos) |
write_char('=', width); |
write_char(p, '=', width); |
} |
} |
|
|
|
|
static void |
static void |
write_data_number(const struct tbl_data *data, int width) |
write_data_number(struct termp *p, const struct tbl_data *data, int width) |
{ |
{ |
char *dp, pnt; |
char *dp, pnt; |
int d, padl, sz; |
int d, padl, sz; |
|
|
padl = data->cell->head->decimal - d + 1; |
padl = data->cell->head->decimal - d + 1; |
assert(width - sz - padl); |
assert(width - sz - padl); |
|
|
write_char(' ', padl); |
write_char(p, ' ', padl); |
(void)printf("%s", data->string); |
term_word(p, data->string); |
write_char(' ', width - sz - padl); |
write_char(p, ' ', width - sz - padl); |
} |
} |
|
|
|
|
static void |
static void |
write_data_literal(const struct tbl_data *data, int width) |
write_data_literal(struct termp *p, const struct tbl_data *data, int width) |
{ |
{ |
int padl, padr; |
int padl, padr; |
|
|
|
|
switch (data->cell->pos) { |
switch (data->cell->pos) { |
case (TBL_CELL_LONG): |
case (TBL_CELL_LONG): |
padl = 1; |
padl = 1; |
padr = width - (int)strlen(data->string) - 1; |
padr = width - (int)term_strlen(p, data->string) - 1; |
break; |
break; |
case (TBL_CELL_CENTRE): |
case (TBL_CELL_CENTRE): |
padl = width - (int)strlen(data->string); |
padl = width - (int)term_strlen(p, data->string); |
if (padl % 2) |
if (padl % 2) |
padr++; |
padr++; |
padl /= 2; |
padl /= 2; |
padr += padl; |
padr += padl; |
break; |
break; |
case (TBL_CELL_RIGHT): |
case (TBL_CELL_RIGHT): |
padl = width - (int)strlen(data->string); |
padl = width - (int)term_strlen(p, data->string); |
break; |
break; |
default: |
default: |
padr = width - (int)strlen(data->string); |
padr = width - (int)term_strlen(p, data->string); |
break; |
break; |
} |
} |
|
|
write_char(' ', padl); |
write_char(p, ' ', padl); |
(void)printf("%s", data->string); |
term_word(p, data->string); |
write_char(' ', padr); |
write_char(p, ' ', padr); |
} |
} |
|
|
|
|
static void |
static void |
write_data(const struct tbl_data *data, int width) |
write_data(struct termp *p, const struct tbl_data *data, int width) |
{ |
{ |
|
|
if (NULL == data) { |
if (NULL == data) { |
write_char(' ', width); |
write_char(p, ' ', width); |
return; |
return; |
} |
} |
|
|
if (TBL_DATA_HORIZ & data->flags || |
if (TBL_DATA_HORIZ & data->flags || |
TBL_DATA_DHORIZ & data->flags) { |
TBL_DATA_DHORIZ & data->flags) { |
write_data_spanner(data, width); |
write_data_spanner(p, data, width); |
return; |
return; |
} |
} |
|
|
|
|
case (TBL_CELL_HORIZ): |
case (TBL_CELL_HORIZ): |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case (TBL_CELL_DHORIZ): |
case (TBL_CELL_DHORIZ): |
write_data_spanner(data, width); |
write_data_spanner(p, data, width); |
break; |
break; |
case (TBL_CELL_LONG): |
case (TBL_CELL_LONG): |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
|
|
case (TBL_CELL_LEFT): |
case (TBL_CELL_LEFT): |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case (TBL_CELL_RIGHT): |
case (TBL_CELL_RIGHT): |
write_data_literal(data, width); |
write_data_literal(p, data, width); |
break; |
break; |
case (TBL_CELL_NUMBER): |
case (TBL_CELL_NUMBER): |
write_data_number(data, width); |
write_data_number(p, data, width); |
break; |
break; |
default: |
default: |
abort(); |
abort(); |
|
|
|
|
|
|
static void |
static void |
write_spanner(const struct tbl_head *head) |
write_spanner(struct termp *p, const struct tbl_head *head) |
{ |
{ |
char *p; |
char *w; |
|
|
p = NULL; |
w = NULL; |
switch (head->pos) { |
switch (head->pos) { |
case (TBL_HEAD_VERT): |
case (TBL_HEAD_VERT): |
p = "|"; |
w = "|"; |
break; |
break; |
case (TBL_HEAD_DVERT): |
case (TBL_HEAD_DVERT): |
p = "||"; |
w = "||"; |
break; |
break; |
default: |
default: |
break; |
break; |
} |
} |
|
|
assert(p); |
assert(p); |
printf("%s", p); |
term_word(p, w); |
} |
} |
|
|
|
|
static inline void |
static inline void |
write_char(char c, int len) |
write_char(struct termp *p, char c, int len) |
{ |
{ |
int i; |
int i; |
|
static char w[2]; |
|
|
|
w[0] = c; |
for (i = 0; i < len; i++) |
for (i = 0; i < len; i++) |
printf("%c", c); |
term_word(p, w); |
} |
} |