summaryrefslogtreecommitdiffstats
path: root/src/devices/grolbp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/grolbp')
-rw-r--r--src/devices/grolbp/charset.h89
-rw-r--r--src/devices/grolbp/grolbp.1.man504
-rw-r--r--src/devices/grolbp/grolbp.am36
-rw-r--r--src/devices/grolbp/lbp.cpp738
-rw-r--r--src/devices/grolbp/lbp.h544
5 files changed, 1911 insertions, 0 deletions
diff --git a/src/devices/grolbp/charset.h b/src/devices/grolbp/charset.h
new file mode 100644
index 0000000..c4e43a0
--- /dev/null
+++ b/src/devices/grolbp/charset.h
@@ -0,0 +1,89 @@
+// -*- C++ -*-
+/* Copyright (C) 2000-2020 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+// Definition of the WP54 character set
+
+unsigned char symset[] = {
+0x57,0x50,0x35,0x34,0x00,0x41,0x76,0x61,0x6e,0x74,0x47,0x61,
+0x72,0x64,0x65,0x2d,0x42,0x6f,0x6f,0x6b,0x00,0x41,0x76,
+0x61,0x6e,0x74,0x47,0x61,0x72,0x64,0x65,0x2d,0x44,0x65,
+0x6d,0x69,0x00,0x41,0x76,0x61,0x6e,0x74,0x47,0x61,0x72,
+0x64,0x65,0x2d,0x42,0x6f,0x6f,0x6b,0x4f,0x62,0x6c,0x69,
+0x71,0x75,0x65,0x00,0x41,0x76,0x61,0x6e,0x74,0x47,0x61,
+0x72,0x64,0x65,0x2d,0x44,0x65,0x6d,0x69,0x4f,0x62,0x6c,
+0x69,0x71,0x75,0x65,0x00,0x42,0x6f,0x6f,0x6b,0x6d,0x61,
+0x6e,0x2d,0x4c,0x69,0x67,0x68,0x74,0x00,0x42,0x6f,0x6f,
+0x6b,0x6d,0x61,0x6e,0x2d,0x44,0x65,0x6d,0x69,0x00,0x42,
+0x6f,0x6f,0x6b,0x6d,0x61,0x6e,0x2d,0x4c,0x69,0x67,0x68,
+0x74,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x42,0x6f,0x6f,
+0x6b,0x6d,0x61,0x6e,0x2d,0x44,0x65,0x6d,0x69,0x49,0x74,
+0x61,0x6c,0x69,0x63,0x00,0x43,0x65,0x6e,0x74,0x75,0x72,
+0x79,0x53,0x63,0x68,0x6c,0x62,0x6b,0x2d,0x52,0x6f,0x6d,
+0x61,0x6e,0x00,0x43,0x65,0x6e,0x74,0x75,0x72,0x79,0x53,
+0x63,0x68,0x6c,0x62,0x6b,0x2d,0x42,0x6f,0x6c,0x64,0x00,
+0x43,0x65,0x6e,0x74,0x75,0x72,0x79,0x53,0x63,0x68,0x6c,
+0x62,0x6b,0x2d,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x43,
+0x65,0x6e,0x74,0x75,0x72,0x79,0x53,0x63,0x68,0x6c,0x62,
+0x6b,0x2d,0x42,0x6f,0x6c,0x64,0x49,0x74,0x61,0x6c,0x69,
+0x63,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,0x52,0x6f,0x6d,
+0x61,0x6e,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,0x42,0x6f,
+0x6c,0x64,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,0x49,0x74,
+0x61,0x6c,0x69,0x63,0x00,0x44,0x75,0x74,0x63,0x68,0x2d,
+0x42,0x6f,0x6c,0x64,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,
+0x53,0x77,0x69,0x73,0x73,0x00,0x53,0x77,0x69,0x73,0x73,
+0x2d,0x42,0x6f,0x6c,0x64,0x00,0x53,0x77,0x69,0x73,0x73,
+0x2d,0x4f,0x62,0x6c,0x69,0x71,0x75,0x65,0x00,0x53,0x77,
+0x69,0x73,0x73,0x2d,0x42,0x6f,0x6c,0x64,0x4f,0x62,0x6c,
+0x69,0x71,0x75,0x65,0x00,0x53,0x77,0x69,0x73,0x73,0x2d,
+0x4e,0x61,0x72,0x72,0x6f,0x77,0x00,0x53,0x77,0x69,0x73,
+0x73,0x2d,0x4e,0x61,0x72,0x72,0x6f,0x77,0x2d,0x42,0x6f,
+0x6c,0x64,0x00,0x53,0x77,0x69,0x73,0x73,0x2d,0x4e,0x61,
+0x72,0x72,0x6f,0x77,0x2d,0x4f,0x62,0x6c,0x69,0x71,0x75,
+0x65,0x00,0x53,0x77,0x69,0x73,0x73,0x2d,0x4e,0x61,0x72,
+0x72,0x6f,0x77,0x2d,0x42,0x6f,0x6c,0x64,0x4f,0x62,0x6c,
+0x69,0x71,0x75,0x65,0x00,0x5a,0x61,0x70,0x66,0x43,0x61,
+0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x2d,
+0x52,0x6f,0x6d,0x61,0x6e,0x00,0x5a,0x61,0x70,0x66,0x43,
+0x61,0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,0x69,0x63,
+0x2d,0x42,0x6f,0x6c,0x64,0x00,0x5a,0x61,0x70,0x66,0x43,
+0x61,0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,0x69,0x63,
+0x2d,0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x5a,0x61,0x70,
+0x66,0x43,0x61,0x6c,0x6c,0x69,0x67,0x72,0x61,0x70,0x68,
+0x69,0x63,0x2d,0x42,0x6f,0x6c,0x64,0x49,0x74,0x61,0x6c,
+0x69,0x63,0x00,0x5a,0x61,0x70,0x66,0x43,0x68,0x61,0x6e,
+0x63,0x65,0x72,0x79,0x2d,0x4d,0x65,0x64,0x69,0x75,0x6d,
+0x49,0x74,0x61,0x6c,0x69,0x63,0x00,0x00,0x09,0x00,0x0A,
+0x00,0x0B,0x00,0x0E,0x00,0x14,0x00,0x17,0x00,0x18,0x00,
+0x1F,0x00,0x20,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x45,0x00,
+0x47,0x00,0x48,0x00,0x80,0x00,0x82,0x00,0x83,0x00,0x84,
+0x00,0x85,0x00,0x87,0x00,0x8B,0x00,0x8C,0x00,0x8D,0x00,0x8E,
+0x00,0x8F,0x00,0x90,0x00,0x91,0x00,0x92,0x00,0x95,0x00,0x96,
+0x00,0x97,0x00,0x98,0x00,0x99,0x00,0x9C,0x00,0x9E,0x00,
+0x9F,0x00,0xA0,0x00,0xA1,0x00,0xA2,0x00,0xA3,0x00,0xCB,0x00,
+0xCC,0x00,0xCD,0x00,0xCE,0x00,0xD1,0x00,0xD3,0x00,0xD4,
+0x00,0xD5,0x00,0xD6,0x00,0xFA,0x00,0xFB,0x00,0xFC,0x00,0xFD,
+0x00,0xCF,0x00,0x26,0x00,0x7E,0x03,0x05,0x00,0xA5,0x00,
+0xA6,0x00,0xA8,0x00,0xAA,0x00,0xAD,0x00,0xAE,0x00,0xAF,0x00,
+0xB0,0x00,0xB1,0x00,0xB2,0x00,0xB3,0x00,0xB5,0x00,0xB6,0x00,
+0xB8,0x00,0xB9,0x00,0xBA,0x00,0xBB,0x00,0xBC,0x00,0xBE,
+0x00,0xBF,0x00,0xC0,0x00,0xC1,0x00,0xC6,0x00,0xDC,0x00,0xEB,
+0x00,0xEC,0x00,0xF2,0x00,0xF3,0x00,0x15,0x00,0x16,0x00,
+0x86
+};
diff --git a/src/devices/grolbp/grolbp.1.man b/src/devices/grolbp/grolbp.1.man
new file mode 100644
index 0000000..c8cda76
--- /dev/null
+++ b/src/devices/grolbp/grolbp.1.man
@@ -0,0 +1,504 @@
+'\" t
+.TH grolbp @MAN1EXT@ "@MDATE@" "groff @VERSION@"
+.SH Name
+grolbp \-
+.I groff
+output driver for Canon CaPSL printers
+.
+.
+.\" Modified from grolj4 man page by Francisco Andrés Verdú
+.\" <pandres@dragonet.es> for the grolbp program.
+.
+.
+.\" ====================================================================
+.\" Legal Terms
+.\" ====================================================================
+.\"
+.\" Copyright (C) 1994-2020 Free Software Foundation, Inc.
+.\"
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of
+.\" this manual under the conditions for verbatim copying, provided that
+.\" the entire resulting derived work is distributed under the terms of
+.\" a permission notice identical to this one.
+.\"
+.\" Permission is granted to copy and distribute translations of this
+.\" manual into another language, under the above conditions for
+.\" modified versions, except that this permission notice may be
+.\" included in translations approved by the Free Software Foundation
+.\" instead of in the original English.
+.
+.
+.\" Save and disable compatibility mode (for, e.g., Solaris 10/11).
+.do nr *groff_grolbp_1_man_C \n[.cp]
+.cp 0
+.
+.\" Define fallback for groff 1.23's MR macro if the system lacks it.
+.nr do-fallback 0
+.if !\n(.f .nr do-fallback 1 \" mandoc
+.if \n(.g .if !d MR .nr do-fallback 1 \" older groff
+.if !\n(.g .nr do-fallback 1 \" non-groff *roff
+.if \n[do-fallback] \{\
+. de MR
+. ie \\n(.$=1 \
+. I \%\\$1
+. el \
+. IR \%\\$1 (\\$2)\\$3
+. .
+.\}
+.rr do-fallback
+.
+.
+.\" ====================================================================
+.SH Synopsis
+.\" ====================================================================
+.
+.SY grolbp
+.RB [ \-l ]
+.RB [ \-c\~\c
+.IR num-copies ]
+.RB [ \-F\~\c
+.IR font-directory ]
+.RB [ \-o\~\c
+.IR orientation ]
+.RB [ \-p\~\c
+.IR paper-format ]
+.RB [ \-w\~\c
+.IR width ]
+.RI [ file\~ .\|.\|.]
+.
+.SY grolbp
+[\c
+.BI \-\-copies= num-copies\c
+] [\c
+.BI \-\-fontdir= font-directory\c
+] [\c
+.B \-\-landscape\c
+] [\c
+.BI \-\-linewidth= width\c
+] [\c
+.BI \-\-orientation= orientation\c
+] [\c
+.BI \-\-papersize= paper-format\c
+]
+.RI [ file\~ .\|.\|.]
+.YS
+.
+.
+.SY grolbp
+.B \-h
+.
+.SY grolbp
+.B \-\-help
+.YS
+.
+.
+.SY grolbp
+.B \-v
+.
+.SY grolbp
+.B \-\-version
+.YS
+.
+.
+.\" ====================================================================
+.SH Description
+.\" ====================================================================
+.
+This GNU
+.I roff
+output driver translates the output of
+.MR @g@troff @MAN1EXT@
+into a CaPSL and VDM format suitable for Canon LBP-4 and LBP-8 printers.
+.
+Normally,
+.I grolbp
+is invoked by
+.MR groff @MAN1EXT@
+when the latter is given the
+.RB \[lq] \-T\~lbp \[rq]
+option.
+.
+(In this installation,
+.B @DEVICE@
+is the default output device.)
+.
+Use
+.IR groff 's
+.B \-P
+option to pass any options shown above to
+.IR grolbp .
+.
+If no
+.I file
+arguments are given,
+or if
+.I file
+is \[lq]\-\[rq],
+.I grolbp
+reads the standard input stream.
+.
+Output is written to the standard output stream.
+.
+.
+.\" ====================================================================
+.SS Typefaces
+.\" ====================================================================
+.
+The driver supports the Dutch,
+Swiss,
+and Swiss-Narrow scalable typefaces,
+each in the regular,
+bold,
+italic,
+and bold-italic styles.
+.
+Additionally,
+the bitmapped,
+monospaced Courier and Elite typefaces are available in regular,
+bold,
+and
+italic styles;
+Courier at 8 and 12 points,
+Elite at 8 and 10 points.
+.
+The following chart summarizes the
+.I groff
+font names used to access them.
+.
+.
+.P
+.TS
+tab(|) allbox center;
+Cb Cb Cb Cb Cb
+L L L L L
+.
+Typeface | Roman | Bold | Italic | Bold-Italic
+Dutch | TR | TB | TI | TBI
+Swiss | HR | HB | HI | HBI
+Swiss Narrow | HNR | HNB | HNI | HNBI
+Courier | CR | CB | CI |
+Elite | ER | EB | EI |
+.TE
+.
+.
+.\" ====================================================================
+.SS "Paper format, orientation, and device description file"
+.\" ====================================================================
+.
+.I grolbp
+supports paper formats
+.RB \[lq] A4 \[rq],
+.RB \[lq] letter \[rq],
+.RB \[lq] legal \[rq],
+and
+.RB \[lq] executive \[rq].
+.
+These are matched case-insensitively.
+.
+The
+.BR \-p ,
+.B \-\-papersize
+option overrides any setting in the device description file
+.IR DESC .
+.
+If neither specifies a paper format,
+A4 is assumed.
+.
+.
+.P
+In its
+.I DESC
+file,
+.I grolbp
+(case-insensitively) recognizes an
+.B orientation
+directive accepting one mandatory argument,
+.B portrait
+or
+.BR landscape .
+.
+The first valid orientation directive encountered controls.
+.\" XXX: This is inconsistent with other description file processing.
+.
+The
+.BR \-l ,
+.BR \-o ,
+and
+.B \-\-orientation
+command-line options
+override any setting in
+.IR DESC .
+.
+If none of the foregoing specify the orientation,
+portrait is assumed.
+.
+.
+.\" ====================================================================
+.SS "Font description files"
+.\" ====================================================================
+.
+In addition to the font description file directives documented in
+.MR groff_font @MAN5EXT@ ,
+.I grolbp
+recognizes
+.BR lbpname ,
+which maps the
+.I groff
+font name to the font name used internally by the printer.
+.
+Its syntax is as follows.
+.RS
+.EX
+.RI lbpname\~ printer-font-name
+.EE
+.RE
+.
+.
+.BR lbpname 's
+argument is case-sensitive.
+.
+The printer's font names are encoded as follows.
+.
+.
+.P
+For bitmapped fonts,
+.I printer-font_name
+has the form
+.RS
+.EX
+.RI N\[la] base-font-name \[ra]\[la] font-style \[ra]
+.EE
+.RE
+.I base-font-name
+is the font name as it appears in the printer's font listings without
+the first letter,
+up to
+(but not including)
+the font size.
+.
+.I font-style
+can be one of the letters
+.BR R ,
+.BR I ,
+or
+.BR B ,
+.\" The bold-italic style apparently was not supported for bitmap fonts.
+indicating the roman,
+italic,
+and bold styles,
+respectively.
+.
+For instance,
+if the printer's \[lq]font listing A\[rq]
+shows \[lq]Nelite12I.ISO_USA\[rq],
+the corresponding entry in the
+.I groff
+font description file is
+.RS
+.EX
+lbpname NeliteI
+.EE
+.RE
+.
+You may need to modify
+.I grolbp
+to add support for new bitmapped fonts,
+since the available font names and font sizes of bitmapped fonts
+(as documented above)
+are hard-coded into the program.
+.
+.
+.P
+For scalable fonts,
+.I printer-font-name
+is identical to the font name as it appears in the printer's \[lq]font
+listing A\[rq].
+.
+For instance,
+to select the \[lq]Swiss\[rq] font in bold-italic style,
+which appears in the font listing
+as \%\[lq]Swiss\-BoldOblique\[rq],
+.RS
+.EX
+lbpname Swiss\-BoldOblique
+.EE
+.RE
+is the required directive,
+and this is what we find in the
+.I groff
+font description file
+.I HBI
+for the
+.B lbp
+device.
+.
+.
+.\" ====================================================================
+.SS "Drawing commands"
+.\" ====================================================================
+.
+For compatibility with
+.MR grolj4 @MAN1EXT@ ,
+an additional drawing command is available.
+.
+.
+.TP
+.BI \[rs]D\[aq]R\~ "dh dv" \[aq]
+Draw a rule
+(solid black rectangle)
+with one corner at the drawing position,
+and the diagonally opposite corner at the drawing position
+.RI +( dh , dv ).
+.\" XXX , at which the drawing position will be afterward. ?
+.
+.
+.\" ====================================================================
+.SH Options
+.\" ====================================================================
+.
+.B \-h
+and
+.B \-\-help
+display a usage message,
+while
+.B \-v
+and
+.B \-\-version
+show version information;
+all exit afterward.
+.
+.
+.TP
+.BI \-c " num-copies"
+.TQ
+.BI \-\-copies= num-copies
+Produce
+.I num-copies
+copies of each page.
+.
+.
+.TP
+.BI \-F " font-directory"
+.TQ
+.BI \-\-fontdir= font-directory
+Prepend directory
+.RI font-directory /dev name
+to the search path for font and device description files;
+.I name
+is the name of the device,
+usually
+.BR lbp .
+.
+.
+.TP
+.B \-l
+.TQ
+.B \-\-landscape
+Format the document in landscape orientation.
+.
+.
+.TP
+.BI \-o " orientation"
+.TQ
+.BI \-\-orientation= orientation
+Format the document in the given
+.IR orientation ,
+which must be
+.RB \%\[lq] portrait \[rq]
+or
+.RB \%\[lq] landscape \[rq].
+.
+.
+.TP
+.BI \-p " paper-format"
+.TQ
+.BI \-\-papersize= paper-format
+Set the paper format to
+.IR paper-format ,
+which must be a valid paper format as described above.
+.
+.
+.TP
+.BI \-w " width"
+.TQ
+.BI \-\-linewidth= width
+Set the default line thickness to
+.I width
+thousandths of an em;
+the default is
+.B 40
+(0.04\~em).
+.
+.
+.\" ====================================================================
+.SH Environment
+.\" ====================================================================
+.
+.TP
+.I GROFF_FONT_PATH
+lists directories in which to seek the selected output device's
+directory of device and font description files.
+.
+See
+.MR @g@troff @MAN1EXT@
+and
+.MR groff_font @MAN5EXT@ .
+.
+.
+.\" ====================================================================
+.SH Files
+.\" ====================================================================
+.
+.TP
+.I @FONTDIR@/\:\%devlbp/\:DESC
+describes the
+.B lbp
+output device.
+.
+.
+.TP
+.IR @FONTDIR@/\:\%devlbp/ F
+describes the font known
+.RI as\~ F
+on device
+.BR lbp .
+.
+.
+.TP
+.I @MACRODIR@/\:lbp\:.tmac
+defines macros for use with the
+.B lbp
+output device.
+.
+It is automatically loaded by
+.I troffrc
+when the
+.B lbp
+output device is selected.
+.
+.
+.\" ====================================================================
+.SH "See also"
+.\" ====================================================================
+.
+.MR groff @MAN1EXT@ ,
+.MR @g@troff @MAN1EXT@ ,
+.MR groff_out @MAN5EXT@ ,
+.MR groff_font @MAN5EXT@ ,
+.MR groff_char @MAN7EXT@
+.
+.
+.\" Restore compatibility mode (for, e.g., Solaris 10/11).
+.cp \n[*groff_grolbp_1_man_C]
+.do rr *groff_grolbp_1_man_C
+.
+.
+.\" Local Variables:
+.\" fill-column: 72
+.\" mode: nroff
+.\" End:
+.\" vim: set filetype=groff textwidth=72:
diff --git a/src/devices/grolbp/grolbp.am b/src/devices/grolbp/grolbp.am
new file mode 100644
index 0000000..3ee3a0a
--- /dev/null
+++ b/src/devices/grolbp/grolbp.am
@@ -0,0 +1,36 @@
+# Copyright (C) 2014-2020 Free Software Foundation, Inc.
+#
+# 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+bin_PROGRAMS += grolbp
+grolbp_SOURCES = \
+ src/devices/grolbp/lbp.cpp \
+ src/devices/grolbp/lbp.h \
+ src/devices/grolbp/charset.h
+
+grolbp_LDADD = $(LIBM) \
+ libdriver.a \
+ libgroff.a \
+ lib/libgnu.a
+man1_MANS += src/devices/grolbp/grolbp.1
+EXTRA_DIST += src/devices/grolbp/grolbp.1.man
+
+
+# Local Variables:
+# fill-column: 72
+# mode: makefile-automake
+# End:
+# vim: set autoindent filetype=automake textwidth=72:
diff --git a/src/devices/grolbp/lbp.cpp b/src/devices/grolbp/lbp.cpp
new file mode 100644
index 0000000..35cd54e
--- /dev/null
+++ b/src/devices/grolbp/lbp.cpp
@@ -0,0 +1,738 @@
+/* Copyright (C) 1994-2020 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/*
+TODO
+
+ - Add X command to include bitmaps
+*/
+
+#include <assert.h>
+
+#include "driver.h"
+#include "lbp.h"
+#include "charset.h"
+#include "paper.h"
+
+#include "nonposix.h"
+
+extern "C" const char *Version_string;
+
+static int user_papersize = -1;
+static int orientation = -1;
+
+// custom paper format
+static double user_paperlength = 0;
+static double user_paperwidth = 0;
+
+static int ncopies = 1;
+
+#define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em
+static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR;
+
+static int set_papersize(const char *paperformat);
+
+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(int, double, double);
+ ~lbp_printer();
+ void set_char(glyph *, 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,const environment *env);
+ 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;
+ int req_linethickness; // requested line thickness
+ // custom paper format
+ int papersize;
+ int paperlength;
+ int paperwidth;
+};
+
+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 recognize bitmapped fonts by the first character of its name
+ if (arg[0] == 'N')
+ this->is_scalable = 0;
+ // fprintf(stderr, "Loading font \"%s\" \n", arg);
+ }
+ // fprintf(stderr, "Loading font %s \"%s\" in %s at %d\n",
+ // command, arg, filename, lineno);
+}
+
+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(int ps, double pw, double pl)
+: fill_pattern(1),
+ fill_mode(0),
+ cur_hpos(-1),
+ cur_font(0),
+ cur_size(0),
+ cur_symbol_set(0),
+ req_linethickness(-1)
+{
+ SET_BINARY(fileno(stdout));
+ 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 format handling
+ if (orientation < 0)
+ orientation = 0; // Default orientation is portrait
+ papersize = 14; // Default paper format is A4
+ if (font::papersize) {
+ papersize = set_papersize(font::papersize);
+ paperlength = font::paperlength;
+ paperwidth = font::paperwidth;
+ }
+ if (ps >= 0) {
+ papersize = ps;
+ paperlength = int(pl * font::res + 0.5);
+ paperwidth = int(pw * font::res + 0.5);
+ }
+ 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<");
+}
+
+inline void lbp_printer::set_line_thickness(int size,const environment *env)
+{
+ if (size == 0)
+ line_thickness = 1;
+ else {
+ if (size < 0)
+ // line_thickness =
+ // (env->size * (font::res/72)) * (linewidth_factor/1000)
+ // we ought to check for overflow
+ line_thickness =
+ env->size * linewidth_factor * font::res / 72000;
+ else // size > 0
+ line_thickness = size;
+ } // else from if (size == 0)
+ if (line_thickness < 1)
+ line_thickness = 1;
+ if (vdminited())
+ vdmlinewidth(line_thickness);
+ req_linethickness = size; // an size requested
+ /* fprintf(stderr, "thickness: %d == %d, size %d, %d \n",
+ size, line_thickness, env->size,req_linethickness); */
+ return;
+} // lbp_printer::set_line_thickness
+
+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.
+ int cpi; // The font size in characters per inch
+ // (bitmapped 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 available 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 are only two bitmapped fonts shipped with the printer.
+ if (!strcasecmp(nam, "courier")) {
+ // Courier font
+ if (siz >= 12)
+ cpi = 10;
+ else cpi = 17;
+ }
+ if (!strcasecmp(nam, "elite")) {
+ 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;
+}
+
+void lbp_printer::set_char(glyph *g, font *f, const environment *env,
+ int w, const char *)
+{
+ int code = f->get_code(g);
+ 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 * font::res) / 72));
+ }
+ else
+ // bitmapped font
+ lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size));
+ lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
+ cur_font = psf;
+ cur_symbol_set = 0;
+ // Update the line thickness if needed
+ if ((req_linethickness < 0 ) && (env->size != cur_size))
+ set_line_thickness(req_linethickness,env);
+ cur_size = env->size;
+ }
+ 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 * font::res) / 72));
+ 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 * font::res) / 72));
+ lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
+ break;
+ case 4:
+ lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
+ 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 * font::res) / 72));
+ cur_size = env->size;
+ // Update the line thickness if needed
+ if (req_linethickness < 0 )
+ set_line_thickness(req_linethickness,env);
+ }
+ 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("Opening temporary 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);
+ /* let's 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;
+}
+
+inline void lbp_printer::setfillmode(int mode)
+{
+ if (mode != fill_mode) {
+ if (mode != 1)
+ vdmsetfillmode(mode, 1, 0);
+ else
+ // To get black, we must use white inverted.
+ 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;
+ // fprintf(stderr, "Polygon (%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)
+{
+ if ((req_linethickness < 0 ) && (env->size != cur_size))
+ set_line_thickness(req_linethickness,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;
+ }
+ set_line_thickness(p[0],env);
+ }
+ 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] == 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;
+ }
+ break;
+ case 'F':
+ // not implemented yet
+ 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(user_papersize, user_paperwidth, user_paperlength);
+}
+
+static struct {
+ const char *name;
+ int code;
+} lbp_papersizes[] =
+ {{ "A4", 14 },
+ { "letter", 30 },
+ { "legal", 32 },
+ { "executive", 40 },
+ };
+
+static int set_papersize(const char *paperformat)
+{
+ unsigned int i;
+ // First, test for a standard (i.e. supported directly by the printer)
+ // paper format.
+ for (i = 0 ; i < sizeof(lbp_papersizes) / sizeof(lbp_papersizes[0]); i++)
+ {
+ if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0)
+ return lbp_papersizes[i].code;
+ }
+ // Otherwise, we assume a custom paper format.
+ return 82; // XXX: magic number
+}
+
+static void handle_unknown_desc_command(const char *command, const char *arg,
+ const char *filename, int lineno)
+{
+ // 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,
+ "'orientation' 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,
+ "invalid argument to 'orientation' command");
+ }
+ }
+ }
+}
+
+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' },
+ { "linewidth", required_argument, NULL, 'w' },
+ { "fontdir", required_argument, NULL, 'F' },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, 0, 0 }
+};
+
+static void usage(FILE *stream)
+{
+ fprintf(stream,
+"usage: %s [-l] [-c num-copies] [-F font-directory] [-o orientation]"
+" [-p paper-format] [-w width] [file ...]\n"
+"usage: %s {-v | --version}\n"
+"usage: %s {-h | --help}\n",
+ program_name, program_name, program_name);
+ if (stdout == stream) {
+ fputs(
+"\n"
+"Translate the output of troff(1) into a CaPSL and VDM format suitable"
+"\n"
+"for Canon LBP-4 and LBP-8 printers. See the grolbp(1) manual page.\n",
+ stream);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (program_name == NULL)
+ program_name = strsave(argv[0]);
+ font::set_unknown_desc_command_handler(handle_unknown_desc_command);
+ // command line parsing
+ int c;
+ int option_index = 0;
+ while ((c = getopt_long(argc, argv, "c:F:hI:lo:p:vw:", long_options,
+ &option_index))
+ != EOF) {
+ switch (c) {
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case 'I':
+ // ignore include path arguments
+ break;
+ case 'p':
+ {
+ const char *s;
+ if (!font::scan_papersize(optarg, &s,
+ &user_paperlength, &user_paperwidth))
+ error("ignoring invalid paper format '%1'", optarg);
+ else
+ user_papersize = set_papersize(s);
+ break;
+ }
+ case 'l':
+ orientation = 1;
+ break;
+ case 'v':
+ printf("GNU grolbp (groff) version %s\n", Version_string);
+ exit(EXIT_SUCCESS);
+ 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 'w':
+ {
+ char *ptr;
+ long n = strtol(optarg, &ptr, 10);
+ if (n == 0 && ptr == optarg)
+ error("argument for -w must be a non-negative integer");
+ else if (n < 0 || n > INT_MAX)
+ error("out of range argument for -w");
+ else
+ linewidth_factor = int(n);
+ break;
+ }
+ case 'h':
+ usage(stdout);
+ break;
+ case '?':
+ usage(stderr);
+ exit(EXIT_FAILURE);
+ break;
+ default:
+ assert(0 == "unhandled getopt_long return value");
+ }
+ }
+ if (optind >= argc)
+ do_file("-");
+ while (optind < argc)
+ do_file(argv[optind++]);
+ if (lbpoutput)
+ lbpputs("\033c\033<");
+ return 0;
+}
+
+// Local Variables:
+// fill-column: 72
+// mode: C++
+// End:
+// vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
diff --git a/src/devices/grolbp/lbp.h b/src/devices/grolbp/lbp.h
new file mode 100644
index 0000000..ee1c7b9
--- /dev/null
+++ b/src/devices/grolbp/lbp.h
@@ -0,0 +1,544 @@
+// -*- C -*-
+/* Copyright (C) 1994-2020 Free Software Foundation, Inc.
+ Written by Francisco Andrés Verdú <pandres@dragonet.es>
+
+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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This file contains a set of utility functions to use canon CaPSL printers
+ * (lbp-4 and lbp-8 series printers) */
+
+#ifndef LBP_H
+#define LBP_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+static FILE *lbpoutput = NULL;
+static FILE *vdmoutput = NULL;
+
+
+static inline void
+lbpinit(FILE *outfile)
+{
+ lbpoutput = outfile;
+}
+
+
+static void
+lbpprintf(const char *format, ... )
+{ /* Taken from cjet */
+ va_list stuff;
+
+ va_start(stuff, format);
+ vfprintf(lbpoutput, format, stuff);
+ va_end(stuff);
+}
+
+
+static inline void
+lbpputs(const char *data)
+{
+ fputs(data,lbpoutput);
+}
+
+
+static inline void
+lbpputc(unsigned char c)
+{
+ fputc(c,lbpoutput);
+}
+
+
+static inline void
+lbpsavestatus(int idx )
+{
+ fprintf(lbpoutput,"\033[%d%%y",idx);
+}
+
+
+static inline void
+lbprestorestatus(int idx )
+{
+ fprintf(lbpoutput,"\033[%d%cz",idx ,'%');
+}
+
+
+static inline void
+lbpsavepos(int idx)
+{
+ fprintf(lbpoutput,"\033[1;%d;0x",idx);
+}
+
+
+static inline void
+lbprestorepos(int idx)
+{
+ fprintf(lbpoutput,"\033[0;%d;0x",idx);
+}
+
+
+static inline void
+lbprestoreposx(int idx)
+{
+ fprintf(lbpoutput,"\033[0;%d;1x",idx);
+}
+
+
+static inline void
+lbpmoverel(int despl, char direction)
+{
+ fprintf(lbpoutput,"\033[%d%c",despl,direction);
+}
+
+
+static inline void
+lbplinerel(int width,int despl,char direction )
+{
+ fprintf(lbpoutput,"\033[%d;0;9{\033[%d%c\033[9}",width,despl,direction);
+}
+
+
+static inline void
+lbpmoveabs(int x, int y)
+{
+ fprintf(lbpoutput,"\033[%d;%df",y,x);
+}
+
+
+static inline void
+lbplineto(int x,int y, int width )
+{
+ fprintf(lbpoutput,"\033[%d;0;9{",width);
+ lbpmoveabs(x,y);
+ fprintf(lbpoutput,"\033[9}\n");
+}
+
+
+static inline void
+lbpruleabs(int x, int y, int hsize, int vsize)
+{
+ lbpmoveabs(x,y);
+ fprintf(lbpoutput,"\033[0;9;000s");
+ lbpmoveabs(x+hsize,y+vsize);
+ fprintf(lbpoutput,"\033[9r");
+}
+
+
+static void vdmprintf(const char *format, ... );
+
+
+static inline char *
+vdmnum(int num,char *result)
+{
+ char b1,b2,b3;
+ char *p = result;
+ int nm;
+
+ nm = abs(num);
+ /* First byte 1024 - 32768 */
+ b1 = ((nm >> 10) & 0x3F);
+ if (b1) *p++ = b1 | 0x40;
+
+ /* Second Byte 16 - 1024 */
+ b2 = ((nm >> 4) & 0x3F);
+ if ( b1 || b2) *p++= b2 | 0x40;
+
+ /* Third byte 0 - 15 */
+ b3 = ((nm & 0x0F) | 32);
+ if (num >= 0) b3 |= 16;
+ *p++ = b3;
+ *p = 0x00; /* End of the resulting string */
+ return result;
+}
+
+
+static inline void
+vdmorigin(int newx, int newy)
+{
+ char nx[4],ny[4];
+
+ vdmprintf("}\"%s%s\x1e",vdmnum(newx,nx),vdmnum(newy,ny));
+}
+
+
+static inline FILE *
+vdminit(FILE *vdmfile)
+{
+ char scale[4],size[4],lineend[4];
+
+/* vdmoutput = tmpfile();*/
+ vdmoutput = vdmfile;
+ /* Initialize the VDM mode */
+ vdmprintf("\033[0&}#GROLBP\x1e!0%s%s\x1e$\x1e}F%s\x1e",\
+ vdmnum(-3,scale),vdmnum(1,size),vdmnum(1,lineend));
+ return vdmoutput;
+
+}
+
+
+static inline void
+vdmend()
+{
+ vdmprintf("}p\x1e");
+}
+
+
+static void
+vdmprintf(const char *format, ... )
+{ /* Taken from cjet */
+ va_list stuff;
+
+ if (vdmoutput == NULL) vdminit(tmpfile());
+ va_start(stuff, format);
+ vfprintf(vdmoutput, format, stuff);
+ va_end(stuff);
+}
+
+
+static inline void
+vdmsetfillmode(int pattern,int perimeter, int inverted)
+{
+ char patt[4],perim[4],
+ rot[4], /* rotation */
+ espejo[4], /* espejo */
+ inv[4]; /* Inverted */
+
+ vdmprintf("I%s%s%s%s%s\x1e",vdmnum(pattern,patt),\
+ vdmnum(perimeter,perim),vdmnum(0,rot),
+ vdmnum(0,espejo),vdmnum(inverted,inv));
+}
+
+
+static inline void
+vdmcircle(int centerx, int centery, int radius)
+{
+ char x[4],y[4],rad[4];
+
+ vdmprintf("5%s%s%s\x1e",vdmnum(centerx,x),vdmnum(centery,y),\
+ vdmnum(radius,rad));
+}
+
+
+static inline void
+vdmaarc(int centerx, int centery, int radius,int startangle,int angle,int style,int arcopen)
+{
+ char x[4],y[4],rad[4],stx[4],sty[4],styl[4],op[4];
+
+ vdmprintf("}6%s%s%s%s%s%s%s\x1e",vdmnum(arcopen,op),\
+ vdmnum(centerx,x),vdmnum(centery,y),\
+ vdmnum(radius,rad),vdmnum(startangle,stx),vdmnum(angle,sty),\
+ vdmnum(style,styl));
+}
+
+
+static inline void
+vdmvarc(int centerx, int centery,int radius, int startx, int starty, int endx, int endy,\
+ int style,int arcopen)
+{
+ char x[4],y[4],rad[4],stx[4],sty[4],enx[4],eny[4],styl[4],op[4];
+
+ vdmprintf("}6%s%s%s%s%s%s%s%s%s\x1e",vdmnum(arcopen,op),\
+ vdmnum(centerx,x),vdmnum(centery,y),\
+ vdmnum(radius,rad),vdmnum(startx,stx),vdmnum(starty,sty),\
+ vdmnum(endx,enx),vdmnum(endy,eny),vdmnum(style,styl));
+}
+
+
+static inline void
+vdmellipse(int centerx, int centery, int radiusx, int radiusy,int rotation)
+{
+ char x[4],y[4],radx[4],rady[4],rotat[4];
+
+ vdmprintf("}7%s%s%s%s%s\x1e\n",vdmnum(centerx,x),vdmnum(centery,y),\
+ vdmnum(radiusx,radx),vdmnum(radiusy,rady),\
+ vdmnum(rotation,rotat));
+}
+
+
+static inline void
+vdmsetlinetype(int lintype)
+{
+ char ltyp[4], expfact[4];
+
+ vdmprintf("E1%s%s\x1e",vdmnum(lintype,ltyp),vdmnum(1,expfact));
+
+}
+
+
+static inline void
+vdmsetlinestyle(int lintype, int pattern,int unionstyle)
+{
+ char patt[4],ltip[4],
+ rot[4], /* rotation */
+ espejo[4], /* espejo */
+ in[4]; /* Inverted */
+
+ vdmprintf("}G%s%s%s%s%s\x1e",vdmnum(lintype,ltip),\
+ vdmnum(pattern,patt),vdmnum(0,rot),
+ vdmnum(0,espejo),vdmnum(0,in));
+ vdmprintf("}F%s",vdmnum(unionstyle,rot));
+}
+
+
+static inline void
+vdmlinewidth(int width)
+{
+ char wh[4];
+
+ vdmprintf("F1%s\x1e",vdmnum(width,wh));
+}
+
+
+static inline void
+vdmrectangle(int origx, int origy,int dstx, int dsty)
+{
+ char xcoord[4],ycoord[4],sdstx[4],sdsty[4];
+
+ vdmprintf("}:%s%s%s%s\x1e\n",vdmnum(origx,xcoord),vdmnum(dstx,sdstx),\
+ vdmnum(origy,ycoord),vdmnum(dsty,sdsty));
+}
+
+
+static inline void
+vdmpolyline(int numpoints, int *points)
+{
+ int i,*p = points;
+ char xcoord[4],ycoord[4];
+
+ if (numpoints < 2) return;
+ vdmprintf("1%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord));
+ p += 2;
+ for (i = 1; i < numpoints ; i++) {
+ vdmprintf("%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord));
+ p += 2;
+ } /* for */
+ vdmprintf("\x1e\n");
+}
+
+
+static inline void
+vdmpolygon(int numpoints, int *points)
+{
+ int i,*p = points;
+ char xcoord[4],ycoord[4];
+
+ if (numpoints < 2) return;
+ vdmprintf("2%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord));
+ p += 2;
+ for (i = 1; i < numpoints ; i++) {
+ vdmprintf("%s%s",vdmnum(*p,xcoord),vdmnum(*(p+1),ycoord));
+ p += 2;
+ } /* for */
+ vdmprintf("\x1e\n");
+
+}
+
+
+/************************************************************************
+ * Higher level auxiliary functions *
+ ************************************************************************/
+static inline int
+vdminited()
+{
+ return (vdmoutput != NULL);
+}
+
+
+static inline void
+vdmline(int startx, int starty, int sizex, int sizey)
+{
+ int points[4];
+
+ points[0] = startx;
+ points[1] = starty;
+ points[2] = sizex;
+ points[3] = sizey;
+
+ vdmpolyline(2,points);
+
+}
+
+
+/*#define THRESHOLD .05 */ /* inch */
+#define THRESHOLD 1 /* points (1/300 inch) */
+static inline void
+splinerel(double px,double py,int flush)
+{
+ static int lx = 0 ,ly = 0;
+ static double pend = 0.0;
+ static int dy = 0, despx = 0, despy = 0, sigpend = 0;
+ int dxnew = 0, dynew = 0, sg;
+ char xcoord[4],ycoord[4];
+ double npend ;
+
+ if (flush == -1) {lx = (int)px; ly = (int)py; return;}
+
+ if (flush == 0) {
+ dxnew = (int)px -lx;
+ dynew = (int)py -ly;
+ if ((dxnew == 0) && (dynew == 0)) return;
+ sg = (dxnew < 0)? -1 : 0;
+/* fprintf(stderr,"s (%d,%d) (%d,%d)\n",dxnew,dynew,despx,despy);*/
+ if (dynew == 0) {
+ despx = dxnew;
+ if ((sg == sigpend) && (dy == 0)){
+ return;
+ }
+ dy = 0;
+ }
+ else {
+ dy = 1;
+ npend = (1.0*dxnew)/dynew;
+ if (( npend == pend) && (sigpend == sg))
+ { despy = dynew; despx = dxnew; return; }
+ else
+ { sigpend = sg;
+ pend = npend;
+ } /* else (( npend == pend) && ... */
+ } /* else (if (dynew == 0)) */
+ } /* if (!flush ) */
+
+ /* if we've changed direction we must draw the line */
+/* fprintf(stderr," (%d) %.2f,%.2f\n",flush,(float)px,(float)py);*/
+ if ((despx != 0) || (despy != 0)) vdmprintf("%s%s",vdmnum(despx,xcoord),\
+ vdmnum(despy,ycoord));
+ /*if ((despx != 0) || (despy != 0)) fprintf(stderr,"2
+ *%d,%d\n",despx,despy);*/
+ if (flush) {
+ dxnew = dy = despx = despy = 0;
+ return;
+ } /* if (flush) */
+ dxnew -= despx;
+ dynew -= despy;
+ if ((dxnew != 0) || (dynew != 0)) vdmprintf("%s%s",vdmnum(dxnew,xcoord),\
+ vdmnum(dynew,ycoord));
+
+/* if ((dxnew != 0) || (dynew != 0)) fprintf(stderr,"3
+ * %d,%d\n",dxnew,dynew);*/
+ lx = (int)px; ly = (int)py;
+ dxnew = dy = despx = despy = 0;
+
+}
+
+
+/**********************************************************************
+ * The following code to draw splines is adapted from the transfig package
+ */
+static void
+quadratic_spline(double a_1, double b_1, double a_2, double b_2, \
+ double a_3, double b_3, double a_4, double b_4)
+{
+ double x_1, y_1, x_4, y_4;
+ double x_mid, y_mid;
+
+ x_1 = a_1; y_1 = b_1;
+ x_4 = a_4; y_4 = b_4;
+ x_mid = (a_2 + a_3)/2.0;
+ y_mid = (b_2 + b_3)/2.0;
+ if ((fabs(x_1 - x_mid) < THRESHOLD)
+ && (fabs(y_1 - y_mid) < THRESHOLD)) {
+ splinerel(x_mid, y_mid, 0);
+/* fprintf(tfp, "PA%.4f,%.4f;\n", x_mid, y_mid);*/
+ }
+ else {
+ quadratic_spline(x_1, y_1, ((x_1+a_2)/2.0), ((y_1+b_2)/2.0),
+ ((3.0*a_2+a_3)/4.0), ((3.0*b_2+b_3)/4.0), x_mid, y_mid);
+ }
+
+ if ((fabs(x_mid - x_4) < THRESHOLD)
+ && (fabs(y_mid - y_4) < THRESHOLD)) {
+ splinerel(x_4, y_4, 0);
+/* fprintf(tfp, "PA%.4f,%.4f;\n", x_4, y_4);*/
+ }
+ else {
+ quadratic_spline(x_mid, y_mid,
+ ((a_2+3.0*a_3)/4.0), ((b_2+3.0*b_3)/4.0),
+ ((a_3+x_4)/2.0), ((b_3+y_4)/2.0), x_4, y_4);
+ }
+}
+
+
+#define XCOORD(i) numbers[(2*i)]
+#define YCOORD(i) numbers[(2*i)+1]
+static void
+vdmspline(int numpoints, int o_x, int o_y, int *numbers)
+{
+ double cx_1, cy_1, cx_2, cy_2, cx_3, cy_3, cx_4, cy_4;
+ double x_1, y_1, x_2, y_2;
+ char xcoord[4],ycoord[4];
+ int i;
+
+ /*p = s->points;
+ x_1 = p->x/ppi;*/
+ x_1 = o_x;
+ y_1 = o_y;
+/* p = p->next;
+ x_2 = p->x/ppi;
+ y_2 = p->y/ppi;*/
+ x_2 = o_x + XCOORD(0);
+ y_2 = o_y + YCOORD(0);
+ cx_1 = (x_1 + x_2)/2.0;
+ cy_1 = (y_1 + y_2)/2.0;
+ cx_2 = (x_1 + 3.0*x_2)/4.0;
+ cy_2 = (y_1 + 3.0*y_2)/4.0;
+
+/* fprintf(stderr,"Spline %d (%d,%d)\n",numpoints,(int)x_1,(int)y_1);*/
+ vdmprintf("1%s%s",vdmnum((int)x_1,xcoord),vdmnum((int)y_1,ycoord));
+ splinerel(x_1,y_1,-1);
+ splinerel(cx_1,cy_1,0);
+/* fprintf(tfp, "PA%.4f,%.4f;PD%.4f,%.4f;\n",
+ x_1, y_1, cx_1, cy_1);*/
+
+ /*for (p = p->next; p != NULL; p = p->next) {*/
+ for (i = 1; i < (numpoints); i++) {
+ x_1 = x_2;
+ y_1 = y_2;
+/* x_2 = p->x/ppi;
+ y_2 = p->y/ppi;*/
+ x_2 = x_1 + XCOORD(i);
+ y_2 = y_1 + YCOORD(i);
+ cx_3 = (3.0*x_1 + x_2)/4.0;
+ cy_3 = (3.0*y_1 + y_2)/4.0;
+ cx_4 = (x_1 + x_2)/2.0;
+ cy_4 = (y_1 + y_2)/2.0;
+ /* fprintf(stderr,"Point (%d,%d) - (%d,%d)\n",(int)x_1,(int)(y_1),(int)x_2,(int)y_2);*/
+ quadratic_spline(cx_1, cy_1, cx_2, cy_2, cx_3, cy_3, cx_4, cy_4);
+ cx_1 = cx_4;
+ cy_1 = cy_4;
+ cx_2 = (x_1 + 3.0*x_2)/4.0;
+ cy_2 = (y_1 + 3.0*y_2)/4.0;
+ }
+ x_1 = x_2;
+ y_1 = y_2;
+/* p = s->points->next;
+ x_2 = p->x/ppi;
+ y_2 = p->y/ppi;*/
+ x_2 = o_x + XCOORD(0);
+ y_2 = o_y + YCOORD(0);
+ cx_3 = (3.0*x_1 + x_2)/4.0;
+ cy_3 = (3.0*y_1 + y_2)/4.0;
+ cx_4 = (x_1 + x_2)/2.0;
+ cy_4 = (y_1 + y_2)/2.0;
+ splinerel(x_1, y_1, 0);
+ splinerel(x_1, y_1, 1);
+ /*vdmprintf("%s%s",vdmnum((int)(x_1-lx),xcoord),\
+ vdmnum((int)(y_1-ly),ycoord));*/
+ vdmprintf("\x1e\n");
+/* fprintf(tfp, "PA%.4f,%.4f;PU;\n", x_1, y_1);*/
+
+
+}
+
+
+#endif