2 /* Copyright (C) 1994 Free Software Foundation, Inc.
3 Written by Francisco Andrés Verdú <pandres@dragonet.es> with many ideas
4 taken from the other groff drivers.
7 This file is part of groff.
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License along
20 with groff; see the file COPYING. If not, write to the Free Software
21 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 - Add X command to include bitmaps
37 static short int papersize
= -1, // papersize
38 orientation
= -1 , // orientation
39 paperlength
= 0, // Custom Paper size
41 ncopies
= 1; // Number of copies
43 class lbp_font
: public font
{
46 void handle_unknown_font_command(const char *command
, const char *arg
,
47 const char *filename
, int lineno
);
48 static lbp_font
*load_lbp_font(const char *);
52 lbp_font(const char *);
56 class lbp_printer
: public printer
{
60 void set_char(int, font
*, const environment
*, int, const char *name
);
61 void draw(int code
, int *p
, int np
, const environment
*env
);
63 void end_page(int page_length
);
64 font
*make_font(const char *);
67 void set_line_thickness(int size
, int dot
= 0);
69 void vdmflush(); // the name vdmend was already used in lbp.h
70 void setfillmode(int mode
);
71 void lbp_printer::polygon( int hpos
,int vpos
,int np
,int *p
);
72 char *lbp_printer::font_name(const lbp_font
*f
, const int siz
);
80 unsigned short cur_symbol_set
;
84 lbp_font::lbp_font(const char *nm
)
93 lbp_font
*lbp_font::load_lbp_font(const char *s
)
95 lbp_font
*f
= new lbp_font(s
);
97 f
->is_scalable
= 1; // Default is that fonts are scalable
106 void lbp_font::handle_unknown_font_command(const char *command
,
108 const char *filename
, int lineno
)
110 if (strcmp(command
, "lbpname") == 0) {
112 fatal_with_file_and_line(filename
, lineno
,
113 "`%1' command requires an argument",
115 this->lbpname
= new char[strlen(arg
)+1];
116 strcpy(this->lbpname
,arg
);
117 // We Recongnize bitmaped fonts by the first character of it's name
118 if (arg
[0] == 'N') this->is_scalable
= 0;
119 // fprintf(stderr,"Loading font \"%s\" \n",arg);
120 }; // if (strcmp(command, "lbpname")
121 // fprintf(stderr,"Loading font %s \"%s\" in %s at %d\n",command,arg,filename,lineno);
124 static void wp54charset()
128 lbpputs("\033[714;100;29;0;32;120.}");
129 for (i
= 0; i
< sizeof(symset
) ; i
++) lbpputc(symset
[i
]);
130 lbpputs("\033[100;0 D");
134 lbp_printer::lbp_printer()
144 lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
145 wp54charset(); // Define the new symbol set
146 lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
147 // Paper size handling
148 if (orientation
< 0) orientation
= 0;// Default orientation is portrait
149 if (papersize
< 0) papersize
= 14; // Default paper size is A4
150 if (papersize
< 80) // standard paper
151 lbpprintf("\033[%dp",(papersize
| orientation
));
153 lbpprintf("\033[%d;%d;%dp",(papersize
| orientation
),\
154 paperlength
,paperwidth
);
157 lbpprintf("\033[%dv\n",ncopies
);
159 lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
161 lbpputs("\033[0t\033[2t");
162 lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML
163 // Secondary symbol set IBMR1
167 lbp_printer::~lbp_printer()
169 lbpputs("\033P1y\033\\");
170 lbpputs("\033c\033<");
173 void lbp_printer::begin_page(int)
177 void lbp_printer::end_page(int)
179 if (vdminited()) vdmflush();
184 void lbp_printer::end_of_line()
186 cur_hpos
= -1; // force absolute motion
189 char *lbp_printer::font_name(const lbp_font
*f
, const int siz
)
191 static char bfont_name
[255] ; // The resulting font name
192 char type
, // Italic, Roman, Bold
193 ori
, // Normal or Rotated
194 nam
[strlen(f
->lbpname
)-2]; // The font name without other data.
195 int cpi
; // The font size in characters per inch
196 // (Bitmaped fonts are monospaced).
199 /* Bitmap font selection is ugly in this printer, so don't expect
200 this function to be elegant. */
202 bfont_name
[0] = 0x00;
203 if (orientation
) // Landscape
207 type
= f
->lbpname
[strlen(f
->lbpname
)-1];
208 strncpy(nam
,&(f
->lbpname
[1]),strlen(f
->lbpname
)-2);
209 nam
[strlen(f
->lbpname
)-2] = 0x00;
210 // fprintf(stderr,"Bitmap font '%s' %d %c %c \n",nam,siz,type,ori);
211 /* Since these fonts are avaiable only at certain sizes,
212 10 and 17 cpi for courier, 12 and 17 cpi for elite,
213 we adjust the resulting size. */
214 // Fortunately there were only two bitmaped fonts shiped with the printer.
215 if (!strcasecmp(nam
,"courier"))
217 if (siz
>= 12) cpi
= 10;
220 if (!strcasecmp(nam
,"elite"))
222 if (siz
>= 10) cpi
= 12;
226 // Now that we have all the data, let's generate the font name.
227 if ((type
!= 'B') && (type
!= 'I')) // Roman font
228 sprintf(bfont_name
,"%c%s%d",ori
,nam
,cpi
);
230 sprintf(bfont_name
,"%c%s%d%c",ori
,nam
,cpi
,type
);
234 }; // lbp_printer::font_name
236 void lbp_printer::set_char(int index
, font
*f
, const environment
*env
, int w
, const char *name
)
238 int code
= f
->get_code(index
);
240 unsigned char ch
= code
& 0xff;
241 unsigned short symbol_set
= code
>> 8;
243 lbp_font
*psf
= (lbp_font
*)f
;
244 // fprintf(stderr,"Loading font %s \"%d\" \n",psf->lbpname,env->size);
245 if (psf
->is_scalable
)
246 { // Scalable font selection is different from bitmaped
247 lbpprintf("\033Pz%s.IBML\033\\\033[%d C",psf
->lbpname
,\
248 (int)((env
->size
*300)/72));
251 lbpprintf("\033Pz%s.IBML\033\\\n",font_name(psf
,env
->size
));
253 lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
254 cur_size
= env
->size
;
258 if (symbol_set
!= cur_symbol_set
) {
259 if ( cur_symbol_set
== 3 ) {
260 // if current symbol set is Symbol we must restore the font
261 lbpprintf("\033Pz%s.IBML\033\\\033[%d C",cur_font
->lbpname
,\
262 (int)((env
->size
*300)/72));
263 }; // if ( cur_symbol_set == 3 )
264 switch (symbol_set
) {
265 case 0: lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
267 case 1: lbpputs("\033(d\033)' 1"); // Select wp54 symbol set
269 case 2: lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set
271 case 3: lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",\
272 (int)((env
->size
*300)/72));
273 lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
275 case 4: lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
277 }; // switch (symbol_set)
279 // if (symbol_set == 1) lbpputs("\033(d"); // Select wp54 symbol set
280 // else lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
281 cur_symbol_set
= symbol_set
;
283 if (env
->size
!= cur_size
) {
285 if (!cur_font
->is_scalable
)
286 lbpprintf("\033Pz%s.IBML\033\\\n",font_name(cur_font
,env
->size
));
288 lbpprintf("\033[%d C",(int)((env
->size
*300)/72));
289 cur_size
= env
->size
;
291 if ((env
->hpos
!= cur_hpos
) || (env
->vpos
!= cur_vpos
))
293 // lbpmoveabs(env->hpos - ((5*300)/16),env->vpos );
294 lbpmoveabs(env
->hpos
- 64,env
->vpos
- 64 );
295 cur_vpos
= env
->vpos
;
296 cur_hpos
= env
->hpos
;
298 if ((ch
& 0x7F) < 32) lbpputs("\033[1.v");
304 lbp_printer::vdmstart()
307 static int changed_origin
= 0;
311 // f = fopen("/tmp/gtmp","w+");
312 if (f
== NULL
) perror("Openinig temp file");
314 if (!changed_origin
) { // we should change the origin only one time
318 vdmlinewidth(line_thickness
);
323 lbp_printer::vdmflush()
330 /* lets copy the vdm code to the output */
334 bytes_read
= fread(buffer
,1,sizeof(buffer
),vdmoutput
);
335 bytes_read
= fwrite(buffer
,1,bytes_read
,lbpoutput
);
336 } while ( bytes_read
== sizeof(buffer
));
338 fclose(vdmoutput
); // This will also delete the file,
339 // since it is created by tmpfile()
342 }; // lbp_printer::vdmflush
345 lbp_printer::setfillmode(int mode
)
347 if (mode
!= fill_mode
) {
348 if (mode
!= 1) vdmsetfillmode(mode
,1,0);
349 else vdmsetfillmode(mode
,1,1); // To get black we must use white
356 lbp_printer::polygon( int hpos
,int vpos
,int np
,int *p
)
362 /* fprintf(stderr,"Poligon (%d,%d) ", points[0],points[1]);*/
363 for (i
= 0; i
< np
; i
++) points
[i
+2] = p
[i
];
364 /* for (i = 0; i < np; i++) fprintf(stderr," %d ",p[i]);
365 fprintf(stderr,"\n"); */
366 vdmpolygon((np
/2) + 1,points
);
369 void lbp_printer::draw(int code
, int *p
, int np
, const environment
*env
)
373 if (np
== 0) line_thickness
= 1;
374 else { // troff gratuitously adds an extra 0
375 if (np
!= 1 && np
!= 2) {
376 error("0 or 1 argument required for thickness");
379 if (p
[0] == 0) line_thickness
= 1;
380 if (p
[0] < 0) // Default = 1 point
381 line_thickness
= (int)(env
->size
*30/72);
382 line_thickness
= (int)((abs(p
[0])*env
->size
)/10);
383 if ((line_thickness
> 16 ) && (!vdminited()))
384 { /* for greater thickness we must use VDM */
386 /* vdmlinewidth(line_thickness); already done in
389 if (vdminited()) vdmlinewidth(line_thickness
);
390 // fprintf(stderr,"\nthickness: %d == %d, size %d\n",\
391 // p[0],line_thickness,env->size );
397 error("2 arguments required for line");
400 if (!vdminited()) vdmstart();
401 vdmline(env
->hpos
,env
->vpos
,p
[0],p
[1]);
402 /*fprintf(stderr,"\nline: %d,%d - %d,%d thickness %d == %d\n",\
403 env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],\
404 env->vpos -64 + p[1],env->size, line_thickness);*/
408 error("2 arguments required for Rule");
412 setfillmode(fill_pattern
); // Solid Rule
413 vdmrectangle(env
->hpos
,env
->vpos
,p
[0],p
[1]);
416 lbpruleabs(env
->hpos
- 64,env
->vpos
-64 , p
[0], p
[1]);
420 fprintf(stderr
,"\nrule: thickness %d == %d\n", env
->size
, line_thickness
);
422 case 'P': // Filled Polygon
423 if (!vdminited()) vdmstart();
424 setfillmode(fill_pattern
);
425 polygon(env
->hpos
,env
->vpos
,np
,p
);
427 case 'p': // Empty Polygon
428 if (!vdminited()) vdmstart();
430 polygon(env
->hpos
,env
->vpos
,np
,p
);
432 case 'C': // Filled Circle
433 if (!vdminited()) vdmstart();
434 // fprintf(stderr,"Circle (%d,%d) Fill %d\n",env->hpos,env->vpos,fill_pattern);
435 setfillmode(fill_pattern
);
436 vdmcircle(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2);
438 case 'c': // Empty Circle
439 if (!vdminited()) vdmstart();
441 vdmcircle(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2);
443 case 'E': // Filled Ellipse
444 if (!vdminited()) vdmstart();
445 setfillmode(fill_pattern
);
446 vdmellipse(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2,p
[1]/2,0);
448 case 'e': // Empty Ellipse
449 if (!vdminited()) vdmstart();
451 vdmellipse(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2,p
[1]/2,0);
454 if (!vdminited()) vdmstart();
456 // VDM draws arcs clockwise and pic counterclockwise
457 // We must compensate for that, exchanging the starting and
459 vdmvarc(env
->hpos
+ p
[0],env
->vpos
+p
[1],\
460 int(sqrt( (p
[0]*p
[0])+(p
[1]*p
[1]))),\
462 (-p
[0]),(-p
[1]),1,2);
465 if (!vdminited()) vdmstart();
467 vdmspline(np
/2,env
->hpos
,env
->vpos
,p
);
470 if (np
!= 1 && np
!= 2) {
471 error("1 argument required for fill");
474 // fprintf(stderr,"Fill %d\n",p[0]);
475 if ((p
[0] == 1) || (p
[0] >= 1000)) { // Black
479 if (p
[0] == 0) { // White
483 if ((p
[0] > 1) && (p
[0] < 1000))
485 if (p
[0] >= 990) fill_pattern
= -23;
486 else if (p
[0] >= 700) fill_pattern
= -28;
487 else if (p
[0] >= 500) fill_pattern
= -27;
488 else if (p
[0] >= 400) fill_pattern
= -26;
489 else if (p
[0] >= 300) fill_pattern
= -25;
490 else if (p
[0] >= 200) fill_pattern
= -22;
491 else if (p
[0] >= 100) fill_pattern
= -24;
492 else fill_pattern
= -21;
493 }; // if (p[0] >= 0 && p[0] <= 1000)
496 error("unrecognised drawing command `%1'", char(code
));
502 font
*lbp_printer::make_font(const char *nm
)
504 return lbp_font::load_lbp_font(nm
);
509 printer
*make_printer()
511 return new lbp_printer
;
525 static int set_papersize(const char *papersize
)
529 // First test for a standard (i.e. supported directly by the printer)
531 for (i
= 0 ; i
< sizeof(papersizes
)/sizeof(papersizes
[0]); i
++)
533 if (strcasecmp(papersizes
[i
].name
,papersize
) == 0)
534 return papersizes
[i
].code
;
537 // Now test for a custom papersize
538 if (strncasecmp("cust",papersize
,4) == 0)
544 p
= papsize
= strdup(&papersize
[4]);
545 if (papsize
== NULL
) return -1;
548 { // let's test for an uppercase x
551 if (p
== NULL
) { free(papsize
); return -1;};
552 }; // if (p1 == NULL)
553 paperlength
= atoi(p1
);
554 if (paperlength
== 0) { free(papsize
); return -1;};
555 paperwidth
= atoi(p
);
556 if (paperwidth
== 0) { free(papsize
); return -1;};
559 }; // if (strcnasecmp("cust",papersize,4) == 0)
564 static int handle_papersize_command(const char *arg
)
566 int n
= set_papersize(arg
);
569 { // If is not a standard nor custom paper size
570 // let's see if it's a file (i.e /etc/papersize )
571 FILE *f
= fopen(arg
,"r");
573 { // the file exists and is readable
577 // set_papersize doesn't like the trailing \n
578 p
= psize
; while (*p
) p
++;
579 if (*(--p
) == '\n') *p
= 0x00;
581 n
= set_papersize(psize
);
586 }; // handle_papersize_command
589 static void handle_unknown_desc_command(const char *command
, const char *arg
,
590 const char *filename
, int lineno
)
593 if (strcasecmp(command
, "papersize") == 0) {
594 // We give priority to command line options
595 if (papersize
> 0) return;
597 error_with_file_and_line(filename
, lineno
,
598 "`papersize' command requires an argument");
601 int n
= handle_papersize_command(arg
);
603 error_with_file_and_line(filename
, lineno
,
604 "unknown paper size `%1'", arg
);
608 }; // if (arg == 0) ... else ...
609 }; // if (strcasecmp(command, "papersize")
611 // orientation command
612 if (strcasecmp(command
, "orientation") == 0) {
613 // We give priority to command line options
614 if (orientation
> 0) return;
616 error_with_file_and_line(filename
, lineno
,
617 "`papersize' command requires an argument");
619 if (strcasecmp(arg
,"portrait") == 0) orientation
= 0;
620 else { if (strcasecmp(arg
,"landscape") == 0) orientation
= 1;
621 else error_with_file_and_line(filename
, lineno
,
622 "`orientation' command requires an argument");
624 }; // if (arg == 0) ... else ...
625 }; // if (strcasecmp(command, "orientation") == 0)
628 static struct option long_options
[] = {
629 {"orientation",1,NULL
,'o'},
630 {"version",0,NULL
,'v'},
631 {"copies",1,NULL
,'c'},
632 {"landscape",0,NULL
,'l'},
633 {"papersize",1,NULL
,'p'},
634 {"fontdir",1,NULL
,'F'},
642 "usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or] "\
644 " -o --orientation=[portrait|landscape]\n"\
646 " -c --copies=numcopies\n"\
648 " -p --papersize=paper_size\n"\
649 " -F --fontdir=dir\n"\
655 int main(int argc
, char **argv
)
657 if (program_name
== NULL
) program_name
= strdup(argv
[0]);
659 font::set_unknown_desc_command_handler(handle_unknown_desc_command
);
660 // command line parsing
662 int digit_optind
= 0, option_index
= 0;
666 c
= getopt_long (argc
, argv
, "F:p:lvo:c:h",\
667 long_options
, &option_index
);
669 case 'F' : font::command_line_font_dir(optarg
);
672 int n
= handle_papersize_command(optarg
);
674 error("unknown paper size `%1'", optarg
);
679 case 'l' : orientation
= 1;
682 extern const char *version_string
;
683 fprintf(stderr
, "grolbp version %s\n",\
689 if (strcasecmp(optarg
,"portrait") == 0)
692 if (strcasecmp(optarg
,"landscape") == 0)
695 error("unknown orientation '%1'", optarg
);
701 long n
= strtol(optarg
, &ptr
, 10);
702 if ((n
<= 0) && (ptr
== optarg
))
703 error("argument for -c must be a positive integer");
704 else if (n
<= 0 || n
> 32767)
705 error("out of range argument for -c");
707 ncopies
= unsigned(n
);
720 while (optind
< argc
) {
721 do_file(argv
[optind
++]);
724 lbpputs("\033c\033<");