/* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
You should have received a copy of the GNU General Public License along
with groff; see the file LICENSE. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define DEFAULT_LINES_PER_PAGE 66
static int horizontal_tab_flag
= 0;
static int form_feed_flag
= 0;
static int bold_flag
= 1;
static int underline_flag
= 1;
static int overstrike_flag
= 1;
enum { UNDERLINE_MODE
= 01, BOLD_MODE
= 02 };
// Mode to use for bold-underlining.
static unsigned char bold_underline_mode
= BOLD_MODE
|UNDERLINE_MODE
;
class tty_font
: public font
{
unsigned char get_mode() { return mode
; }
void handle_x_command(int argc
, const char **argv
);
static tty_font
*load_tty_font(const char *);
tty_font
*tty_font::load_tty_font(const char *s
)
tty_font
*f
= new tty_font(s
);
const char *s
= f
->get_internal_name();
if (s
!= 0 && (n
= strtol(s
, 0, 0)) != 0)
f
->mode
= int(n
& (BOLD_MODE
|UNDERLINE_MODE
));
f
->mode
&= ~UNDERLINE_MODE
;
if ((f
->mode
& (BOLD_MODE
|UNDERLINE_MODE
)) == (BOLD_MODE
|UNDERLINE_MODE
))
f
->mode
= (f
->mode
& ~(BOLD_MODE
|UNDERLINE_MODE
)) | bold_underline_mode
;
tty_font::tty_font(const char *nm
)
void tty_font::handle_x_command(int argc
, const char **argv
)
if (argc
>= 1 && strcmp(argv
[0], "bold") == 0)
else if (argc
>= 1 && strcmp(argv
[0], "underline") == 0)
// hpos and vpos must be non-adjacent, to work round a bug in g++ 1.37.1
class tty_printer
: public printer
{
enum { INITIAL_VEC_SIZE
= 32 };
void set_char(int, font
*, const environment
*, int);
font
*make_font(const char *);
tty_printer::tty_printer()
: vec_used(0), vec_size(0), vec(0)
if (font::paperlength
== 0)
lines_per_page
= DEFAULT_LINES_PER_PAGE
;
else if (font::paperlength
% font::vert
!= 0)
fatal("paperlength not a multiple of vertical resolution");
lines_per_page
= font::paperlength
/font::vert
;
if (lines_per_page
> USHRT_MAX
|| lines_per_page
<= 0)
fatal("ridiculous paperlength");
columns_per_page
= font::paperwidth
/font::hor
;
// If columns_per_page is zero, we won't truncate.
if (columns_per_page
< 0)
tty_printer::~tty_printer()
void tty_printer::set_char(int i
, font
*f
, const environment
*env
, int w
)
fatal("horizontal position not a multiple of horizontal resolution");
error("character to the left of first column discarded");
if (columns_per_page
!= 0 && h
>= columns_per_page
) {
error("character to the right of last column discarded");
error("character with ridiculously large horizontal position discarded");
fatal("vertical position not a multiple of vertical resolution");
// Note that the first output line corresponds to groff position font::vert.
error("character above first line discarded");
if (v
> lines_per_page
) {
error("character below last line discarded");
fatal("width of character not equal to horizontal resolution");
if (vec_used
>= vec_size
) {
vec_size
= INITIAL_VEC_SIZE
;
if (vec_size
> USHRT_MAX
/2) {
if (vec_size
>= USHRT_MAX
)
fatal("too many characters on the page");
vec
= new glyph
[vec_size
];
memcpy(vec
, old_vec
, vec_used
*sizeof(glyph
));
// We need a stable sort, but qsort is not stable, so we fake it.
vec
[vec_used
].serial
= vec_used
;
vec
[vec_used
].code
= f
->get_code(i
);
vec
[vec_used
].mode
= ((tty_font
*)f
)->get_mode();
static int compare_glyph(void *p1
, void *p2
)
int v1
= ((glyph
*)p1
)->vpos
;
int v2
= ((glyph
*)p2
)->vpos
;
int h1
= ((glyph
*)p1
)->hpos
;
int h2
= ((glyph
*)p2
)->hpos
;
if (((glyph
*)p1
)->serial
< ((glyph
*)p2
)->serial
)
void tty_printer::end_page()
qsort(vec
, vec_used
, sizeof(glyph
), compare_glyph
);
// We have already discarded characters with vpos < 1 or > lines_per_page.
for (int i
= 0; i
< vec_used
; i
++) {
assert(vpos
<= vec
[i
].vpos
);
&& vec
[i
].hpos
== vec
[i
+ 1].hpos
&& vec
[i
].vpos
== vec
[i
+ 1].vpos
)
for (; vpos
< vec
[i
].vpos
; vpos
++) {
if (hpos
> vec
[i
].hpos
) {
if (horizontal_tab_flag
) {
int next_tab_pos
= ((hpos
+ TAB_WIDTH
) / TAB_WIDTH
) * TAB_WIDTH
;
if (next_tab_pos
> vec
[i
].hpos
)
for (; hpos
< vec
[i
].hpos
; hpos
++)
assert(hpos
== vec
[i
].hpos
&& vpos
== vec
[i
].vpos
);
if (isalnum(vec
[i
].code
) && vec
[i
].mode
& UNDERLINE_MODE
) {
if (vec
[i
].mode
& BOLD_MODE
) {
if (vpos
<= lines_per_page
)
for (; vpos
<= lines_per_page
; vpos
++)
font
*tty_printer::make_font(const char *nm
)
return tty_font::load_tty_font(nm
);
int main(int argc
, char **argv
)
static char stderr_buf
[BUFSIZ
];
setbuf(stderr
, stderr_buf
);
while ((c
= getopt(argc
, argv
, "F:vhfbuoBU")) != EOF
)
extern const char *version_string
;
fprintf(stderr
, "grotty version %s\n", version_string
);
// Do not embolden by overstriking.
// Do not overstrike (other than emboldening and underlining).
// Do bold-underlining as bold.
bold_underline_mode
= BOLD_MODE
;
// Do bold-underlining as underlining.
bold_underline_mode
= UNDERLINE_MODE
;
font::command_line_font_dir(optarg
);
for (int i
= optind
; i
< argc
; i
++)
fprintf(stderr
, "usage: %s [-hfvbuoBU] [-F dir] [files ...]\n",