#include "driver.h"
#include "lbp.h"
#include "charset.h"
#include "paper.h"
#include "nonposix.h"
extern "C" const char *Version_string;
static int user_papersize = -1; static int orientation = -1; static double user_paperlength = 0; static double user_paperwidth = 0;
static int ncopies = 1;
#define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em
static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR;
static int set_papersize(const char *paperformat);
class lbp_font : public font {
public:
~lbp_font();
void handle_unknown_font_command(const char *command, const char *arg,
const char *filename, int lineno);
static lbp_font *load_lbp_font(const char *);
char *lbpname;
char is_scalable;
private:
lbp_font(const char *);
};
class lbp_printer : public printer {
public:
lbp_printer(int, double, double);
~lbp_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
void begin_page(int);
void end_page(int page_length);
font *make_font(const char *);
void end_of_line();
private:
void set_line_thickness(int size,const environment *env);
void vdmstart();
void vdmflush(); void setfillmode(int mode);
void polygon( int hpos,int vpos,int np,int *p);
char *font_name(const lbp_font *f, const int siz);
int fill_pattern;
int fill_mode;
int cur_hpos;
int cur_vpos;
lbp_font *cur_font;
int cur_size;
unsigned short cur_symbol_set;
int line_thickness;
int req_linethickness; int papersize;
int paperlength; int paperwidth;
};
lbp_font::lbp_font(const char *nm)
: font(nm)
{
}
lbp_font::~lbp_font()
{
}
lbp_font *lbp_font::load_lbp_font(const char *s)
{
lbp_font *f = new lbp_font(s);
f->lbpname = NULL;
f->is_scalable = 1; if (!f->load()) {
delete f;
return 0;
}
return f;
}
void lbp_font::handle_unknown_font_command(const char *command,
const char *arg,
const char *filename, int lineno)
{
if (strcmp(command, "lbpname") == 0) {
if (arg == 0)
fatal_with_file_and_line(filename, lineno,
"`%1' command requires an argument",
command);
this->lbpname = new char[strlen(arg) + 1];
strcpy(this->lbpname, arg);
if (arg[0] == 'N')
this->is_scalable = 0;
}
}
static void wp54charset()
{
unsigned int i;
lbpputs("\033[714;100;29;0;32;120.}");
for (i = 0; i < sizeof(symset); i++)
lbpputc(symset[i]);
lbpputs("\033[100;0 D");
return;
}
lbp_printer::lbp_printer(int ps, double pw, double pl)
: fill_pattern(1),
fill_mode(0),
cur_hpos(-1),
cur_font(0),
cur_size(0),
cur_symbol_set(0),
req_linethickness(-1)
{
SET_BINARY(fileno(stdout));
lbpinit(stdout);
lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
wp54charset(); lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
if (orientation < 0)
orientation = 0; papersize = 14; if (font::papersize) {
papersize = set_papersize(font::papersize);
paperlength = font::paperlength;
paperwidth = font::paperwidth;
}
if (ps >= 0) {
papersize = ps;
paperlength = int(pl * font::res + 0.5);
paperwidth = int(pw * font::res + 0.5);
}
if (papersize < 80) lbpprintf("\033[%dp", (papersize | orientation));
else lbpprintf("\033[%d;%d;%dp", (papersize | orientation),
paperlength, paperwidth);
lbpprintf("\033[%dv\n", ncopies);
lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
lbpmoveabs(0, 0);
lbpputs("\033[0t\033[2t");
lbpputs("\033('$2\033)' 1"); cur_symbol_set = 0;
}
lbp_printer::~lbp_printer()
{
lbpputs("\033P1y\033\\");
lbpputs("\033c\033<");
}
inline void lbp_printer::set_line_thickness(int size,const environment *env)
{
if (size == 0)
line_thickness = 1;
else {
if (size < 0)
line_thickness =
env->size * linewidth_factor * font::res / 72000;
else line_thickness = size;
} if (line_thickness < 1)
line_thickness = 1;
if (vdminited())
vdmlinewidth(line_thickness);
req_linethickness = size;
return;
}
void lbp_printer::begin_page(int)
{
}
void lbp_printer::end_page(int)
{
if (vdminited())
vdmflush();
lbpputc('\f');
cur_hpos = -1;
}
void lbp_printer::end_of_line()
{
cur_hpos = -1; }
char *lbp_printer::font_name(const lbp_font *f, const int siz)
{
static char bfont_name[255]; char type, ori, *nam; int cpi;
bfont_name[0] = 0x00;
if (orientation) ori = 'R';
else ori = 'N';
type = f->lbpname[strlen(f->lbpname) - 1];
nam = new char[strlen(f->lbpname) - 2];
strncpy(nam, &(f->lbpname[1]), strlen(f->lbpname) - 2);
nam[strlen(f->lbpname) - 2] = 0x00;
cpi = 17;
if (!strcasecmp(nam, "courier")) {
if (siz >= 12)
cpi = 10;
else cpi = 17;
}
if (!strcasecmp(nam, "elite")) {
if (siz >= 10)
cpi = 12;
else cpi = 17;
}
if ((type != 'B') && (type != 'I')) sprintf(bfont_name, "%c%s%d", ori, nam, cpi);
else
sprintf(bfont_name, "%c%s%d%c", ori, nam, cpi, type);
return bfont_name;
}
void lbp_printer::set_char(int idx, font *f, const environment *env,
int w, const char *)
{
int code = f->get_code(idx);
unsigned char ch = code & 0xff;
unsigned short symbol_set = code >> 8;
if (f != cur_font) {
lbp_font *psf = (lbp_font *)f;
if (psf->is_scalable) {
lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf->lbpname,
(int)((env->size * font::res) / 72));
}
else
lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size));
lbpputs("\033)' 1"); cur_font = psf;
cur_symbol_set = 0;
if ((req_linethickness < 0 ) && (env->size != cur_size))
set_line_thickness(req_linethickness,env);
cur_size = env->size;
}
if (symbol_set != cur_symbol_set) {
if (cur_symbol_set == 3)
lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font->lbpname,
(int)((env->size * font::res) / 72));
switch (symbol_set) {
case 0:
lbpputs("\033('$2\033)' 1"); break;
case 1:
lbpputs("\033(d\033)' 1"); break;
case 2:
lbpputs("\033('$2\033)'!0"); break;
case 3:
lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",
(int)((env->size * font::res) / 72));
lbpputs("\033(\"!!0\033)\"!!1"); break;
case 4:
lbpputs("\033)\"! 1\033(\"!$2"); break;
}
cur_symbol_set = symbol_set;
}
if (env->size != cur_size) {
if (!cur_font->is_scalable)
lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font, env->size));
else
lbpprintf("\033[%d C", (int)((env->size * font::res) / 72));
cur_size = env->size;
if (req_linethickness < 0 )
set_line_thickness(req_linethickness,env);
}
if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos)) {
lbpmoveabs(env->hpos - 64, env->vpos - 64);
cur_vpos = env->vpos;
cur_hpos = env->hpos;
}
if ((ch & 0x7F) < 32)
lbpputs("\033[1.v");
lbpputc(ch);
cur_hpos += w;
}
void lbp_printer::vdmstart()
{
FILE *f;
static int changed_origin = 0;
errno = 0;
f = tmpfile();
if (f == NULL)
perror("Opening temporary file");
vdminit(f);
if (!changed_origin) { changed_origin = 1;
vdmorigin(-63, 0);
}
vdmlinewidth(line_thickness);
}
void
lbp_printer::vdmflush()
{
char buffer[1024];
int bytes_read = 1;
vdmend();
fflush(lbpoutput);
rewind(vdmoutput);
do {
bytes_read = fread(buffer, 1, sizeof(buffer), vdmoutput);
bytes_read = fwrite(buffer, 1, bytes_read, lbpoutput);
} while (bytes_read == sizeof(buffer));
fclose(vdmoutput); vdmoutput = NULL;
}
inline void lbp_printer::setfillmode(int mode)
{
if (mode != fill_mode) {
if (mode != 1)
vdmsetfillmode(mode, 1, 0);
else
vdmsetfillmode(mode, 1, 1); fill_mode = mode;
}
}
inline void lbp_printer::polygon(int hpos, int vpos, int np, int *p)
{
int *points, i;
points = new int[np + 2];
points[0] = hpos;
points[1] = vpos;
for (i = 0; i < np; i++)
points[i + 2] = p[i];
vdmpolygon((np /2) + 1, points);
}
void lbp_printer::draw(int code, int *p, int np, const environment *env)
{
if ((req_linethickness < 0 ) && (env->size != cur_size))
set_line_thickness(req_linethickness,env);
switch (code) {
case 't':
if (np == 0)
line_thickness = 1;
else { if (np != 1 && np != 2) {
error("0 or 1 argument required for thickness");
break;
}
set_line_thickness(p[0],env);
}
break;
case 'l': if (np != 2) {
error("2 arguments required for line");
break;
}
if (!vdminited())
vdmstart();
vdmline(env->hpos, env->vpos, p[0], p[1]);
break;
case 'R': if (np != 2) {
error("2 arguments required for Rule");
break;
}
if (vdminited()) {
setfillmode(fill_pattern); vdmrectangle(env->hpos, env->vpos, p[0], p[1]);
}
else {
lbpruleabs(env->hpos - 64, env->vpos -64, p[0], p[1]);
cur_vpos = p[1];
cur_hpos = p[0];
}
break;
case 'P': if (!vdminited())
vdmstart();
setfillmode(fill_pattern);
polygon(env->hpos, env->vpos, np, p);
break;
case 'p': if (!vdminited())
vdmstart();
setfillmode(0);
polygon(env->hpos, env->vpos, np, p);
break;
case 'C': if (!vdminited())
vdmstart();
setfillmode(fill_pattern);
vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
break;
case 'c': if (!vdminited())
vdmstart();
setfillmode(0);
vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
break;
case 'E': if (!vdminited())
vdmstart();
setfillmode(fill_pattern);
vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
break;
case 'e': if (!vdminited())
vdmstart();
setfillmode(0);
vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
break;
case 'a': if (!vdminited())
vdmstart();
setfillmode(0);
vdmvarc(env->hpos + p[0], env->vpos+p[1],
int(sqrt(double((p[0]*p[0]) + (p[1]*p[1])))),
p[2], p[3],
(-p[0]), (-p[1]), 1, 2);
break;
case '~': if (!vdminited())
vdmstart();
setfillmode(0);
vdmspline(np/2, env->hpos, env->vpos, p);
break;
case 'f':
if (np != 1 && np != 2) {
error("1 argument required for fill");
break;
}
if ((p[0] == 1) || (p[0] >= 1000)) { fill_pattern = 1;
break;
}
if (p[0] == 0) { fill_pattern = 0;
break;
}
if ((p[0] > 1) && (p[0] < 1000))
{
if (p[0] >= 990) fill_pattern = -23;
else if (p[0] >= 700) fill_pattern = -28;
else if (p[0] >= 500) fill_pattern = -27;
else if (p[0] >= 400) fill_pattern = -26;
else if (p[0] >= 300) fill_pattern = -25;
else if (p[0] >= 200) fill_pattern = -22;
else if (p[0] >= 100) fill_pattern = -24;
else fill_pattern = -21;
}
break;
case 'F':
break;
default:
error("unrecognised drawing command `%1'", char(code));
break;
}
return;
}
font *lbp_printer::make_font(const char *nm)
{
return lbp_font::load_lbp_font(nm);
}
printer *make_printer()
{
return new lbp_printer(user_papersize, user_paperwidth, user_paperlength);
}
static struct {
const char *name;
int code;
} lbp_papersizes[] =
{{ "A4", 14 },
{ "letter", 30 },
{ "legal", 32 },
{ "executive", 40 },
};
static int set_papersize(const char *paperformat)
{
unsigned int i;
for (i = 0 ; i < sizeof(lbp_papersizes) / sizeof(lbp_papersizes[0]); i++)
{
if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0)
return lbp_papersizes[i].code;
}
return 82;
}
static void handle_unknown_desc_command(const char *command, const char *arg,
const char *filename, int lineno)
{
if (strcasecmp(command, "orientation") == 0) {
if (orientation > 0)
return;
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`orientation' command requires an argument");
else {
if (strcasecmp(arg, "portrait") == 0)
orientation = 0;
else {
if (strcasecmp(arg, "landscape") == 0)
orientation = 1;
else
error_with_file_and_line(filename, lineno,
"invalid argument to `orientation' command");
}
}
}
}
static struct option long_options[] = {
{ "orientation", required_argument, NULL, 'o' },
{ "version", no_argument, NULL, 'v' },
{ "copies", required_argument, NULL, 'c' },
{ "landscape", no_argument, NULL, 'l' },
{ "papersize", required_argument, NULL, 'p' },
{ "linewidth", required_argument, NULL, 'w' },
{ "fontdir", required_argument, NULL, 'F' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, 0, 0 }
};
static void usage(FILE *stream)
{
fprintf(stream,
"usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or]\n"
" [-w width] [files ...]\n"
"\n"
" -o --orientation=[portrait|landscape]\n"
" -v --version\n"
" -c --copies=numcopies\n"
" -l --landscape\n"
" -p --papersize=paper_size\n"
" -w --linewidth=width\n"
" -F --fontdir=dir\n"
" -h --help\n",
program_name);
}
int main(int argc, char **argv)
{
if (program_name == NULL)
program_name = strsave(argv[0]);
font::set_unknown_desc_command_handler(handle_unknown_desc_command);
int c = 0;
int option_index = 0;
while (c >= 0) {
c = getopt_long (argc, argv, "c:F:hI:lo:p:vw:",
long_options, &option_index);
switch (c) {
case 'F':
font::command_line_font_dir(optarg);
break;
case 'I':
break;
case 'p':
{
const char *s;
if (!font::scan_papersize(optarg, &s,
&user_paperlength, &user_paperwidth))
error("invalid paper size `%1' ignored", optarg);
else
user_papersize = set_papersize(s);
break;
}
case 'l':
orientation = 1;
break;
case 'v':
printf("GNU grolbp (groff) version %s\n", Version_string);
exit(0);
break;
case 'o':
if (strcasecmp(optarg, "portrait") == 0)
orientation = 0;
else {
if (strcasecmp(optarg, "landscape") == 0)
orientation = 1;
else
error("unknown orientation '%1'", optarg);
}
break;
case 'c':
{
char *ptr;
long n = strtol(optarg, &ptr, 10);
if ((n <= 0) && (ptr == optarg))
error("argument for -c must be a positive integer");
else if (n <= 0 || n > 32767)
error("out of range argument for -c");
else
ncopies = unsigned(n);
break;
}
case 'w':
{
char *ptr;
long n = strtol(optarg, &ptr, 10);
if (n == 0 && ptr == optarg)
error("argument for -w must be a non-negative integer");
else if (n < 0 || n > INT_MAX)
error("out of range argument for -w");
else
linewidth_factor = int(n);
break;
}
case 'h':
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
}
}
if (optind >= argc)
do_file("-");
while (optind < argc)
do_file(argv[optind++]);
lbpputs("\033c\033<");
return 0;
}