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
36 static short int papersize
= -1, // papersize
37 orientation
= -1 , // orientation
38 paperlength
= 0, // Custom Paper size
40 ncopies
= 1; // Number of copies
42 class lbp_font
: public font
{
45 void handle_unknown_font_command(const char *command
, const char *arg
,
46 const char *filename
, int lineno
);
47 static lbp_font
*load_lbp_font(const char *);
51 lbp_font(const char *);
55 class lbp_printer
: public printer
{
59 void set_char(int, font
*, const environment
*, int, const char *name
);
60 void draw(int code
, int *p
, int np
, const environment
*env
);
62 void end_page(int page_length
);
63 font
*make_font(const char *);
66 void set_line_thickness(int size
, int dot
= 0);
68 void vdmflush(); // the name vdmend was already used in lbp.h
69 void setfillmode(int mode
);
70 void lbp_printer::polygon( int hpos
,int vpos
,int np
,int *p
);
71 char *lbp_printer::font_name(const lbp_font
*f
, const int siz
);
79 unsigned short cur_symbol_set
;
83 // Compatibility section.
85 // Here we define some functions not present in some of the targets
88 // Solaris 8 doesn't have the strsep function
89 static char *strsep(char **pcadena
, const char *delim
)
93 p
= strtok(*pcadena
,delim
);
94 *pcadena
= strtok(NULL
,delim
);
101 // Ditto with OS/390 and strdup
102 static char *strdup(const char *s
)
106 result
= (char *)malloc(strlen(s
)+1);
107 if (result
!= NULL
) strcpy(result
,s
);
113 lbp_font::lbp_font(const char *nm
)
118 lbp_font::~lbp_font()
122 lbp_font
*lbp_font::load_lbp_font(const char *s
)
124 lbp_font
*f
= new lbp_font(s
);
126 f
->is_scalable
= 1; // Default is that fonts are scalable
135 void lbp_font::handle_unknown_font_command(const char *command
,
137 const char *filename
, int lineno
)
139 if (strcmp(command
, "lbpname") == 0) {
141 fatal_with_file_and_line(filename
, lineno
,
142 "`%1' command requires an argument",
144 this->lbpname
= new char[strlen(arg
)+1];
145 strcpy(this->lbpname
,arg
);
146 // We Recongnize bitmaped fonts by the first character of it's name
147 if (arg
[0] == 'N') this->is_scalable
= 0;
148 // fprintf(stderr,"Loading font \"%s\" \n",arg);
149 }; // if (strcmp(command, "lbpname")
150 // fprintf(stderr,"Loading font %s \"%s\" in %s at %d\n",command,arg,filename,lineno);
153 static void wp54charset()
157 lbpputs("\033[714;100;29;0;32;120.}");
158 for (i
= 0; i
< sizeof(symset
) ; i
++) lbpputc(symset
[i
]);
159 lbpputs("\033[100;0 D");
163 lbp_printer::lbp_printer()
173 lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
174 wp54charset(); // Define the new symbol set
175 lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
176 // Paper size handling
177 if (orientation
< 0) orientation
= 0;// Default orientation is portrait
178 if (papersize
< 0) papersize
= 14; // Default paper size is A4
179 if (papersize
< 80) // standard paper
180 lbpprintf("\033[%dp",(papersize
| orientation
));
182 lbpprintf("\033[%d;%d;%dp",(papersize
| orientation
),\
183 paperlength
,paperwidth
);
186 lbpprintf("\033[%dv\n",ncopies
);
188 lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
190 lbpputs("\033[0t\033[2t");
191 lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML
192 // Secondary symbol set IBMR1
196 lbp_printer::~lbp_printer()
198 lbpputs("\033P1y\033\\");
199 lbpputs("\033c\033<");
202 void lbp_printer::begin_page(int)
206 void lbp_printer::end_page(int)
208 if (vdminited()) vdmflush();
213 void lbp_printer::end_of_line()
215 cur_hpos
= -1; // force absolute motion
218 char *lbp_printer::font_name(const lbp_font
*f
, const int siz
)
220 static char bfont_name
[255] ; // The resulting font name
221 char type
, // Italic, Roman, Bold
222 ori
, // Normal or Rotated
223 *nam
; // The font name without other data.
224 // nam[strlen(f->lbpname)-2]; // The font name without other data.
225 int cpi
; // The font size in characters per inch
226 // (Bitmaped fonts are monospaced).
229 /* Bitmap font selection is ugly in this printer, so don't expect
230 this function to be elegant. */
232 bfont_name
[0] = 0x00;
233 if (orientation
) // Landscape
237 type
= f
->lbpname
[strlen(f
->lbpname
)-1];
238 nam
= new char[strlen(f
->lbpname
)-2];
239 strncpy(nam
,&(f
->lbpname
[1]),strlen(f
->lbpname
)-2);
240 nam
[strlen(f
->lbpname
)-2] = 0x00;
241 // fprintf(stderr,"Bitmap font '%s' %d %c %c \n",nam,siz,type,ori);
242 /* Since these fonts are avaiable only at certain sizes,
243 10 and 17 cpi for courier, 12 and 17 cpi for elite,
244 we adjust the resulting size. */
246 // Fortunately there were only two bitmaped fonts shiped with the printer.
247 if (!strcasecmp(nam
,"courier"))
249 if (siz
>= 12) cpi
= 10;
252 if (!strcasecmp(nam
,"elite"))
254 if (siz
>= 10) cpi
= 12;
258 // Now that we have all the data, let's generate the font name.
259 if ((type
!= 'B') && (type
!= 'I')) // Roman font
260 sprintf(bfont_name
,"%c%s%d",ori
,nam
,cpi
);
262 sprintf(bfont_name
,"%c%s%d%c",ori
,nam
,cpi
,type
);
266 }; // lbp_printer::font_name
268 void lbp_printer::set_char(int index
, font
*f
, const environment
*env
, int w
, const char *name
)
270 int code
= f
->get_code(index
);
272 unsigned char ch
= code
& 0xff;
273 unsigned short symbol_set
= code
>> 8;
275 lbp_font
*psf
= (lbp_font
*)f
;
276 // fprintf(stderr,"Loading font %s \"%d\" \n",psf->lbpname,env->size);
277 if (psf
->is_scalable
)
278 { // Scalable font selection is different from bitmaped
279 lbpprintf("\033Pz%s.IBML\033\\\033[%d C",psf
->lbpname
,\
280 (int)((env
->size
*300)/72));
283 lbpprintf("\033Pz%s.IBML\033\\\n",font_name(psf
,env
->size
));
285 lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
286 cur_size
= env
->size
;
290 if (symbol_set
!= cur_symbol_set
) {
291 if ( cur_symbol_set
== 3 ) {
292 // if current symbol set is Symbol we must restore the font
293 lbpprintf("\033Pz%s.IBML\033\\\033[%d C",cur_font
->lbpname
,\
294 (int)((env
->size
*300)/72));
295 }; // if ( cur_symbol_set == 3 )
296 switch (symbol_set
) {
297 case 0: lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
299 case 1: lbpputs("\033(d\033)' 1"); // Select wp54 symbol set
301 case 2: lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set
303 case 3: lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",\
304 (int)((env
->size
*300)/72));
305 lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
307 case 4: lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
309 }; // switch (symbol_set)
311 // if (symbol_set == 1) lbpputs("\033(d"); // Select wp54 symbol set
312 // else lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
313 cur_symbol_set
= symbol_set
;
315 if (env
->size
!= cur_size
) {
317 if (!cur_font
->is_scalable
)
318 lbpprintf("\033Pz%s.IBML\033\\\n",font_name(cur_font
,env
->size
));
320 lbpprintf("\033[%d C",(int)((env
->size
*300)/72));
321 cur_size
= env
->size
;
323 if ((env
->hpos
!= cur_hpos
) || (env
->vpos
!= cur_vpos
))
325 // lbpmoveabs(env->hpos - ((5*300)/16),env->vpos );
326 lbpmoveabs(env
->hpos
- 64,env
->vpos
- 64 );
327 cur_vpos
= env
->vpos
;
328 cur_hpos
= env
->hpos
;
330 if ((ch
& 0x7F) < 32) lbpputs("\033[1.v");
336 lbp_printer::vdmstart()
339 static int changed_origin
= 0;
343 // f = fopen("/tmp/gtmp","w+");
344 if (f
== NULL
) perror("Openinig temp file");
346 if (!changed_origin
) { // we should change the origin only one time
350 vdmlinewidth(line_thickness
);
355 lbp_printer::vdmflush()
362 /* lets copy the vdm code to the output */
366 bytes_read
= fread(buffer
,1,sizeof(buffer
),vdmoutput
);
367 bytes_read
= fwrite(buffer
,1,bytes_read
,lbpoutput
);
368 } while ( bytes_read
== sizeof(buffer
));
370 fclose(vdmoutput
); // This will also delete the file,
371 // since it is created by tmpfile()
374 }; // lbp_printer::vdmflush
377 lbp_printer::setfillmode(int mode
)
379 if (mode
!= fill_mode
) {
380 if (mode
!= 1) vdmsetfillmode(mode
,1,0);
381 else vdmsetfillmode(mode
,1,1); // To get black we must use white
388 lbp_printer::polygon( int hpos
,int vpos
,int np
,int *p
)
390 //int points[np+2],i;
393 points
= new int[np
+2];
396 /* fprintf(stderr,"Poligon (%d,%d) ", points[0],points[1]);*/
397 for (i
= 0; i
< np
; i
++) points
[i
+2] = p
[i
];
398 /* for (i = 0; i < np; i++) fprintf(stderr," %d ",p[i]);
399 fprintf(stderr,"\n"); */
400 vdmpolygon((np
/2) + 1,points
);
403 void lbp_printer::draw(int code
, int *p
, int np
, const environment
*env
)
407 if (np
== 0) line_thickness
= 1;
408 else { // troff gratuitously adds an extra 0
409 if (np
!= 1 && np
!= 2) {
410 error("0 or 1 argument required for thickness");
413 if (p
[0] == 0) line_thickness
= 1;
414 if (p
[0] < 0) // Default = 1 point
415 line_thickness
= (int)(env
->size
*30/72);
416 line_thickness
= (int)((abs(p
[0])*env
->size
)/10);
417 if ((line_thickness
> 16 ) && (!vdminited()))
418 { /* for greater thickness we must use VDM */
420 /* vdmlinewidth(line_thickness); already done in
423 if (vdminited()) vdmlinewidth(line_thickness
);
424 // fprintf(stderr,"\nthickness: %d == %d, size %d\n",\
425 // p[0],line_thickness,env->size );
431 error("2 arguments required for line");
434 if (!vdminited()) vdmstart();
435 vdmline(env
->hpos
,env
->vpos
,p
[0],p
[1]);
436 /*fprintf(stderr,"\nline: %d,%d - %d,%d thickness %d == %d\n",\
437 env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],\
438 env->vpos -64 + p[1],env->size, line_thickness);*/
442 error("2 arguments required for Rule");
446 setfillmode(fill_pattern
); // Solid Rule
447 vdmrectangle(env
->hpos
,env
->vpos
,p
[0],p
[1]);
450 lbpruleabs(env
->hpos
- 64,env
->vpos
-64 , p
[0], p
[1]);
454 fprintf(stderr
,"\nrule: thickness %d == %d\n", env
->size
, line_thickness
);
456 case 'P': // Filled Polygon
457 if (!vdminited()) vdmstart();
458 setfillmode(fill_pattern
);
459 polygon(env
->hpos
,env
->vpos
,np
,p
);
461 case 'p': // Empty Polygon
462 if (!vdminited()) vdmstart();
464 polygon(env
->hpos
,env
->vpos
,np
,p
);
466 case 'C': // Filled Circle
467 if (!vdminited()) vdmstart();
468 // fprintf(stderr,"Circle (%d,%d) Fill %d\n",env->hpos,env->vpos,fill_pattern);
469 setfillmode(fill_pattern
);
470 vdmcircle(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2);
472 case 'c': // Empty Circle
473 if (!vdminited()) vdmstart();
475 vdmcircle(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2);
477 case 'E': // Filled Ellipse
478 if (!vdminited()) vdmstart();
479 setfillmode(fill_pattern
);
480 vdmellipse(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2,p
[1]/2,0);
482 case 'e': // Empty Ellipse
483 if (!vdminited()) vdmstart();
485 vdmellipse(env
->hpos
+ (p
[0]/2),env
->vpos
,p
[0]/2,p
[1]/2,0);
488 if (!vdminited()) vdmstart();
490 // VDM draws arcs clockwise and pic counterclockwise
491 // We must compensate for that, exchanging the starting and
493 vdmvarc(env
->hpos
+ p
[0],env
->vpos
+p
[1],\
494 int(sqrt( (p
[0]*p
[0])+(p
[1]*p
[1]))),\
496 (-p
[0]),(-p
[1]),1,2);
499 if (!vdminited()) vdmstart();
501 vdmspline(np
/2,env
->hpos
,env
->vpos
,p
);
504 if (np
!= 1 && np
!= 2) {
505 error("1 argument required for fill");
508 // fprintf(stderr,"Fill %d\n",p[0]);
509 if ((p
[0] == 1) || (p
[0] >= 1000)) { // Black
513 if (p
[0] == 0) { // White
517 if ((p
[0] > 1) && (p
[0] < 1000))
519 if (p
[0] >= 990) fill_pattern
= -23;
520 else if (p
[0] >= 700) fill_pattern
= -28;
521 else if (p
[0] >= 500) fill_pattern
= -27;
522 else if (p
[0] >= 400) fill_pattern
= -26;
523 else if (p
[0] >= 300) fill_pattern
= -25;
524 else if (p
[0] >= 200) fill_pattern
= -22;
525 else if (p
[0] >= 100) fill_pattern
= -24;
526 else fill_pattern
= -21;
527 }; // if (p[0] >= 0 && p[0] <= 1000)
530 error("unrecognised drawing command `%1'", char(code
));
536 font
*lbp_printer::make_font(const char *nm
)
538 return lbp_font::load_lbp_font(nm
);
543 printer
*make_printer()
545 return new lbp_printer
;
560 static int set_papersize(const char *papersize
)
564 // First test for a standard (i.e. supported directly by the printer)
566 for (i
= 0 ; i
< sizeof(papersizes
)/sizeof(papersizes
[0]); i
++)
568 if (strcasecmp(papersizes
[i
].name
,papersize
) == 0)
569 return papersizes
[i
].code
;
572 // Now test for a custom papersize
573 if (strncasecmp("cust",papersize
,4) == 0)
579 p
= papsize
= strdup(&papersize
[4]);
580 if (papsize
== NULL
) return -1;
583 { // let's test for an uppercase x
586 if (p
== NULL
) { free(papsize
); return -1;};
587 }; // if (p1 == NULL)
588 paperlength
= atoi(p1
);
589 if (paperlength
== 0) { free(papsize
); return -1;};
590 paperwidth
= atoi(p
);
591 if (paperwidth
== 0) { free(papsize
); return -1;};
594 }; // if (strcnasecmp("cust",papersize,4) == 0)
599 static int handle_papersize_command(const char *arg
)
601 int n
= set_papersize(arg
);
604 { // If is not a standard nor custom paper size
605 // let's see if it's a file (i.e /etc/papersize )
606 FILE *f
= fopen(arg
,"r");
608 { // the file exists and is readable
612 // set_papersize doesn't like the trailing \n
613 p
= psize
; while (*p
) p
++;
614 if (*(--p
) == '\n') *p
= 0x00;
616 n
= set_papersize(psize
);
621 }; // handle_papersize_command
624 static void handle_unknown_desc_command(const char *command
, const char *arg
,
625 const char *filename
, int lineno
)
628 if (strcasecmp(command
, "papersize") == 0) {
629 // We give priority to command line options
630 if (papersize
> 0) return;
632 error_with_file_and_line(filename
, lineno
,
633 "`papersize' command requires an argument");
636 int n
= handle_papersize_command(arg
);
638 error_with_file_and_line(filename
, lineno
,
639 "unknown paper size `%1'", arg
);
643 }; // if (arg == 0) ... else ...
644 }; // if (strcasecmp(command, "papersize")
646 // orientation command
647 if (strcasecmp(command
, "orientation") == 0) {
648 // We give priority to command line options
649 if (orientation
> 0) return;
651 error_with_file_and_line(filename
, lineno
,
652 "`papersize' command requires an argument");
654 if (strcasecmp(arg
,"portrait") == 0) orientation
= 0;
655 else { if (strcasecmp(arg
,"landscape") == 0) orientation
= 1;
656 else error_with_file_and_line(filename
, lineno
,
657 "`orientation' command requires an argument");
659 }; // if (arg == 0) ... else ...
660 }; // if (strcasecmp(command, "orientation") == 0)
663 static struct option long_options
[] = {
664 {"orientation",1,NULL
,'o'},
665 {"version",0,NULL
,'v'},
666 {"copies",1,NULL
,'c'},
667 {"landscape",0,NULL
,'l'},
668 {"papersize",1,NULL
,'p'},
669 {"fontdir",1,NULL
,'F'},
677 "usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or] "\
679 " -o --orientation=[portrait|landscape]\n"\
681 " -c --copies=numcopies\n"\
683 " -p --papersize=paper_size\n"\
684 " -F --fontdir=dir\n"\
690 int main(int argc
, char **argv
)
692 if (program_name
== NULL
) program_name
= strdup(argv
[0]);
694 font::set_unknown_desc_command_handler(handle_unknown_desc_command
);
695 // command line parsing
697 int option_index
= 0;
701 c
= getopt_long (argc
, argv
, "F:p:lvo:c:h",\
702 long_options
, &option_index
);
704 case 'F' : font::command_line_font_dir(optarg
);
707 int n
= handle_papersize_command(optarg
);
709 error("unknown paper size `%1'", optarg
);
714 case 'l' : orientation
= 1;
717 extern const char *version_string
;
718 fprintf(stderr
, "grolbp version %s\n",\
724 if (strcasecmp(optarg
,"portrait") == 0)
727 if (strcasecmp(optarg
,"landscape") == 0)
730 error("unknown orientation '%1'", optarg
);
736 long n
= strtol(optarg
, &ptr
, 10);
737 if ((n
<= 0) && (ptr
== optarg
))
738 error("argument for -c must be a positive integer");
739 else if (n
<= 0 || n
> 32767)
740 error("out of range argument for -c");
742 ncopies
= unsigned(n
);
755 while (optind
< argc
) {
756 do_file(argv
[optind
++]);
759 lbpputs("\033c\033<");