diff options
Diffstat (limited to 'contrib/groff/grolbp/lbp.cc')
-rw-r--r-- | contrib/groff/grolbp/lbp.cc | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/contrib/groff/grolbp/lbp.cc b/contrib/groff/grolbp/lbp.cc new file mode 100644 index 0000000..fe06e1c --- /dev/null +++ b/contrib/groff/grolbp/lbp.cc @@ -0,0 +1,772 @@ +// -*- C++ -*- +/* Copyright (C) 1994 Free Software Foundation, Inc. + Written by Francisco Andrés Verdú <pandres@dragonet.es> with many ideas + taken from the other groff drivers. + + +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 2, or (at your option) any later +version. + +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 +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +TODO + + - Add X command to include bitmaps +*/ +#define _GNU_SOURCE + +#include "driver.h" +#include "lbp.h" +#include "charset.h" + +#include "nonposix.h" + +#ifdef HAVE_STRNCASECMP +#ifdef NEED_DECLARATION_STRNCASECMP +extern "C" { + // SunOS's string.h fails to declare this. + int strncasecmp(const char *, const char *, int); +} +#endif /* NEED_DECLARATION_STRNCASECMP */ +#endif /* HAVE_STRNCASECMP */ + +static short int papersize = -1, // papersize + orientation = -1 , // orientation + paperlength = 0, // Custom Paper size + paperwidth = 0, + ncopies = 1; // Number of copies + +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(); // the name vdmend was already used in lbp.h + 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; +}; + +// Compatibility section. +// +// Here we define some functions not present in some of the targets +// platforms +#ifndef HAVE_STRSEP +// Solaris 8 doesn't have the strsep function +static char *strsep(char **pcadena, const char *delim) +{ + char *p; + + p = strtok(*pcadena,delim); + *pcadena = strtok(NULL,delim); + return p; + +}; +#endif + +#ifndef HAVE_STRDUP +// Ditto with OS/390 and strdup +static char *strdup(const char *s) +{ + char *result; + + result = (char *)malloc(strlen(s)+1); + if (result != NULL) strcpy(result,s); + return result; + +}; // strdup + +#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; // Default is that fonts are scalable + 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); + // We Recongnize bitmaped fonts by the first character of it's name + if (arg[0] == 'N') this->is_scalable = 0; + // fprintf(stderr,"Loading font \"%s\" \n",arg); + }; // if (strcmp(command, "lbpname") + // fprintf(stderr,"Loading font %s \"%s\" in %s at %d\n",command,arg,filename,lineno); +}; + +static void wp54charset() +{ + 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(); // Define the new symbol set + lbpputs("\033[7 I\033[?32h\033[?33h\033[11h"); + // Paper size handling + if (orientation < 0) orientation = 0;// Default orientation is portrait + if (papersize < 0) papersize = 14; // Default paper size is A4 + if (papersize < 80) // standard paper + lbpprintf("\033[%dp",(papersize | orientation)); + else // Custom paper + lbpprintf("\033[%d;%d;%dp",(papersize | orientation),\ + paperlength,paperwidth); + + // Number of copies + 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"); // Primary symbol set IBML + // Secondary symbol set IBMR1 + 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; // force absolute motion +} + +char *lbp_printer::font_name(const lbp_font *f, const int siz) +{ + static char bfont_name[255] ; // The resulting font name + char type, // Italic, Roman, Bold + ori, // Normal or Rotated + *nam; // The font name without other data. +// nam[strlen(f->lbpname)-2]; // The font name without other data. + int cpi; // The font size in characters per inch + // (Bitmaped fonts are monospaced). + + + /* Bitmap font selection is ugly in this printer, so don't expect + this function to be elegant. */ + + bfont_name[0] = 0x00; + if (orientation) // Landscape + ori = 'R'; + else // Portrait + 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; + // fprintf(stderr,"Bitmap font '%s' %d %c %c \n",nam,siz,type,ori); + /* Since these fonts are avaiable only at certain sizes, + 10 and 17 cpi for courier, 12 and 17 cpi for elite, + we adjust the resulting size. */ + cpi = 17; + // Fortunately there were only two bitmaped fonts shiped with the printer. + if (!strcasecmp(nam,"courier")) + { // Courier font + if (siz >= 12) cpi = 10; + else cpi = 17; + }; + if (!strcasecmp(nam,"elite")) + { // Elite font + if (siz >= 10) cpi = 12; + else cpi = 17; + }; + + // Now that we have all the data, let's generate the font name. + if ((type != 'B') && (type != 'I')) // Roman font + sprintf(bfont_name,"%c%s%d",ori,nam,cpi); + else + sprintf(bfont_name,"%c%s%d%c",ori,nam,cpi,type); + + return bfont_name; + +}; // lbp_printer::font_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; + // fprintf(stderr,"Loading font %s \"%d\" \n",psf->lbpname,env->size); + if (psf->is_scalable) + { // Scalable font selection is different from bitmaped + lbpprintf("\033Pz%s.IBML\033\\\033[%d C",psf->lbpname,\ + (int)((env->size*300)/72)); + } else + { // Bitmaped font + lbpprintf("\033Pz%s.IBML\033\\\n",font_name(psf,env->size)); + }; + lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set + cur_size = env->size; + cur_font = psf; + cur_symbol_set = 0; + } + if (symbol_set != cur_symbol_set) { + if ( cur_symbol_set == 3 ) { + // if current symbol set is Symbol we must restore the font + lbpprintf("\033Pz%s.IBML\033\\\033[%d C",cur_font->lbpname,\ + (int)((env->size*300)/72)); + }; // if ( cur_symbol_set == 3 ) + switch (symbol_set) { + case 0: lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets + break; + case 1: lbpputs("\033(d\033)' 1"); // Select wp54 symbol set + break; + case 2: lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set + break; + case 3: lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",\ + (int)((env->size*300)/72)); + lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font + break; + case 4: lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set + break; + }; // switch (symbol_set) + +// if (symbol_set == 1) lbpputs("\033(d"); // Select wp54 symbol set +// else lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets + 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 - ((5*300)/16),env->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(); + // f = fopen("/tmp/gtmp","w+"); + if (f == NULL) perror("Openinig temp file"); + vdminit(f); + if (!changed_origin) { // we should change the origin only one time + changed_origin = 1; + vdmorigin(-63,0); + }; + vdmlinewidth(line_thickness); + +}; + +void +lbp_printer::vdmflush() +{ + char buffer[1024]; + int bytes_read = 1; + + vdmend(); + fflush(lbpoutput); + /* lets copy the vdm code to the output */ + 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); // This will also delete the file, + // since it is created by tmpfile() + vdmoutput = NULL; + +}; // lbp_printer::vdmflush + +inline void +lbp_printer::setfillmode(int mode) +{ + if (mode != fill_mode) { + if (mode != 1) vdmsetfillmode(mode,1,0); + else vdmsetfillmode(mode,1,1); // To get black we must use white + // inverted + fill_mode = mode; + }; +}; // setfillmode + +inline void +lbp_printer::polygon( int hpos,int vpos,int np,int *p) +{ + //int points[np+2],i; + int *points,i; + + points = new int[np+2]; + points[0] = hpos; + points[1] = vpos; +/* fprintf(stderr,"Poligon (%d,%d) ", points[0],points[1]);*/ + for (i = 0; i < np; i++) points[i+2] = p[i]; +/* for (i = 0; i < np; i++) fprintf(stderr," %d ",p[i]); + fprintf(stderr,"\n"); */ + 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 { // troff gratuitously adds an extra 0 + if (np != 1 && np != 2) { + error("0 or 1 argument required for thickness"); + break; + } // if (np != ... + if (p[0] == 0) line_thickness = 1; + if (p[0] < 0) // Default = 1 point + line_thickness = (int)(env->size*30/72); + line_thickness = (int)((abs(p[0])*env->size)/10); + if ((line_thickness > 16 ) && (!vdminited())) + { /* for greater thickness we must use VDM */ + vdmstart(); + /* vdmlinewidth(line_thickness); already done in + * vdmstart() */ + }; + if (vdminited()) vdmlinewidth(line_thickness); + // fprintf(stderr,"\nthickness: %d == %d, size %d\n", + // p[0],line_thickness,env->size ); + } // else + break; + + case 'l': // Line + if (np != 2) { + error("2 arguments required for line"); + break; + }; + if (!vdminited()) vdmstart(); + vdmline(env->hpos,env->vpos,p[0],p[1]); + /*fprintf(stderr,"\nline: %d,%d - %d,%d thickness %d == %d\n",\ + env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],\ + env->vpos -64 + p[1],env->size, line_thickness);*/ + break; + case 'R': // Rule + if (np != 2) { + error("2 arguments required for Rule"); + break; + } + if (vdminited()) { + setfillmode(fill_pattern); // Solid Rule + 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': // Filled Polygon + if (!vdminited()) vdmstart(); + setfillmode(fill_pattern); + polygon(env->hpos,env->vpos,np,p); + break; + case 'p': // Empty Polygon + if (!vdminited()) vdmstart(); + setfillmode(0); + polygon(env->hpos,env->vpos,np,p); + break; + case 'C': // Filled Circle + if (!vdminited()) vdmstart(); + // fprintf(stderr,"Circle (%d,%d) Fill %d\n",env->hpos,env->vpos,fill_pattern); + setfillmode(fill_pattern); + vdmcircle(env->hpos + (p[0]/2),env->vpos,p[0]/2); + break; + case 'c': // Empty Circle + if (!vdminited()) vdmstart(); + setfillmode(0); + vdmcircle(env->hpos + (p[0]/2),env->vpos,p[0]/2); + break; + case 'E': // Filled Ellipse + if (!vdminited()) vdmstart(); + setfillmode(fill_pattern); + vdmellipse(env->hpos + (p[0]/2),env->vpos,p[0]/2,p[1]/2,0); + break; + case 'e': // Empty Ellipse + if (!vdminited()) vdmstart(); + setfillmode(0); + vdmellipse(env->hpos + (p[0]/2),env->vpos,p[0]/2,p[1]/2,0); + break; + case 'a': // Arc + if (!vdminited()) vdmstart(); + setfillmode(0); + // VDM draws arcs clockwise and pic counterclockwise + // We must compensate for that, exchanging the starting and + // ending points + 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 '~': // Spline + 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; + }; + // fprintf(stderr,"Fill %d\n",p[0]); + if ((p[0] == 1) || (p[0] >= 1000)) { // Black + fill_pattern = 1; + break; + }; // if (p[0] == 1) + if (p[0] == 0) { // White + 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; + }; // if (p[0] >= 0 && p[0] <= 1000) + break; + default: + error("unrecognised drawing command `%1'", char(code)); + break; + }; // switch (code) + 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) +{ + int i; + + // First test for a standard (i.e. supported directly by the printer) + // papersize + for (i = 0 ; i < sizeof(papersizes)/sizeof(papersizes[0]); i++) + { + if (strcasecmp(papersizes[i].name,papersize) == 0) + return papersizes[i].code; + }; + + // Now test for a custom papersize + 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) + { // let's test for an uppercase x + p = papsize ; + p1 = strsep(&p,"X"); + if (p == NULL) { free(papsize); return -1;}; + }; // if (p1 == NULL) + paperlength = atoi(p1); + if (paperlength == 0) { free(papsize); return -1;}; + paperwidth = atoi(p); + if (paperwidth == 0) { free(papsize); return -1;}; + free(papsize); + return 82; + }; // if (strcnasecmp("cust",papersize,4) == 0) + + return -1; +}; + +static int handle_papersize_command(const char *arg) +{ + int n = set_papersize(arg); + + if (n < 0) + { // If is not a standard nor custom paper size + // let's see if it's a file (i.e /etc/papersize ) + FILE *f = fopen(arg,"r"); + if (f != NULL) + { // the file exists and is readable + char psize[255],*p; + fgets(psize,254,f); + fclose(f); + // set_papersize doesn't like the trailing \n + p = psize; while (*p) p++; + if (*(--p) == '\n') *p = 0x00; + + n = set_papersize(psize); + }; // if (f != NULL) + }; // if (n < 0) + + return n; +}; // handle_papersize_command + + +static void handle_unknown_desc_command(const char *command, const char *arg, + const char *filename, int lineno) +{ + // papersize command + if (strcasecmp(command, "papersize") == 0) { + // We give priority to command line options + 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 (arg == 0) ... else ... + }; // if (strcasecmp(command, "papersize") + + // orientation command + if (strcasecmp(command, "orientation") == 0) { + // We give priority to command line options + 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"); + }; + }; // if (arg == 0) ... else ... + }; // if (strcasecmp(command, "orientation") == 0) +}; + +static struct option long_options[] = { + {"orientation",1,NULL,'o'}, + {"version",0,NULL,'v'}, + {"copies",1,NULL,'c'}, + {"landscape",0,NULL,'l'}, + {"papersize",1,NULL,'p'}, + {"fontdir",1,NULL,'F'}, + {"help",0,NULL,'h'}, + {0, 0, 0, 0} + }; + +static void usage() +{ + fprintf(stderr, + "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); + exit(1); +}; // usage + +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); + // command line parsing + 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' : { + extern const char *version_string; + fprintf(stderr, "grolbp version %s\n",\ + version_string); + fflush(stderr); + 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(); + break; + + + }; // switch (c) + }; // while (c > 0 ) + + if (optind >= argc) + do_file("-"); + + while (optind < argc) { + do_file(argv[optind++]); + }; + + lbpputs("\033c\033<"); + return 0; +}; |