2 /* Copyright (C) 1994, 2000, 2001, 2002, 2003 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
39 extern "C" const char *Version_string
;
41 static int user_papersize
= -1; // papersize
42 static int orientation
= -1; // orientation
43 static double user_paperlength
= 0; // Custom Paper size
44 static double user_paperwidth
= 0;
45 static int ncopies
= 1; // Number of copies
47 #define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em
48 static int linewidth_factor
= DEFAULT_LINEWIDTH_FACTOR
;
50 static int set_papersize(const char *paperformat
);
52 class lbp_font
: public font
{
55 void handle_unknown_font_command(const char *command
, const char *arg
,
56 const char *filename
, int lineno
);
57 static lbp_font
*load_lbp_font(const char *);
61 lbp_font(const char *);
64 class lbp_printer
: public printer
{
66 lbp_printer(int, double, double);
68 void set_char(int, font
*, const environment
*, int, const char *name
);
69 void draw(int code
, int *p
, int np
, const environment
*env
);
71 void end_page(int page_length
);
72 font
*make_font(const char *);
75 void set_line_thickness(int size
,const environment
*env
);
77 void vdmflush(); // the name vdmend was already used in lbp.h
78 void setfillmode(int mode
);
79 void polygon( int hpos
,int vpos
,int np
,int *p
);
80 char *font_name(const lbp_font
*f
, const int siz
);
88 unsigned short cur_symbol_set
;
90 int req_linethickness
; // requested line thickness
92 int paperlength
; // custom paper size
96 // Compatibility section.
98 // Here we define some functions not present in some of the targets
101 // Solaris 8 doesn't have the strsep function
102 static char *strsep(char **pcadena
, const char *delim
)
105 p
= strtok(*pcadena
, delim
);
106 *pcadena
= strtok(NULL
, delim
);
111 lbp_font::lbp_font(const char *nm
)
116 lbp_font::~lbp_font()
120 lbp_font
*lbp_font::load_lbp_font(const char *s
)
122 lbp_font
*f
= new lbp_font(s
);
124 f
->is_scalable
= 1; // Default is that fonts are scalable
133 void lbp_font::handle_unknown_font_command(const char *command
,
135 const char *filename
, int lineno
)
137 if (strcmp(command
, "lbpname") == 0) {
139 fatal_with_file_and_line(filename
, lineno
,
140 "`%1' command requires an argument",
142 this->lbpname
= new char[strlen(arg
) + 1];
143 strcpy(this->lbpname
, arg
);
144 // we recognize bitmapped fonts by the first character of its name
146 this->is_scalable
= 0;
147 // fprintf(stderr, "Loading font \"%s\" \n", arg);
149 // fprintf(stderr, "Loading font %s \"%s\" in %s at %d\n",
150 // command, arg, filename, lineno);
153 static void wp54charset()
156 lbpputs("\033[714;100;29;0;32;120.}");
157 for (i
= 0; i
< sizeof(symset
); i
++)
159 lbpputs("\033[100;0 D");
163 lbp_printer::lbp_printer(int ps
, double pw
, double pl
)
170 req_linethickness(-1)
172 SET_BINARY(fileno(stdout
));
174 lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
175 wp54charset(); // Define the new symbol set
176 lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
177 // Paper size handling
179 orientation
= 0; // Default orientation is portrait
180 papersize
= 14; // Default paper size is A4
181 if (font::papersize
) {
182 papersize
= set_papersize(font::papersize
);
183 paperlength
= font::paperlength
;
184 paperwidth
= font::paperwidth
;
188 paperlength
= int(pl
* font::res
+ 0.5);
189 paperwidth
= int(pw
* font::res
+ 0.5);
191 if (papersize
< 80) // standard paper
192 lbpprintf("\033[%dp", (papersize
| orientation
));
194 lbpprintf("\033[%d;%d;%dp", (papersize
| orientation
),
195 paperlength
, paperwidth
);
197 lbpprintf("\033[%dv\n", ncopies
);
198 lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
200 lbpputs("\033[0t\033[2t");
201 lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML
202 // Secondary symbol set IBMR1
206 lbp_printer::~lbp_printer()
208 lbpputs("\033P1y\033\\");
209 lbpputs("\033c\033<");
212 inline void lbp_printer::set_line_thickness(int size
,const environment
*env
)
219 // (env->size * (font::res/72)) * (linewidth_factor/1000)
220 // we ought to check for overflow
222 env
->size
* linewidth_factor
* font::res
/ 72000;
224 line_thickness
= size
;
225 } // else from if (size == 0)
226 if (line_thickness
< 1)
229 vdmlinewidth(line_thickness
);
230 req_linethickness
= size
; // an size requested
231 /* fprintf(stderr, "thickness: %d == %d, size %d, %d \n",
232 size, line_thickness, env->size,req_linethickness); */
234 }; // lbp_printer::set_line_thickness
236 void lbp_printer::begin_page(int)
240 void lbp_printer::end_page(int)
248 void lbp_printer::end_of_line()
250 cur_hpos
= -1; // force absolute motion
253 char *lbp_printer::font_name(const lbp_font
*f
, const int siz
)
255 static char bfont_name
[255]; // The resulting font name
256 char type
, // Italic, Roman, Bold
257 ori
, // Normal or Rotated
258 *nam
; // The font name without other data.
259 int cpi
; // The font size in characters per inch
260 // (bitmapped fonts are monospaced).
261 /* Bitmap font selection is ugly in this printer, so don't expect
262 this function to be elegant. */
263 bfont_name
[0] = 0x00;
264 if (orientation
) // Landscape
268 type
= f
->lbpname
[strlen(f
->lbpname
) - 1];
269 nam
= new char[strlen(f
->lbpname
) - 2];
270 strncpy(nam
, &(f
->lbpname
[1]), strlen(f
->lbpname
) - 2);
271 nam
[strlen(f
->lbpname
) - 2] = 0x00;
272 // fprintf(stderr, "Bitmap font '%s' %d %c %c \n", nam, siz, type, ori);
273 /* Since these fonts are available only at certain sizes,
274 10 and 17 cpi for courier, 12 and 17 cpi for elite,
275 we adjust the resulting size. */
277 // Fortunately there are only two bitmapped fonts shipped with the printer.
278 if (!strcasecmp(nam
, "courier")) {
284 if (!strcasecmp(nam
, "elite")) {
289 // Now that we have all the data, let's generate the font name.
290 if ((type
!= 'B') && (type
!= 'I')) // Roman font
291 sprintf(bfont_name
, "%c%s%d", ori
, nam
, cpi
);
293 sprintf(bfont_name
, "%c%s%d%c", ori
, nam
, cpi
, type
);
297 void lbp_printer::set_char(int index
, font
*f
, const environment
*env
,
300 int code
= f
->get_code(index
);
301 unsigned char ch
= code
& 0xff;
302 unsigned short symbol_set
= code
>> 8;
304 lbp_font
*psf
= (lbp_font
*)f
;
305 // fprintf(stderr, "Loading font %s \"%d\" \n", psf->lbpname, env->size);
306 if (psf
->is_scalable
) {
307 // Scalable font selection is different from bitmaped
308 lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf
->lbpname
,
309 (int)((env
->size
* font::res
) / 72));
313 lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf
, env
->size
));
314 lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
317 // Update the line thickness if needed
318 if ((req_linethickness
< 0 ) && (env
->size
!= cur_size
))
319 set_line_thickness(req_linethickness
,env
);
320 cur_size
= env
->size
;
322 if (symbol_set
!= cur_symbol_set
) {
323 if (cur_symbol_set
== 3)
324 // if current symbol set is Symbol we must restore the font
325 lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font
->lbpname
,
326 (int)((env
->size
* font::res
) / 72));
327 switch (symbol_set
) {
329 lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
332 lbpputs("\033(d\033)' 1"); // Select wp54 symbol set
335 lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set
338 lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",
339 (int)((env
->size
* font::res
) / 72));
340 lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
343 lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
346 cur_symbol_set
= symbol_set
;
348 if (env
->size
!= cur_size
) {
349 if (!cur_font
->is_scalable
)
350 lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font
, env
->size
));
352 lbpprintf("\033[%d C", (int)((env
->size
* font::res
) / 72));
353 cur_size
= env
->size
;
354 // Update the line thickness if needed
355 if (req_linethickness
< 0 )
356 set_line_thickness(req_linethickness
,env
);
358 if ((env
->hpos
!= cur_hpos
) || (env
->vpos
!= cur_vpos
)) {
359 // lbpmoveabs(env->hpos - ((5 * 300) / 16), env->vpos);
360 lbpmoveabs(env
->hpos
- 64, env
->vpos
- 64);
361 cur_vpos
= env
->vpos
;
362 cur_hpos
= env
->hpos
;
364 if ((ch
& 0x7F) < 32)
370 void lbp_printer::vdmstart()
373 static int changed_origin
= 0;
376 // f = fopen("/tmp/gtmp","w+");
378 perror("Opening temporary file");
380 if (!changed_origin
) { // we should change the origin only one time
384 vdmlinewidth(line_thickness
);
388 lbp_printer::vdmflush()
394 /* let's copy the vdm code to the output */
397 bytes_read
= fread(buffer
, 1, sizeof(buffer
), vdmoutput
);
398 bytes_read
= fwrite(buffer
, 1, bytes_read
, lbpoutput
);
399 } while (bytes_read
== sizeof(buffer
));
400 fclose(vdmoutput
); // This will also delete the file,
401 // since it is created by tmpfile()
405 inline void lbp_printer::setfillmode(int mode
)
407 if (mode
!= fill_mode
) {
409 vdmsetfillmode(mode
, 1, 0);
411 vdmsetfillmode(mode
, 1, 1); // To get black we must use white
417 inline void lbp_printer::polygon(int hpos
, int vpos
, int np
, int *p
)
420 points
= new int[np
+ 2];
423 // fprintf(stderr, "Poligon (%d,%d) ", points[0], points[1]);
424 for (i
= 0; i
< np
; i
++)
425 points
[i
+ 2] = p
[i
];
426 // for (i = 0; i < np; i++) fprintf(stderr, " %d ", p[i]);
427 // fprintf(stderr, "\n");
428 vdmpolygon((np
/2) + 1, points
);
431 void lbp_printer::draw(int code
, int *p
, int np
, const environment
*env
)
433 if ((req_linethickness
< 0 ) && (env
->size
!= cur_size
))
434 set_line_thickness(req_linethickness
,env
);
440 else { // troff gratuitously adds an extra 0
441 if (np
!= 1 && np
!= 2) {
442 error("0 or 1 argument required for thickness");
445 set_line_thickness(p
[0],env
);
450 error("2 arguments required for line");
455 vdmline(env
->hpos
, env
->vpos
, p
[0], p
[1]);
456 /* fprintf(stderr, "\nline: %d,%d - %d,%d thickness %d == %d\n",
457 env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],
458 env->vpos -64 + p[1], env->size, line_thickness);*/
462 error("2 arguments required for Rule");
466 setfillmode(fill_pattern
); // Solid Rule
467 vdmrectangle(env
->hpos
, env
->vpos
, p
[0], p
[1]);
470 lbpruleabs(env
->hpos
- 64, env
->vpos
-64, p
[0], p
[1]);
474 // fprintf(stderr, "\nrule: thickness %d == %d\n",
475 // env->size, line_thickness);
477 case 'P': // Filled Polygon
480 setfillmode(fill_pattern
);
481 polygon(env
->hpos
, env
->vpos
, np
, p
);
483 case 'p': // Empty Polygon
487 polygon(env
->hpos
, env
->vpos
, np
, p
);
489 case 'C': // Filled Circle
492 // fprintf(stderr, "Circle (%d,%d) Fill %d\n",
493 // env->hpos, env->vpos, fill_pattern);
494 setfillmode(fill_pattern
);
495 vdmcircle(env
->hpos
+ (p
[0]/2), env
->vpos
, p
[0]/2);
497 case 'c': // Empty Circle
501 vdmcircle(env
->hpos
+ (p
[0]/2), env
->vpos
, p
[0]/2);
503 case 'E': // Filled Ellipse
506 setfillmode(fill_pattern
);
507 vdmellipse(env
->hpos
+ (p
[0]/2), env
->vpos
, p
[0]/2, p
[1]/2, 0);
509 case 'e': // Empty Ellipse
513 vdmellipse(env
->hpos
+ (p
[0]/2), env
->vpos
, p
[0]/2, p
[1]/2, 0);
519 // VDM draws arcs clockwise and pic counterclockwise
520 // We must compensate for that, exchanging the starting and
522 vdmvarc(env
->hpos
+ p
[0], env
->vpos
+p
[1],
523 int(sqrt(double((p
[0]*p
[0]) + (p
[1]*p
[1])))),
525 (-p
[0]), (-p
[1]), 1, 2);
531 vdmspline(np
/2, env
->hpos
, env
->vpos
, p
);
534 if (np
!= 1 && np
!= 2) {
535 error("1 argument required for fill");
538 // fprintf(stderr, "Fill %d\n", p[0]);
539 if ((p
[0] == 1) || (p
[0] >= 1000)) { // Black
543 if (p
[0] == 0) { // White
547 if ((p
[0] > 1) && (p
[0] < 1000))
549 if (p
[0] >= 990) fill_pattern
= -23;
550 else if (p
[0] >= 700) fill_pattern
= -28;
551 else if (p
[0] >= 500) fill_pattern
= -27;
552 else if (p
[0] >= 400) fill_pattern
= -26;
553 else if (p
[0] >= 300) fill_pattern
= -25;
554 else if (p
[0] >= 200) fill_pattern
= -22;
555 else if (p
[0] >= 100) fill_pattern
= -24;
556 else fill_pattern
= -21;
560 // not implemented yet
563 error("unrecognised drawing command `%1'", char(code
));
569 font
*lbp_printer::make_font(const char *nm
)
571 return lbp_font::load_lbp_font(nm
);
574 printer
*make_printer()
576 return new lbp_printer(user_papersize
, user_paperwidth
, user_paperlength
);
589 static int set_papersize(const char *paperformat
)
592 // First test for a standard (i.e. supported directly by the printer)
594 for (i
= 0 ; i
< sizeof(lbp_papersizes
) / sizeof(lbp_papersizes
[0]); i
++)
596 if (strcasecmp(lbp_papersizes
[i
].name
,paperformat
) == 0)
597 return lbp_papersizes
[i
].code
;
599 // Otherwise, we assume a custom paper size
603 static void handle_unknown_desc_command(const char *command
, const char *arg
,
604 const char *filename
, int lineno
)
606 // orientation command
607 if (strcasecmp(command
, "orientation") == 0) {
608 // We give priority to command line options
612 error_with_file_and_line(filename
, lineno
,
613 "`orientation' command requires an argument");
615 if (strcasecmp(arg
, "portrait") == 0)
618 if (strcasecmp(arg
, "landscape") == 0)
621 error_with_file_and_line(filename
, lineno
,
622 "invalid argument to `orientation' command");
628 static struct option long_options
[] = {
629 { "orientation", required_argument
, NULL
, 'o' },
630 { "version", no_argument
, NULL
, 'v' },
631 { "copies", required_argument
, NULL
, 'c' },
632 { "landscape", no_argument
, NULL
, 'l' },
633 { "papersize", required_argument
, NULL
, 'p' },
634 { "linewidth", required_argument
, NULL
, 'w' },
635 { "fontdir", required_argument
, NULL
, 'F' },
636 { "help", no_argument
, NULL
, 'h' },
640 static void usage(FILE *stream
)
643 "usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or]\n"
644 " [-w width] [files ...]\n"
646 " -o --orientation=[portrait|landscape]\n"
648 " -c --copies=numcopies\n"
650 " -p --papersize=paper_size\n"
651 " -w --linewidth=width\n"
652 " -F --fontdir=dir\n"
657 int main(int argc
, char **argv
)
659 if (program_name
== NULL
)
660 program_name
= strsave(argv
[0]);
661 font::set_unknown_desc_command_handler(handle_unknown_desc_command
);
662 // command line parsing
664 int option_index
= 0;
666 c
= getopt_long (argc
, argv
, "c:F:hI:lo:p:vw:",
667 long_options
, &option_index
);
670 font::command_line_font_dir(optarg
);
673 // ignore include path arguments
678 if (!font::scan_papersize(optarg
, &s
,
679 &user_paperlength
, &user_paperwidth
))
680 error("invalid paper size `%1' ignored", optarg
);
682 user_papersize
= set_papersize(s
);
689 printf("GNU grolbp (groff) version %s\n", Version_string
);
693 if (strcasecmp(optarg
, "portrait") == 0)
696 if (strcasecmp(optarg
, "landscape") == 0)
699 error("unknown orientation '%1'", optarg
);
705 long n
= strtol(optarg
, &ptr
, 10);
706 if ((n
<= 0) && (ptr
== optarg
))
707 error("argument for -c must be a positive integer");
708 else if (n
<= 0 || n
> 32767)
709 error("out of range argument for -c");
711 ncopies
= unsigned(n
);
717 long n
= strtol(optarg
, &ptr
, 10);
718 if (n
== 0 && ptr
== optarg
)
719 error("argument for -w must be a non-negative integer");
720 else if (n
< 0 || n
> INT_MAX
)
721 error("out of range argument for -w");
723 linewidth_factor
= int(n
);
738 while (optind
< argc
)
739 do_file(argv
[optind
++]);
740 lbpputs("\033c\033<");