#define _GNU_SOURCE
#include "driver.h"
#include "lbp.h"
#include "charset.h"
#include "nonposix.h"
extern "C" const char *Version_string;
static short int papersize = -1, orientation = -1 , paperlength = 0, paperwidth = 0,
ncopies = 1;
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();
~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, int dot = 0);
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;
};
#ifndef HAVE_STRSEP
static char *strsep(char **pcadena, const char *delim)
{
char *p;
p = strtok(*pcadena,delim);
*pcadena = strtok(NULL,delim);
return p;
};
#endif
#ifndef HAVE_STRDUP
static char *strdup(const char *s)
{
char *result;
result = (char *)malloc(strlen(s)+1);
if (result != NULL) strcpy(result,s);
return result;
};
#endif
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()
: fill_pattern(1),
fill_mode(0),
cur_hpos(-1),
cur_font(0),
cur_size(0),
cur_symbol_set(0),
line_thickness(-1)
{
#ifdef SET_BINARY
SET_BINARY(fileno(stdout));
#endif
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; if (papersize < 0) papersize = 14; 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<");
}
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 index, font *f, const environment *env, int w, const char *name)
{
int code = f->get_code(index);
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*300)/72));
} else
{ lbpprintf("\033Pz%s.IBML\033\\\n",font_name(psf,env->size));
};
lbpputs("\033)' 1"); cur_size = env->size;
cur_font = psf;
cur_symbol_set = 0;
}
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*300)/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*300)/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*300)/72));
cur_size = env->size;
}
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("Openinig temp 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)
{
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;
} if (p[0] == 0) line_thickness = 1;
if (p[0] < 0) line_thickness = (int)(env->size*30/72);
line_thickness = (int)((abs(p[0])*env->size)/10);
if ((line_thickness > 16 ) && (!vdminited()))
{
vdmstart();
};
if (vdminited()) vdmlinewidth(line_thickness);
} 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];
};
fprintf(stderr,"\nrule: thickness %d == %d\n", env->size, line_thickness);
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;
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;
}
static struct
{
const char *name;
int code;
} papersizes[] =
{{ "A4", 14 },
{ "letter", 30 },
{ "legal", 32 },
{ "executive", 40 },
};
static int set_papersize(const char *papersize)
{
unsigned int i;
for (i = 0 ; i < sizeof(papersizes)/sizeof(papersizes[0]); i++)
{
if (strcasecmp(papersizes[i].name,papersize) == 0)
return papersizes[i].code;
};
if (strncasecmp("cust",papersize,4) == 0)
{
char *p ,
*p1,
*papsize;
p = papsize = strdup(&papersize[4]);
if (papsize == NULL) return -1;
p1 = strsep(&p,"x");
if (p == NULL)
{ p = papsize ;
p1 = strsep(&p,"X");
if (p == NULL) { free(papsize); return -1;};
}; paperlength = atoi(p1);
if (paperlength == 0) { free(papsize); return -1;};
paperwidth = atoi(p);
if (paperwidth == 0) { free(papsize); return -1;};
free(papsize);
return 82;
};
return -1;
};
static int handle_papersize_command(const char *arg)
{
int n = set_papersize(arg);
if (n < 0)
{ FILE *f = fopen(arg,"r");
if (f != NULL)
{ char psize[255],*p;
fgets(psize,254,f);
fclose(f);
p = psize; while (*p) p++;
if (*(--p) == '\n') *p = 0x00;
n = set_papersize(psize);
}; };
return n;
};
static void handle_unknown_desc_command(const char *command, const char *arg,
const char *filename, int lineno)
{
if (strcasecmp(command, "papersize") == 0) {
if (papersize > 0) return;
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`papersize' command requires an argument");
else
{
int n = handle_papersize_command(arg);
if (n < 0)
error_with_file_and_line(filename, lineno,
"unknown paper size `%1'", arg);
else
papersize = n;
}; };
if (strcasecmp(command, "orientation") == 0) {
if (orientation > 0) return;
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`papersize' 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,
"`orientation' command requires an argument");
};
}; }; };
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' },
{ "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] "\
" [files ...]\n"\
" -o --orientation=[portrait|landscape]\n"\
" -v --version\n"\
" -c --copies=numcopies\n"\
" -l --landscape\n"\
" -p --papersize=paper_size\n"\
" -F --fontdir=dir\n"\
" -h --help\n",
program_name);
};
int main(int argc, char **argv)
{
if (program_name == NULL) program_name = strdup(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, "F:p:lvo:c:h",\
long_options, &option_index);
switch (c) {
case 'F' : font::command_line_font_dir(optarg);
break;
case 'p' : {
int n = handle_papersize_command(optarg);
if (n < 0)
error("unknown paper size `%1'", optarg);
else
papersize = n;
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 '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;
};