diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/postscript |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/postscript')
217 files changed, 38659 insertions, 0 deletions
diff --git a/sys/src/cmd/postscript/NOTES b/sys/src/cmd/postscript/NOTES new file mode 100755 index 000000000..fb673ce01 --- /dev/null +++ b/sys/src/cmd/postscript/NOTES @@ -0,0 +1,32 @@ + Directory dpost is DWB 3.3 version without UTF changes. dpost.utf is + stuff for Plan 9. Both build and install dpost, so only pick one. The + makefile I sent (postscript.mk) builds dpost.utf. + + Left READING set to ONEBYTE in common/gen.h. Expect dpost errors unless + 'x E UTF' is added to troff output or READING set to UTFENCODING. Easy + to make 'x E UTF' anything else too. + + Left RUNELIB defined in common/rune.h so rune.c stuff is used when + dpost.utf is built. + + UTF.enc is in directory psencoding. Install and link to Default.enc on + Plan 9. + + Carmela requested two new characters: \(bs for backslash and \(dq for + double quote. Both are in devLatin1 and devpost tables. Carmela also + asked for a bunch of her devpost accent characters in devLatin1. Added + them to the end of the devLatin1 tables. + + A word of warning about devLatin1. Carmela, Peter and others complained + about - and hyphens being too long in the Latin1 fonts. I used Abode's + choice but nobody liked it. New devLatin1 tables use a smaller character + for hy. Looks better (I guess) but a width change affects line and page + breaks!! Not sure what you want to do. Complaints on this one go to + npn and carmela!!! + + Didn't take your suggested pathname change in download. Didn't want to + risk breaking Unix 4.0 lp. What's there is bogus but was only for Unix + 4.0. The -r option accomplishes something similiar but needs a full path. + + postio.mk is very different and not tested on V9. + diff --git a/sys/src/cmd/postscript/README b/sys/src/cmd/postscript/README new file mode 100755 index 000000000..7deebb02d --- /dev/null +++ b/sys/src/cmd/postscript/README @@ -0,0 +1,179 @@ +Stuff appears to work, but it's obviously not well tested. I fully +expect several iterations before things are correct!! Make sure you +can back this out quickly. + +This code supports UTF encoding. Directory dpost.utf is a version that +reads UTF encoded files. Directory dpost is DWB 3.3 source and should be +close to what you're currently using. Main source code changes were in +dpost.utf (files font.h, font.c, and dpost.c). Select either dpost or +dpost.utf in TARGETS in postscript.mk. Both build and install a program +called dpost!! + +dpost.utf is more general and includes code that lets it read either +format. Only catch is troff must tell it (with x E UTF) that the file +is UTF and troff currently doesn't output encoding info, so you're +stuck with two post-processors! + +Added common/rune.h and common/rune.c so code can be compiled elsewere. +Both files are only used by dpost. Remove RUNELIB in commmon/rune.h if +fullrune(), chartorune(), and runetochar() are available on your system. +You will also need to set READING in common/gen.h. It controls how dpost +(from dpost.utf) reads troff output. It should be UTFENCODING on Plan 9 +and ONEBYTE elsewhere. If troff includes encoding hint (x E UTF) then +READING selects the default which sould be ONEBYTE. + +Leave WRITING (in common/gen.h) set to ONEBYTE. It only controls dpost +output and dpost (right now) does not work 100% with UTF.enc. Fix should +be easy, but I don't have time now. + +Other translators passed bytes through so only needed slightly modified +proglogues and a new encoding scheme (psencoding/UTF.enc). It works for +Latin1, but still needs a bit more attention. Prologue changes were easy +and only involved adding lines like, + + /show {show} bind def + /stringwidth {stringwidth} bind def + +Guarantees text procedures used in prologues aren't operators and can be +successfully redefined in UTF.enc. Unbinding means a small but probably +not noticeable speed penalty. You may not want to include those changes +on other system. + +------------- +Major Changes +------------- + +See the VERSION file. + +------------------- +Tuning The Makefile +------------------- + +Source files, man pages, and low level makefiles can all be updated +to reflect settings in postscript.mk in one simple step (described +later). In most cases you only need to edit file postscript.mk. + +First save a copy of file postscript.mk. Then adjust the following +definitions in file postscript.mk: + + SYSTEM best match for your version of Unix. Current choices for + SYSTEM are: + + SYSV - System V + V9 - Ninth Edition + BSD4_2 - Berkeley (eg. Sun) + + Controls conditional compilation in a few places. + + GROUP group assigned to all installed files + + OWNER owner of everything that's installed + + BINDIR dpost and picpack go here. All other programs go in POSTBIN. + BINDIR must already exist - it will not be created during an + install. + + HOSTDIR hostresident font directory for PostScript printers. Only + used in the font download program. + + FONTDIR width table directory - for troff and most postprocessors + + MAN1DIR command manpages. A command and its manpage are installed + together - there's no easy way to avoid it. Setting MAN1DIR + to an existing temporary directory (e.g. /tmp) means an + install will work but manpages won't go anywhere permanent. + MAN1DIR must already exist - it will not be created during + an install. + + POSTBIN where most PostScript support programs go. dpost and picpack + the exceptions. + + POSTLIB prologues and miscellaneous PostScript files. Primarily for + the programs that live in POSTBIN. + + CFLGS common compiler options - used to build CFLAGS in the low + level makefiles. CLFGS and LDFLGS are best set on the make + command line. + + LDFLGS common link editor options - used to build LDFLAGS in the + low level makefiles. LDFLGS and CFLGS are best set on the + make command line. + + DKHOST set it to TRUE to compile the DKHOST Datakit support code + in postio. Temporarily resets SYSTEM to SYSV if DKHOST is + TRUE and SYSTEM is BSD4_2. Ignored if SYSTEM is not SYSV + or BSD4_2. + + DKSTREAMS enables streams based DKHOST support in postio when DKHOST + is TRUE and SYSTEM is SYSV or BSD4_2. Choices are TRUE, + FALSE, or a stream module name (e.g. dknetty or dkty). TRUE + selects dknetty. Newer systems may expect dkty. + + ROUNDPAGE must only be set to TRUE or FALSE. TRUE means PostScript + translators include code that maps clipping path dimensions + into known paper sizes. + + TARGETS the default list of what's built by make. Each target must + be the name of a source directory. A target that names a + non-existent source directory is ignored. Setting TARGETS + on the make command line overrides the default list. + +------------------- +Updating The Source +------------------- + +Whenever file postscript.mk changes you should update source files, +man pages, and low level makefiles by typing, + + make -f postscript.mk changes + +------------------------ +More System Dependencies +------------------------ + +The package has been compiled and tested on System V and Ninth Edition +Unix Systems and on Sun workstations. Most differences are handled via +the SYSTEM definition in postscript.mk. Problems that remain are: + + SYSV - System V + Use the native compiler if you're on an internal System V UTS + machine. + + V9 - Ninth or Tenth Edition + chown is in /etc and chgrp no longer exists - it's been folded into + the chown command. You may be forced to build a simple chgrp shell + script (put it in your bin) that calls chown. If you're not superuser + set OWNER to your login name and GROUP to your group id. + + BSD4_2 - Sun Workstations + Use the Bourne shell. chown is should be in /usr/etc. Add /usr/etc + to your PATH and export PATH. If you're not superuser set OWNER to + your login name and GROUP to your group id. + +---------------------- +Installing The Package +---------------------- + +To build (but not install) the default package (i.e. everything named by +TARGETS in postscript.mk) type, + + make -f postscript.mk all + +To build and install the package type, + + make -f postscript.mk all install + +After the package is installed use, + + make -f postscript.mk clobber + +to delete binary files and compiled programs from the source directories. + +To select part of the package define TARGETS on the command line. For +example, + + make -f postscript.mk TARGETS="dpost devpost" all install + +builds and installs dpost and the PostScript font tables. Quotes hide +white space from the shell. + diff --git a/sys/src/cmd/postscript/VERSION b/sys/src/cmd/postscript/VERSION new file mode 100755 index 000000000..6fb4722e5 --- /dev/null +++ b/sys/src/cmd/postscript/VERSION @@ -0,0 +1,372 @@ +------------------------ +Version 3.3.2 7/7/92 +------------------------ + + 1: Added UTF support for Plan 9. Only signigficant source code changes were + in dpost.utf (font.h, font.c, dpost.c). Added common/rune.[hc] so code + can be compiled elsewere. Remove RUNELIB in commmon/rune.h if fullrune(), + chartorune(), and runetochar() are available on your system. Original + DWB 3.3 dpost source is in directory dpost. You should select dpost or + dpost.utf in postscript.mk. Both compile and install a program called + dpost so don't pick both! + + 2: dpost can read old or UTF troff output. Default is whatever is assigned + to READING (file common/gen.h). You get one or the other, unless troff + tells dpost what encoding to use (currently x E UTF). + + 3: Most other translators passed bytes through and so only needed slightly + modified proglogues and a new encoding scheme (psencoding/UTF.enc). It + works for Latin1, but still needs a bit more attention. Prologue changes + were easy and only involved adding lines like, + + /show {show} bind def + /stringwidth {stringwidth} bind def + + Guarantees text procedures used in prologues aren't operators and can be + successfully redefined in UTF.enc. Unbinding means a small but probably + not noticeable speed penalty. You may not want to include those changes + on other system. + + 4: Operator redefinitions means dpost should work in it's own dictionary + (rather than userdict). Not implemented yet, but should be easy. Only + potential problem is with picture inclusion when dpost reads UTF.enc. + +------------------------ +Version 3.3.2 5/15/92 +------------------------ + + 1: postio now outputs all unrecognized status reports - primarly for spooler + accounting purposes. + + 2: The makefiles also enable the selection of alternate stream module names + for streams based DKHOST support in postio. + + 3: dpost now assumes the optional fifth token in a font mounting command + (e.g. x font 2 R /usr/me/font/R) is the full pathname of the font. troff + outputs the pathname when a .fp request contains a third argument that + begins with a / as in .fp 1 R /usr/me/font/R. + + 4: By request Latin1's - character has been changed from minus to the smaller + hyphen character. Added \(dq and \(bs (for " and \ characters) to devpost + and devLatin1 tables. Also added \(!! and \(?? to devpost tables. + + 5: Helvetica-Light and Helvetica-LightOblique tables are included as HL and + HK in devpost and devLatin1, even though fonts aren't generally available. + Also copy H to HM during an install of devpost and devLatin1 tables. + + 6: LH is a horizontally arranged color Lucent logo with text which replaces the AT&T logo. + LV is a vertically arranged monochrome AT&T logo with text. + FA is a horizontally arranged monochrome Lucent logo with text (low res.). + L1 is a monochrome AT&T logo, no text. + LA is a monochrome AT&T text. + + 7: Included L1 and LA outlines in devpost and devLatin1. Adjusted LA scaling + so size of "AT&T" matches what's in LV. Original PostScript came + from Matthijs Melchior. + + 8: Included the "symmetric clippath" version of roundpage.ps as Nroundpage.ps + in directory postscript/psfiles. Move it to roundpage.ps if you want it to + be the default. + + 9: Added a few lines of code to dpost for handling current implementation of + the portrait/landscape mode macros. + +10: The man page for download now documents the -r option and notes that -p + is for Unix 4.0 lp. + +------------------------ +Version 3.3.1 4/30/91 +------------------------ + + 1: buildtables stuff has been cleaned up and is now a user level command. + Uses shell.lib files that are installed with font tables. The devpost + tables were built on a version 47.0 PS-810. The devLatin1 tables were + built on a version 51.7 PS-820. + + 2: The devLatin1 tables provide support for the ISO Latin1 alphabet on + PostScript printers. + + 3: All translators support different text font encoding schemes using the + -E option and *.enc files installed in POSTLIB. The ISO Latin 1 alphabet + is supported with file /usr/lib/postscript/Latin1.enc. + + 4: printfont prints a table of the available (encoded) characters in one + or more PostScript fonts. It also understands the -E option. + + 5: grabit and hardcopy are two new programs that may be of interest to the + more serious PostScript programmer. grabit resembles ==, but produces + output that's usally easier to read. hardcopy redirects output from + PostScript file output operators (or procedures) to paper. It's useful + if you don't have direct access to a printer. + + 6: Prologues and programs are stored together. Other common PostScript files + are now in the psfiles directory. + +------------------------ +Verions 3.3 4/16/90 +------------------------ + + 1: The package is now included in DWB. Version numbers are a bit misleading. + The one in postscript.mk refers to the DWB package. + + 2: dpost (and troff) now read ASCII font tables. makedev and the old binary + format are gone. + + 3: The devpost directory came directly from the DWB package. The font tables + originally distributed with this package are in directory devopost. They + are not installed. If possible we recommend you use the devpost tables. + The old tables can be installed by adding devopost to the TARGETS list in + file postscript.mk. + + 4: dpost recognizes two new fields in font tables. Entries for the full + PostScript font look like, + + fontname Times-Roman + + The fontname field is helps manage host resident fonts, the DocumentFonts + comment, and is used to define font name abbreviations like the ones in + dpost.ps. A font table entry that looks like, + + named in prologue + + disables the runtime abbreviation for the font - dpost assumes it's already + in the prologue. + + 5: Extra font tables included in DWB 3.0's devpost font collection are in + directory devpost.add. They included here, but should probably not be + used. + + 6: Bracket building has been fixed and tested on a wide range of PostScript + printers. It will likely still not work on many clones. Real problem + appears to be with Adobe's braceleftbt character. + + 7: Most of the special tuning code for device emulation has been removed. + Emulation still works, but there may be cases where it's not as good as + earlier versions. + + 8: Several problems with color and reverse video printing have been fixed. + + 9: buildtables directory has been cleanup up. The template files in directory + buildtables/devpost.data were used to build the devpost tables. + +10: postplot and download are two new programs. postplot is for the System V + plot package only. Both were written for the Unix 4.0 lp package. + +11: postgif is also relatively new - it came from Chi Choy. + +12: The translators now rotate clockwise when printing in landscape mode. If + you want the old behavior set ROTATION to -1 in postscript.mk. + +13: forms.ps has been cleaned up some. Better behavior when you print 2 + landscape pages on one sheet. + +14: Handling of Datakit code for System V has been changed some. Makefiles + now expect to find libdk.a and dk.h in standard places (e.g /usr/lib and + /usr/include). Set DKHOST to TRUE in postscript.mk to get Datakit support + on System V. + + If you're stuck and need to have things behave as they did in the past + take a look at file postio/postio.mk. Define DKHOSTDIR and uncomment + three lines and the behavior should be close to what it was. + +15: Picture inclusion and color macros are gone. They're included in the DWB + package, and not here. + +------------------------ +Version 3.2 11/27/89 +------------------------ + + 1: Implemented height and slant requests in dpost. + + 2: Modified the behavior of all translators so save objects are no longer left + on the stack. The original implementation was a mistake and occasionally + (e.g. picture inclusion with forms.ps) resulted in invalid restores. + + 3: Fixed the mistake in the external declaration of mesg in postio/slowsend.c. + + 4: The malloc() call in postdmd (routine dimensions()) is only made if patterns + is positive. + + 5: Changed definition of De in draw.ps so savematrix is loaded with the CTM + whenever De is executed. Original implementation didn't work with forms.ps + because the CTM is changed with each page image. (4/29/89) + + 6: Flush stdout when postio is invoked with the -t option - just convenient + not necessary. (4/30/89) + + 7: Included a man page for the picture inclusion macros - file man/mpictures.5. + (5/6/89) + + 8: Added BoundingBox code to dpost - still needs to go in other translators. + Most of the work is done in common/bbox.c. (5/7/89) + + 9: Fiddled with the bracket building stuff in dpost.ps so things finally look + decent. Was particularly bad on the typesetter. + +10: dpost now generates a PageBoundingBox comment and ps_include.c accepts + the comment. Added -B option to enable/disable the BoundingBox calculations. + -Bon to enable and -Boff to disable. On by default now, but that may change. + Add similar code to the rest of the translators (6/20/89). + +11: Fixed ps_include.c so it properly handles %%BeginGlobal and %%EndGlobal. + Added braces and compare page.start to page.end instead of 0. + +12: Added xymove(hpos, vpos) for \X'PS ...' request - near the end of devcntrl(). + Must output position info for following PostScript. + +13: Added a call to endtext() immediately before the oput() call for \N'...' + requests. Without it spacing often messed up with -e2 but not -e0. + +------------------------ +Version 3.1 11/15/88 +------------------------ + + 1: postio can run as one or two processes (-R option) and can establish an + interactive connection with a postscript printer (-i option). Parsing of + status reports has been improved. The status query mechanism can be disabled + using the -q option. An exit status of 1 implies a system error (eg. can't + open the line) while 2 usually means there was an error in the PostScript + file. By default postio runs as a single process. The -B, -R, and -q options + can be used to speed things up some. A version of the program (previously + supplied in postio.tmp) that can help if you seem to be having flow control + problems can be obtained using the -S option. It's not generally recommended + and should only be used as a last resort! + + 2: Several widthshow encoding schemes have been added to dpost and can reduce + print time by 20% or more. The method used to encode lines of text can be + changed on the command line using the -e option. Level 0 produces output + essentially identical to previous versions of dpost. The default can be + changed by modifying the definition of ENCODING in ./Makefile. At present + only level 0 is thoroughly tested, although level 2 (ie. -e2) may be the + default and is undoubtedly worth a try. + + 3: dpost now supports color selection and reverse video. Access in troff is via + the stand-alone macro package ./macros/color. Examples are, + + .so /usr/lib/macros/color + .CL red "this prints in red" + .CL "white on black" "and this prints white text on a black background" + + The postscript procedures that handle color and reverse video can be found + in ./postscript/color.ps. Additional colors can be added to the colordict + dictionary defined in ./postscript/color.ps. + + 4: The dpost drawing routines have been improved and have been moved from the + prologue (ie. ./postscript/dpost.ps) to ./postscript/draw.ps. That file is + only included if needed. Drawing routines now support the ability to group + a series of drawing commands together as a single path. May be useful for + future versions of pic that wish to fill regions with colors or gray levels. + Access is via the new "x X BeginPath" and "x X DrawPath" device control + commands. In addition there's some complicated PostScript code in file + ./postscript/baseline.ps, that can be used to set text along an arbitrary + curve. It's terribly confusing and I doubt anyone will have the patience to + bother to figure it out. + + 5: A simple picture packing troff preprocessor (picpack) has been included and + the code needed to recover pictures and text has been added to dpost. The + program is designed to supplement to the original picture inclusion mechanism, + and should ONLY be used when absolutely necessary. Using dpost to pull picture + files into a document is strongly recommended and will always be the more + efficient and portable approach. picpack simply provides a way to combine + pictures and text in a single file before dpost is executed. It may help in + a distributed printing environment where the user runs everything through + troff while a spooling daemon (eg. lp) handles the postprocessing. There + are serious disadvantages to this approach, with perhaps the most important + being that troff output files (when picpack is used) will likely result in + files that can no longer be reliably passed through other important post- + processors like proof. + + 6: Code to handle host resident PostScript fonts in dpost has been tested and + finally works. The -H option points dpost to a host resident font directory, + which by default is NULL. Host resident font files stored in that directory + must be assigned a name that corresponds to the one or two character troff + font name. Width tables must also be built (see buildtables/README), the new + binary font files must be installed in /usr/lib/font/devpost, and a mapping + definition from troff's name to the PostScript font name must be added to + ./postscript/dpost.ps. + + 7: The default pattern length in postdmd has been reduced to from 10 to 6 bytes. + Printers with fast processors (eg. PS-810s) often benefit from a further + reduction, while optimal performance on slower printers (eg PS-800s) may + require larger pattern sizes. The pattern length can be set using the -b + option. Increasing the pattern size usually increases the size of the output + file. + + 8: Line drawing in posttek and postbgi includes code that automatically ties + lines to device space coordinates when you select a non-zero width. Helps + eliminate the variation in line thickness that many observed. The default + line width in posttek and postbgi is still 0 (which gets 1 pixel). If you + want a different default change the definition of variable linewidth in files + ./postscript/posttek.ps and ./postscript/postbgi.ps. + + 9: Defocused lines in posttek have been fixed. + +10: postbgi now supports color and can be used to translate most PRISM (color + BGI) jobs. Special device specific tuning needed for many PRISM jobs can be + enabled by using the -P"/prism true" option. Missing pieces (eg. subroutines) + needed for translating PRISM jobs, have also been implemented. + +11: postreverse can reverse the pages in documents that conform to Adobe's 1.0 + or 2.0 file structuring conventions, and it works with all the translators in + this package. The new version is backwards compatible, but files produced by + the new translators should not be passed through old versions of postreverse. + The likely result will be no output at all. If you choose to do a partial + installation put the new postreverse up first! + +12: All translators attempt to conform to Adobe's Version 2.0 file structuring + conventions. dpost output falls short, but only in the interest of efficiency. + Passing dpost output through postreverse (perhaps with the -r option) produces + a minimally conforming PostScript file. + +13: All the translators now support three options that pass arbitrary PostScript + through to the output file. The -P and -C options add a string and the + contents of a file respectively immediately after the prologue. It's assumed + whatever is added is legitimate PostScript - there is no checking. In each + case the added PostScript code becomes part of the job's global environment. + + The -R option can be used to request special action (eg. manualfeed) on a + global or page basis. The argument should be "request", "request:page", or + "request:page:file". If page is given as 0 or omitted the request applies + globally. If file is omitted the lookup is in /usr/lib/postscript/ps.requests. + The collection of recognized requests can be modified or extended by changing + /usr/lib/postscript/ps.requests. + +14: PostScript code (from Johnathan Shopiro) that produces bolder versions of the + Courier fonts has been included in file postscript/fatcourier.ps. The file + can be added to individual prologue files (eg. dpost.ps) or pulled in as + needed using the -C option. + +15: postmd is a new program that can be used to display a large matrix as a gray + scale image. May help if you're looking for patterns in a large matrix. A very + optimistic estimate suggests you can display up to a 600x600 matrix (with five + different shades of gray) on 300dpi printer using 8.5x11 inch paper. + +16: What's available in buildtables has been cleaned up and works well with the + new version of postio. It can be used to have PostScript printers build troff + width tables for both printer and host resident fonts. + +17: The PostScript bind operator has been applied to all procedures that are + expected to be executed more than once. Redefined save and restore procedures + are no longer needed and saverestore.ps is not included in this package. + +18: The bizarre PostScript code used to get to the upper left corner of a page + in old versions of dpost.ps and postprint.ps has been replaced by something + that's at least slightly more comprehensible. All prologues have also been + changed so picture inclusion (eg. including a pic picture that's been run + through troff and dpost) should work better than previous versions. Still + missing (from most translators) is the %%BoundingBox comment and even when + it's put out (by postdmd) only the dimensions are correct - sorry! + +19: The careless mistake in the DKHOST section of postio that some noticed belongs + to me (not Allan Buckwalter) and has now been fixed. + +20: By default all prologues still use the current clipping path to determine page + dimensions, but that behavior can be disabled by setting boolean useclippath + (in each prologue) to false. In that case the page dimensions will be taken + from array pagebbox, which by default is initialized to 8x11 inch paper. The + -P options (in each translator) can change useclippth and pagebbox. + +21: New in the misc directory is sample lp support from Maryann Csaszar and a + simple program that converts host resident font files obtained from a Macintosh + to a format that works on Unix. + diff --git a/sys/src/cmd/postscript/buildtables/README b/sys/src/cmd/postscript/buildtables/README new file mode 100755 index 000000000..caf5f3f1e --- /dev/null +++ b/sys/src/cmd/postscript/buildtables/README @@ -0,0 +1,5 @@ +Programs for building troff width tables on a PostScript printer. +Assumes you have direct access to the printer's serial port. Also +needs a special table dependent shell library file to build the +tables (e.g. ../devLatin1/shell.lib). + diff --git a/sys/src/cmd/postscript/buildtables/buildtables.1 b/sys/src/cmd/postscript/buildtables/buildtables.1 new file mode 100755 index 000000000..dd7ce7de9 --- /dev/null +++ b/sys/src/cmd/postscript/buildtables/buildtables.1 @@ -0,0 +1,214 @@ +.ds dF /usr/lib/font +.ds dQ /usr/lib/postscript +.TH BUILDTABLES 1 "DWB 3.2" +.SH NAME +.B buildtables +\- build +.B troff +tables on a PostScript printer +.SH SYNOPSIS +\*(mBbuildtables\f1 +.OP "" options [] +.OP "" "name \(el" [] +.SH DESCRIPTION +.B buildtables +builds font width tables or the typesetter description +file on a PostScript printer. +No arguments means build a default set of tables; +usually a superset of the LaserWriter Plus collection. +The following +.I options +are understood: +.TP 1.0i +.OP \-b speed +Transmit data over +.I line +at baud rate +.I speed. +Recognized baud rates are 1200, 2400, 4800, 9600, and 19200. +The default +.I speed +is 9600 baud. +.TP 1.0i +.OP \-l line +Build the tables on the PostScript printer attached to +.I line. +There is no default. +.TP 1.0i +.OP \-t name +Use +.I name +as the template for fonts not in the default set. +Choose +.MW R +for proportionally spaced fonts and +.MW CW +for fixed width fonts. +Try +.MW ZD +(ZapfDingbats) if the font has a non-standard +character set. +The default is +.MR R . +.TP 1.0i +.OP \-C file +Copy +.I file +into each PostScript table program; +.I file +must contain legitimate PostScript. +.TP 1.0i +.OP \-H hostdir +Use +.I hostdir +as the host-resident font directory. +A file in +.I hostdir +that matches the name of the +.B troff +font is assumed to be a host-resident font program and is included +in the PostScript width table program. +There is no default. +.TP 1.0i +.OP \-S file +Use +.I file +as the shell library file. +Overrides the choice made with the +.OP \-T +option. +.TP 1.0i +.OP \-T name +Set the target device to +.I name. +.br +Device +.I name +means +.ft 2 +.MI \*(dF/dev name /shell.lib +.ft 1 +is the shell library file. +There is no default. +.PP +If +.OP \-l +is omitted output files are the PostScript programs that +build the tables, rather than the tables themselves. +One of +.OP \-T +or +.OP \-S +is required. +If both are given +.OP \-S +wins. +Although +.OP \-H +is the preferred mechanism for including host-resident font files, +.OP \-C +makes sense when only one width table is built. +.PP +The shell library file defines a collection of functions used to +build +.BR troff (1) +tables. +The default set of tables is the list of names returned by the +.MW AllTables +function. +Changes to the default list can be made by updating the +.MW BuiltinTables +function. +.PP +Each +.B buildtables +argument +must be a default table name, or a pair of names enclosed in quotes. +If the argument is a pair, the first name is the +.B troff +font and the second is the full PostScript font name. +Tables are created in the current directory. +Each is assigned a name that matches the +.B troff +table name. +.PP +The PostScript table programs created by +.BR trofftable (1) +are written to files that have +.MW .ps +appended to the +.B troff +table name. +The +.MW .ps +file is deleted after the table is built. +Options not listed above are passed to +.B trofftable. +The PostScript table programs return data to the host computer using +PostScript's +.MW print +operator. +See +.BR hardcopy (1) +if you do not have access to the printer's serial port. +.SH EXAMPLES +.PP +Build the default collection of devpost tables on the printer +connected to +.MW /dev/tty00 +(no font name arguments): +.EX +buildtables -l/dev/tty00 -Tpost +.EE +To do the same and to restrict the tables that are built, +Add +.B troff +font names (or +.MR DESC ) +to restrict the tables built on the printer connected to +.MR /dev/tty00 : +.EX +buildtables -l/dev/tty00 -Tpost R I B BI DESC S +.EE +Enclose the +.B troff +and PostScript font names in quotes to +build the width table for a font not in the default set +(also on the printer connected to +.MR /dev/tty00 ): +.EX +buildtables -l/dev/tty00 -TLatin1 "GL Garamond-Light" +.EE +A font must be available on the printer when the table is built. +Use +.OP \-H +or +.OP \-C +to include host-resident fonts. +.SH WARNINGS +.PP +A width table will not build properly if the printer cannot access +the PostScript font. +.PP +The +.OP \-TLatin1 +option only works on PostScript printers that support the full +.SM ISO +Latin-1 character set. +The error message from older printers will likely indicate a missing +.MW ISOLatin1Encoding +array. +.SH FILES +.MW \*(dF/dev*/shell.lib +.br +.MW \*(dQ/dpost.ps +.br +.MW \*(dQ/trofftable.ps +.br +.SH SEE ALSO +.BR dpost (1), +.BR hardcopy (1), +.BR postio (1), +.BR troff (1), +.BR trofftable (1), +.BR font (5) diff --git a/sys/src/cmd/postscript/buildtables/buildtables.mk b/sys/src/cmd/postscript/buildtables/buildtables.mk new file mode 100755 index 000000000..73c77473b --- /dev/null +++ b/sys/src/cmd/postscript/buildtables/buildtables.mk @@ -0,0 +1,64 @@ +MAKE=/bin/make +MAKEFILE=buildtables.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +FONTDIR=/usr/lib/font +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript +MAN1DIR=/tmp + +all : buildtables + +install : all + @if [ ! -d $(POSTBIN) ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + cp buildtables $(POSTBIN)/buildtables + @chmod 755 $(POSTBIN)/buildtables + @chgrp $(GROUP) $(POSTBIN)/buildtables + @chown $(OWNER) $(POSTBIN)/buildtables + cp buildtables.1 $(MAN1DIR)/buildtables.1 + @chmod 644 $(MAN1DIR)/buildtables.1 + @chgrp $(GROUP) $(MAN1DIR)/buildtables.1 + @chown $(OWNER) $(MAN1DIR)/buildtables.1 + +clean : + +clobber : clean + rm -f buildtables + +buildtables : buildtables.sh + sed \ + -e "s'^FONTDIR=.*'FONTDIR=$(FONTDIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + buildtables.sh >buildtables + @chmod 755 buildtables + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^FONTDIR=.*'FONTDIR=$(FONTDIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dF.*'.ds dF $(FONTDIR)'" \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + buildtables.1 >XXX.1; \ + mv XXX.1 buildtables.1 + diff --git a/sys/src/cmd/postscript/buildtables/buildtables.sh b/sys/src/cmd/postscript/buildtables/buildtables.sh new file mode 100755 index 000000000..f9e4404d7 --- /dev/null +++ b/sys/src/cmd/postscript/buildtables/buildtables.sh @@ -0,0 +1,94 @@ +# +# Builds one or more font width tables or the typesetter description +# file on a PostScript printer. Assumes you have direct access to the +# printer's serial port. No arguments means build a standard collection +# of tables - usually the LaserWriter Plus set. See trofftable and the +# shell library files /usr/lib/font/dev*/shell.lib for more details. +# + +set -e + +POSTBIN=/usr/lbin/postscript +POSTLIB=/usr/lib/postscript +FONTDIR=/usr/lib/font + +POSTIO=$POSTBIN/postio +TROFFTABLE=$POSTBIN/trofftable + +BAUDRATE= +DEVICE= +LIBRARY= + +while [ -n "$1" ]; do + case $1 in + -C) shift; OPTIONS="$OPTIONS -C$1";; + -C*) OPTIONS="$OPTIONS $1";; + + -F) shift; FONTDIR=$1;; + -F*) FONTDIR=`echo $1 | sed s/-F//`;; + + -H) shift; OPTIONS="$OPTIONS -H$1";; + -H*) OPTIONS="$OPTIONS $1";; + + -S) shift; LIBRARY=$1;; + -S*) LIBRARY=`echo $1 | sed s/-S//`;; + + -T) shift; DEVICE=$1;; + -T*) DEVICE=`echo $1 | sed s/-T//`;; + + -b) shift; BAUDRATE=$1;; + -b*) BAUDRATE=`echo $1 | sed s/-b//`;; + + -c) shift; OPTIONS="$OPTIONS -c$1";; + -c*) OPTIONS="$OPTIONS $1";; + + -l) shift; LINE=$1;; + -l*) LINE=`echo $1 | sed s/-l//`;; + + -s) shift; OPTIONS="$OPTIONS -s$1";; + -s*) OPTIONS="$OPTIONS $1";; + + -t) shift; OPTIONS="$OPTIONS -t$1";; + -t*) OPTIONS="$OPTIONS $1";; + + -?) OPTIONS="$OPTIONS $1$2"; shift;; + -?*) OPTIONS="$OPTIONS $1";; + + *) break;; + esac + shift +done + +if [ ! "$DEVICE" -a ! "$LIBRARY" ]; then + echo "$0: no device or shell library" >&2 + exit 1 +fi + +LIBRARY=${LIBRARY:-${FONTDIR}/dev${DEVICE}/shell.lib} + +# +# No arguments means build everything return by the AllTables function. +# + +if [ $# -eq 0 ]; then + . $LIBRARY + set -- `AllTables` +fi + +for i do + SHORT=`echo $i | awk '{print $1}'` + LONG=`echo $i | awk '{print $2}'` + + if [ "$LINE" ] + then echo "==== Building table $SHORT ====" + else echo "==== Creating table program $SHORT.ps ====" + fi + + $TROFFTABLE -S$LIBRARY $OPTIONS $SHORT $LONG >$SHORT.ps + + if [ "$LINE" ]; then + $POSTIO -t -l$LINE ${BAUDRATE:+-b${BAUDRATE}} $SHORT.ps >$SHORT + rm -f $SHORT.ps + fi +done + diff --git a/sys/src/cmd/postscript/changes b/sys/src/cmd/postscript/changes new file mode 100755 index 000000000..500eda2a6 --- /dev/null +++ b/sys/src/cmd/postscript/changes @@ -0,0 +1,95 @@ +add mkfile to each directory for plan9. + +common: +add getopt.c to common. +insert #include <sys/types.h> before #include <fcntl.h> for off_t in bbox.c. +comment out strtok(), ftell(), sqrt() atan2() defs in ext.h. +insert #include <sys/types.h> before #include <fcntl.h> for off_t in misc.c. +comment out RUNELIB on #endif line in rune.c +add defined(plan9) in tempnam.c. +change path.h for plan9! + +cropmarks: +add cropmarks.rc to cropmarks. + +download: +move #include <sys/types.h> before #include <fcntl.h> for off_t in download.c. + +dpost: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in dpost.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in dpost.c. + +grabit: +add grabit.rc to grabit. + +hardcopy: +add hardcopy.rc to hardcopy. + +postbgi: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postbgi.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in postbgi.c. + +postdaisy: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postdaisy.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in postdaisy.c. + +postdmd: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postdmd.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in postdmd.c. + +postgif: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postgif.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in postgif.c. + +download: +added #include <string.h> in download.c. + +dpost: +added #include <string.h> in draw.c. + +picpack: +added #include <string.h> in picpack.c. + +postmd: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postmd.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in postmd.c. +added #include <string.h> in picpack.c. + +postprint: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postprint.c. +added + #ifdef plan9 + #define isascii(c) ((unsigned char)(c)<=0177) + #endif +after #include <ctype.h> in postprint.c. + +postreverse: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in postreverse.c. + +posttek: +insert #include <sys/types.h> before #include <fcntl.h> for off_t in posttek.c. + diff --git a/sys/src/cmd/postscript/common/bbox.c b/sys/src/cmd/postscript/common/bbox.c new file mode 100755 index 000000000..7e1f14a50 --- /dev/null +++ b/sys/src/cmd/postscript/common/bbox.c @@ -0,0 +1,257 @@ +/* + * + * Boundingbox code for PostScript translators. The boundingbox for each page + * is accumulated in bbox - the one for the whole document goes in docbbox. A + * call to writebbox() puts out an appropriate comment, updates docbbox, and + * resets bbox for the next page. The assumption made at the end of writebbox() + * is that we're really printing the current page only if output is now going + * to stdout - a valid assumption for all supplied translators. Needs the math + * library. + * + */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> +#include <math.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* a few general purpose definitions */ +#include "ext.h" /* external variable declarations */ + +typedef struct bbox { + int set; + double llx, lly; + double urx, ury; +} Bbox; + +Bbox bbox = {FALSE, 0.0, 0.0, 0.0, 0.0}; +Bbox docbbox = {FALSE, 0.0, 0.0, 0.0, 0.0}; + +double ctm[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; +double matrix1[6], matrix2[6]; + +/*****************************************************************************/ + +cover(x, y) + + double x, y; + +{ + +/* + * + * Adds point (x, y) to bbox. Coordinates are in user space - the transformation + * to default coordinates happens in writebbox(). + * + */ + + if ( bbox.set == FALSE ) { + bbox.llx = bbox.urx = x; + bbox.lly = bbox.ury = y; + bbox.set = TRUE; + } else { + if ( x < bbox.llx ) + bbox.llx = x; + if ( y < bbox.lly ) + bbox.lly = y; + if ( x > bbox.urx ) + bbox.urx = x; + if ( y > bbox.ury ) + bbox.ury = y; + } /* End else */ + +} /* End of cover */ + +/*****************************************************************************/ + +writebbox(fp, keyword, slop) + + FILE *fp; /* the comment is written here */ + char *keyword; /* the boundingbox comment string */ + int slop; /* expand (or contract?) the box a bit */ + +{ + + Bbox ubbox; /* user space bounding box */ + double x, y; + +/* + * + * Transforms the numbers in the bbox[] using ctm[], adjusts the corners a bit + * (depending on slop) and then writes comment. If *keyword is BoundingBox use + * whatever's been saved in docbbox, otherwise assume the comment is just for + * the current page. + * + */ + + if ( strcmp(keyword, BOUNDINGBOX) == 0 ) + bbox = docbbox; + + if ( bbox.set == TRUE ) { + ubbox = bbox; + bbox.set = FALSE; /* so cover() works properly */ + x = ctm[0] * ubbox.llx + ctm[2] * ubbox.lly + ctm[4]; + y = ctm[1] * ubbox.llx + ctm[3] * ubbox.lly + ctm[5]; + cover(x, y); + x = ctm[0] * ubbox.llx + ctm[2] * ubbox.ury + ctm[4]; + y = ctm[1] * ubbox.llx + ctm[3] * ubbox.ury + ctm[5]; + cover(x, y); + x = ctm[0] * ubbox.urx + ctm[2] * ubbox.ury + ctm[4]; + y = ctm[1] * ubbox.urx + ctm[3] * ubbox.ury + ctm[5]; + cover(x, y); + x = ctm[0] * ubbox.urx + ctm[2] * ubbox.lly + ctm[4]; + y = ctm[1] * ubbox.urx + ctm[3] * ubbox.lly + ctm[5]; + cover(x, y); + bbox.llx -= slop + 0.5; + bbox.lly -= slop + 0.5; + bbox.urx += slop + 0.5; + bbox.ury += slop + 0.5; + fprintf(fp, "%s %d %d %d %d\n", keyword, (int)bbox.llx, (int)bbox.lly,(int)bbox.urx, (int)bbox.ury); + bbox = ubbox; + } /* End if */ + + resetbbox((fp == stdout) ? TRUE : FALSE); + +} /* End of writebbox */ + +/*****************************************************************************/ + +resetbbox(output) + + int output; + +{ + +/* + * + * Adds bbox to docbbox and resets bbox for the next page. Only update docbbox + * if we really did output on the last page. + * + */ + + if ( docbbox.set == TRUE ) { + cover(docbbox.llx, docbbox.lly); + cover(docbbox.urx, docbbox.ury); + } /* End if */ + + if ( output == TRUE ) { + docbbox = bbox; + docbbox.set = TRUE; + } /* End if */ + + bbox.set = FALSE; + +} /* End of resetbbox */ + +/*****************************************************************************/ + +scale(sx, sy) + + double sx, sy; + +{ + +/* + * + * Scales the default matrix. + * + */ + + matrix1[0] = sx; + matrix1[1] = 0; + matrix1[2] = 0; + matrix1[3] = sy; + matrix1[4] = 0; + matrix1[5] = 0; + + concat(matrix1); + +} /* End of scale */ + +/*****************************************************************************/ + +translate(tx, ty) + + double tx, ty; + +{ + +/* + * + * Translates the default matrix. + * + */ + + matrix1[0] = 1.0; + matrix1[1] = 0.0; + matrix1[2] = 0.0; + matrix1[3] = 1.0; + matrix1[4] = tx; + matrix1[5] = ty; + + concat(matrix1); + +} /* End of translate */ + +/*****************************************************************************/ + +rotate(angle) + + double angle; + +{ + +/* + * + * Rotates by angle degrees. + * + */ + + angle *= 3.1416 / 180; + + matrix1[0] = matrix1[3] = cos(angle); + matrix1[1] = sin(angle); + matrix1[2] = -matrix1[1]; + matrix1[4] = 0.0; + matrix1[5] = 0.0; + + concat(matrix1); + +} /* End of rotate */ + +/*****************************************************************************/ + +concat(m1) + + double m1[]; + +{ + + double m2[6]; + +/* + * + * Replaces the ctm[] by the result of the matrix multiplication m1[] x ctm[]. + * + */ + + m2[0] = ctm[0]; + m2[1] = ctm[1]; + m2[2] = ctm[2]; + m2[3] = ctm[3]; + m2[4] = ctm[4]; + m2[5] = ctm[5]; + + ctm[0] = m1[0] * m2[0] + m1[1] * m2[2]; + ctm[1] = m1[0] * m2[1] + m1[1] * m2[3]; + ctm[2] = m1[2] * m2[0] + m1[3] * m2[2]; + ctm[3] = m1[2] * m2[1] + m1[3] * m2[3]; + ctm[4] = m1[4] * m2[0] + m1[5] * m2[2] + m2[4]; + ctm[5] = m1[4] * m2[1] + m1[5] * m2[3] + m2[5]; + +} /* End of concat */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/common/comments.h b/sys/src/cmd/postscript/common/comments.h new file mode 100755 index 000000000..6b409cad1 --- /dev/null +++ b/sys/src/cmd/postscript/common/comments.h @@ -0,0 +1,127 @@ +/* + * + * Currently defined file structuring comments from Adobe - plus a few others. + * Ones that end with a colon expect arguments, while those ending with a newline + * stand on their own. Truly overkill on Adobe's part and mine for including them + * all! + * + * All PostScript files should begin with a header that starts with one of the + * following comments. + * + */ + +#define NONCONFORMING "%!PS\n" +#define MINCONFORMING "%!PS-Adobe-\n" +#define OLDCONFORMING "%!PS-Adobe-1.0\n" + +#define CONFORMING "%!PS-Adobe-2.0\n" +#define CONFORMINGEPS "%!PS-Adobe-2.0 EPS\n" +#define CONFORMINGQUERY "%!PS-Adobe-2.0 Query\n" +#define CONFORMINGEXITSERVER "%!PS-Adobe-2.0 ExitServer\n" + +/* + * + * Header comments - immediately follow the appropriate document classification + * comment. + * + */ + +#define TITLE "%%Title:" +#define CREATOR "%%Creator:" +#define CREATIONDATE "%%CreationDate:" +#define FOR "%%For:" +#define ROUTING "%%Routing:" +#define BOUNDINGBOX "%%BoundingBox:" +#define PAGES "%%Pages:" +#define REQUIREMENTS "%%Requirements:" + +#define DOCUMENTFONTS "%%DocumentFonts:" +#define DOCUMENTNEEDEDFONTS "%%DocumentNeededFonts:" +#define DOCUMENTSUPPLIEDFONTS "%%DocumentSuppliedFonts:" +#define DOCUMENTNEEDEDPROCSETS "%%DocumentNeededProcSets:" +#define DOCUMENTSUPPLIEDPROCSETS "%%DocumentSuppliedProcSets:" +#define DOCUMENTNEEDEDFILES "%%DocumentNeededFiles:" +#define DOCUMENTSUPPLIEDFILES "%%DocumentSuppliedFiles:" +#define DOCUMENTPAPERSIZES "%%DocumentPaperSizes:" +#define DOCUMENTPAPERFORMS "%%DocumentPaperForms:" +#define DOCUMENTPAPERCOLORS "%%DocumentPaperColors:" +#define DOCUMENTPAPERWEIGHTS "%%DocumentPaperWeights:" +#define DOCUMENTPRINTERREQUIRED "%%DocumentPrinterREquired:" +#define ENDCOMMENTS "%%EndComments\n" +#define ENDPROLOG "%%EndProlog\n" + +/* + * + * Body comments - can appear anywhere in a document. + * + */ + +#define BEGINSETUP "%%BeginSetup\n" +#define ENDSETUP "%%EndSetup\n" +#define BEGINDOCUMENT "%%BeginDocument:" +#define ENDDOCUMENT "%%EndDocument\n" +#define BEGINFILE "%%BeginFile:" +#define ENDFILE "%%EndFile\n" +#define BEGINPROCSET "%%BeginProcSet:" +#define ENDPROCSET "%%EndProcSet\n" +#define BEGINBINARY "%%BeginBinary:" +#define ENDBINARY "%%EndBinary\n" +#define BEGINPAPERSIZE "%%BeginePaperSize:" +#define ENDPAPERSIZE "%%EndPaperSize\n" +#define BEGINFEATURE "%%BeginFeature:" +#define ENDFEATURE "%%EndFeature\n" +#define BEGINEXITSERVER "%%BeginExitServer:" +#define ENDEXITSERVER "%%EndExitServer\n" +#define TRAILER "%%Trailer\n" + +/* + * + * Page level comments - usually will occur once per page. + * + */ + +#define PAGE "%%Page:" +#define PAGEFONTS "%%PageFonts:" +#define PAGEFILES "%%PageFiles:" +#define PAGEBOUNDINGBOX "%%PageBoundingBox:" +#define BEGINPAGESETUP "%%BeginPageSetup\n" +#define BEGINOBJECT "%%BeginObject:" +#define ENDOBJECT "%%EndObject\n" + +/* + * + * Resource requirements - again can appear anywhere in a document. + * + */ + +#define INCLUDEFONT "%%IncludeFont:" +#define INCLUDEPROCSET "%%IncludeProcSet:" +#define INCLUDEFILE "%%IncludeFile:" +#define EXECUTEFILE "%%ExecuteFile:" +#define CHANGEFONT "%%ChangeFont:" +#define PAPERFORM "%%PaparForm:" +#define PAPERCOLOR "%%PaperColor:" +#define PAPERWEIGHT "%%PaperWeight:" +#define PAPERSIZE "%%PaperSize:" +#define FEATURE "%%Feature:" +#define ENDOFFILE "%%EOF\n" + +#define CONTINUECOMMENT "%%+" +#define ATEND "(atend)" + +/* + * + * Some non-standard document comments. Global definitions are occasionally used + * in dpost and are marked by BEGINGLOBAL and ENDGLOBAL. The resulting document + * violates page independence, but can easily be converted to a conforming file + * using a utililty program. + * + */ + +#define BEGINSCRIPT "%%BeginScript\n" +#define BEGINGLOBAL "%%BeginGlobal\n" +#define ENDGLOBAL "%%EndGlobal\n" +#define ENDPAGE "%%EndPage:" +#define FORMSPERPAGE "%%FormsPerPage:" +#define VERSION "%%Version:" + diff --git a/sys/src/cmd/postscript/common/common.c b/sys/src/cmd/postscript/common/common.c new file mode 100755 index 000000000..24c2f55cb --- /dev/null +++ b/sys/src/cmd/postscript/common/common.c @@ -0,0 +1,264 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include "common.h" +#include "comments.h" +#include "path.h" + +struct strtab charcode[FONTSIZE] = { + {4, "\\000"}, {4, "\\001"}, {4, "\\002"}, {4, "\\003"}, + {4, "\\004"}, {4, "\\005"}, {4, "\\006"}, {4, "\\007"}, + {4, "\\010"}, {4, "\\011"}, {4, "\\012"}, {4, "\\013"}, + {4, "\\014"}, {4, "\\015"}, {4, "\\016"}, {4, "\\017"}, + {4, "\\020"}, {4, "\\021"}, {4, "\\022"}, {4, "\\023"}, + {4, "\\024"}, {4, "\\025"}, {4, "\\026"}, {4, "\\027"}, + {4, "\\030"}, {4, "\\031"}, {4, "\\032"}, {4, "\\033"}, + {4, "\\034"}, {4, "\\035"}, {4, "\\036"}, {4, "\\037"}, + {1, " "}, {1, "!"}, {1, "\""}, {1, "#"}, + {1, "$"}, {1, "%"}, {1, "&"}, {1, "'"}, + {2, "\\("}, {2, "\\)"}, {1, "*"}, {1, "+"}, + {1, ","}, {1, "-"}, {1, "."}, {1, "/"}, + {1, "0"}, {1, "1"}, {1, "2"}, {1, "3"}, + {1, "4"}, {1, "5"}, {1, "6"}, {1, "7"}, + {1, "8"}, {1, "9"}, {1, ":"}, {1, ";"}, + {1, "<"}, {1, "="}, {1, ">"}, {1, "?"}, + {1, "@"}, {1, "A"}, {1, "B"}, {1, "C"}, + {1, "D"}, {1, "E"}, {1, "F"}, {1, "G"}, + {1, "H"}, {1, "I"}, {1, "J"}, {1, "K"}, + {1, "L"}, {1, "M"}, {1, "N"}, {1, "O"}, + {1, "P"}, {1, "Q"}, {1, "R"}, {1, "S"}, + {1, "T"}, {1, "U"}, {1, "V"}, {1, "W"}, + {1, "X"}, {1, "Y"}, {1, "Z"}, {1, "["}, + {2, "\\\\"}, {1, "]"}, {1, "^"}, {1, "_"}, + {1, "`"}, {1, "a"}, {1, "b"}, {1, "c"}, + {1, "d"}, {1, "e"}, {1, "f"}, {1, "g"}, + {1, "h"}, {1, "i"}, {1, "j"}, {1, "k"}, + {1, "l"}, {1, "m"}, {1, "n"}, {1, "o"}, + {1, "p"}, {1, "q"}, {1, "r"}, {1, "s"}, + {1, "t"}, {1, "u"}, {1, "v"}, {1, "w"}, + {1, "x"}, {1, "y"}, {1, "z"}, {1, "{"}, + {1, "|"}, {1, "}"}, {1, "~"}, {4, "\\177"}, + {4, "\\200"}, {4, "\\201"}, {4, "\\202"}, {4, "\\203"}, + {4, "\\204"}, {4, "\\205"}, {4, "\\206"}, {4, "\\207"}, + {4, "\\210"}, {4, "\\211"}, {4, "\\212"}, {4, "\\213"}, + {4, "\\214"}, {4, "\\215"}, {4, "\\216"}, {4, "\\217"}, + {4, "\\220"}, {4, "\\221"}, {4, "\\222"}, {4, "\\223"}, + {4, "\\224"}, {4, "\\225"}, {4, "\\226"}, {4, "\\227"}, + {4, "\\230"}, {4, "\\231"}, {4, "\\232"}, {4, "\\233"}, + {4, "\\234"}, {4, "\\235"}, {4, "\\236"}, {4, "\\237"}, + {4, "\\240"}, {4, "\\241"}, {4, "\\242"}, {4, "\\243"}, + {4, "\\244"}, {4, "\\245"}, {4, "\\246"}, {4, "\\247"}, + {4, "\\250"}, {4, "\\251"}, {4, "\\252"}, {4, "\\253"}, + {4, "\\254"}, {4, "\\255"}, {4, "\\256"}, {4, "\\257"}, + {4, "\\260"}, {4, "\\261"}, {4, "\\262"}, {4, "\\263"}, + {4, "\\264"}, {4, "\\265"}, {4, "\\266"}, {4, "\\267"}, + {4, "\\270"}, {4, "\\271"}, {4, "\\272"}, {4, "\\273"}, + {4, "\\274"}, {4, "\\275"}, {4, "\\276"}, {4, "\\277"}, + {4, "\\300"}, {4, "\\301"}, {4, "\\302"}, {4, "\\303"}, + {4, "\\304"}, {4, "\\305"}, {4, "\\306"}, {4, "\\307"}, + {4, "\\310"}, {4, "\\311"}, {4, "\\312"}, {4, "\\313"}, + {4, "\\314"}, {4, "\\315"}, {4, "\\316"}, {4, "\\317"}, + {4, "\\320"}, {4, "\\321"}, {4, "\\322"}, {4, "\\323"}, + {4, "\\324"}, {4, "\\325"}, {4, "\\326"}, {4, "\\327"}, + {4, "\\330"}, {4, "\\331"}, {4, "\\332"}, {4, "\\333"}, + {4, "\\334"}, {4, "\\335"}, {4, "\\336"}, {4, "\\337"}, + {4, "\\340"}, {4, "\\341"}, {4, "\\342"}, {4, "\\343"}, + {4, "\\344"}, {4, "\\345"}, {4, "\\346"}, {4, "\\347"}, + {4, "\\350"}, {4, "\\351"}, {4, "\\352"}, {4, "\\353"}, + {4, "\\354"}, {4, "\\355"}, {4, "\\356"}, {4, "\\357"}, + {4, "\\360"}, {4, "\\361"}, {4, "\\362"}, {4, "\\363"}, + {4, "\\364"}, {4, "\\365"}, {4, "\\366"}, {4, "\\367"}, + {4, "\\370"}, {4, "\\371"}, {4, "\\372"}, {4, "\\373"}, + {4, "\\374"}, {4, "\\375"}, {4, "\\376"}, {4, "\\377"} +}; + +static BOOLEAN in_string = FALSE; +int char_no = 0; +int line_no = 0; +int page_no = 0; /* page number in a document */ +int pages_printed = 0; +static int pplistmaxsize=0; + +static unsigned char *pplist=0; /* bitmap list for storing pages to print */ + +void +pagelist(char *list) { + char c; + int n, m; + int state, start; + + if (list == 0) return; + state = 1; + start = 0; + while ((c=*list) != '\0') { + n = 0; + while (isdigit(c)) { + n = n * 10 + c - '0'; + c = *++list; + } + switch (state) { + case 1: + start = n; + case 2: + if (n/8+1 > pplistmaxsize) { + pplistmaxsize = n/8+1; + pplist = galloc(pplist, n/8+1, "page list"); + } + for (m=start; m<=n; m++) + pplist[m/8] |= 1<<(m%8); + break; + } + switch (c) { + case '-': + state = 2; + list++; + break; + case ',': + state = 1; + list++; + break; + case '\0': + break; + } + } +} + +BOOLEAN +pageon(void) { + extern BOOLEAN debug; + static BOOLEAN privdebug = FALSE; + + if (pplist == 0 && page_no != 0) { + if (privdebug && !debug) { + privdebug = FALSE; + debug = TRUE; + } + return(TRUE); /* no page list, print all pages */ + } + if (page_no/8 < pplistmaxsize && (pplist[page_no/8] & 1<<(page_no%8))) { + if (privdebug && !debug) { + privdebug = FALSE; + debug = TRUE; + } + return(TRUE); + } else { + if (!privdebug && debug) { + privdebug = TRUE; + debug = FALSE; + } + return(FALSE); + } +} + +static int stringhpos, stringvpos; + +void +startstring(void) { + if (!in_string) { + stringhpos = hpos; + stringvpos = vpos; + if (pageon()) Bprint(Bstdout, "("); + in_string = 1; + } +} + +void +endstring(void) { + if (in_string) { + if (pageon()) Bprint(Bstdout, ") %d %d w\n", stringhpos, stringvpos); + in_string = 0; + } +} + +BOOLEAN +isinstring(void) { + return(in_string); +} + +void +startpage(void) { + ++char_no; + ++line_no; + ++page_no; + if (pageon()) { + ++pages_printed; + Bprint(Bstdout, "%s %d %d\n", PAGE, page_no, pages_printed); + Bprint(Bstdout, "/saveobj save def\n"); + Bprint(Bstdout, "mark\n"); + Bprint(Bstdout, "%d pagesetup\n", pages_printed); + } +} + +void +endpage(void) { + endstring(); + curpostfontid = -1; + line_no = 0; + char_no = 0; + if (pageon()) { + Bprint(Bstdout, "cleartomark\n"); + Bprint(Bstdout, "showpage\n"); + Bprint(Bstdout, "saveobj restore\n"); + Bprint(Bstdout, "%s %d %d\n", ENDPAGE, page_no, pages_printed); + } +} + +/* This was taken from postprint */ + +int +cat(char *filename) { + Biobuf *bfile; + Biobufhdr *Bfile; + int n; + static char buf[Bsize]; + + if ((bfile = Bopen(filename, OREAD)) == 0) { + return(1); + } + Bfile = &(bfile->Biobufhdr); + while ((n=Bread(Bfile, buf, Bsize)) > 0) { + if (Bwrite(Bstdout, buf, n) != n) + break; + } + Bterm(Bfile); + if (n != 0) { + return(1); + } + return(0); +} +extern int debug; +void * +galloc(void *ptr, int size, char *perstr) { + void *x; + + if ((x=realloc(ptr, size)) == 0) { + perror(perstr); + exits("malloc"); + } + return(x); +} + +static char *errorstrings[] = { + {""}, /* NONE */ + {"WARNING"}, + {"FATAL"} +}; + +char *programname; +char *inputfilename = "<stdin>"; +int inputlineno; + +void +error(int errtype, char *fmt, ...) { + va_list arg; + + Bflush(Bstdout); + Bflush(Bstderr); + fprint(2, "%s: %s:%d :%s: ", programname, inputfilename, inputlineno, errorstrings[errtype]); + va_start(arg, fmt); + vfprint(2, fmt, arg); + va_end(arg); + if (errtype == FATAL) + exits("fatal error"); +} diff --git a/sys/src/cmd/postscript/common/common.h b/sys/src/cmd/postscript/common/common.h new file mode 100755 index 000000000..85805bbf8 --- /dev/null +++ b/sys/src/cmd/postscript/common/common.h @@ -0,0 +1,43 @@ +#define NONE 0 +#define WARNING 1 +#define FATAL 2 + +#define RUNEGETGROUP(a) ((a>>8)&0xff) +#define RUNEGETCHAR(a) (a&0xff) + +typedef int BOOLEAN; + +#define TRUE 1 +#define FALSE 0 + +#define NUMOFONTS 0x100 +#define FONTSIZE 0x100 + +extern char *programname; +extern char *inputfilename; +extern int inputlineno; + +extern int page_no; +extern int pages_printed; +extern int curpostfontid; +extern int hpos, vpos; + +extern Biobufhdr *Bstdout, *Bstderr; + +struct strtab { + int size; + char *str; + int used; +}; + +extern struct strtab charcode[]; +BOOLEAN pageon(void); +void startstring(void); +void endstring(void); +BOOLEAN isinstring(void); +void startpage(void); +void endpage(void); +int cat(char *); +int Bgetfield(Biobufhdr *, int, void *, int); +void *galloc(void *, int, char *); +void pagelist(char *); diff --git a/sys/src/cmd/postscript/common/ext.h b/sys/src/cmd/postscript/common/ext.h new file mode 100755 index 000000000..a811cca67 --- /dev/null +++ b/sys/src/cmd/postscript/common/ext.h @@ -0,0 +1,40 @@ +/* + * + * External varibles - most are in glob.c. + * + */ + +extern char **argv; /* global so everyone can use them */ +extern int argc; + +extern int x_stat; /* program exit status */ +extern int debug; /* debug flag */ +extern int ignore; /* what we do with FATAL errors */ + +extern long lineno; /* line number */ +extern long position; /* byte position */ +extern char *prog_name; /* and program name - for errors */ +extern char *temp_file; /* temporary file - for some programs */ +extern char *fontencoding; /* text font encoding scheme */ + +extern int dobbox; /* enable BoundingBox stuff if TRUE */ +extern double pageheight; /* only for BoundingBox calculations! */ +extern double pagewidth; + +extern int reading; /* input */ +extern int writing; /* and output encoding */ + +extern char *optarg; /* for getopt() */ +extern int optind; + +extern void interrupt(); +extern char *tempnam(char*,char*); +/* + * extern char *malloc(); + * extern char *calloc(); + * extern char *strtok(); + * extern long ftell(); + * extern double atof(); + * extern double sqrt(); + * extern double atan2(); + */ diff --git a/sys/src/cmd/postscript/common/gen.h b/sys/src/cmd/postscript/common/gen.h new file mode 100755 index 000000000..ba8cbbac3 --- /dev/null +++ b/sys/src/cmd/postscript/common/gen.h @@ -0,0 +1,65 @@ +/* + * + * A few definitions that shouldn't have to change. Used by most programs in + * this package. + * + */ + +#define PROGRAMVERSION "3.3.2" + +#define NON_FATAL 0 +#define FATAL 1 +#define USER_FATAL 2 + +#define OFF 0 +#define ON 1 + +#define FALSE 0 +#define TRUE 1 + +#define BYTE 8 +#define BMASK 0377 + +#define POINTS 72.3 + +#ifndef PI +#define PI 3.141592654 +#endif + +#define ONEBYTE 0 +#define UTFENCODING 1 + +#define READING ONEBYTE +#define WRITING ONEBYTE + +/* + * + * DOROUND controls whether some translators include file ROUNDPAGE (path.h) + * after the prologue. Used to round page dimensions obtained from the clippath + * to know paper sizes. Enabled by setting DOROUND to TRUE (or 1). + * + */ + +#define DOROUND TRUE + +/* + * + * Default resolution and the height and width of a page (in case we need to get + * to upper left corner) - only used in BoundingBox calculations!! + * + */ + +#define DEFAULT_RES 72 +#define PAGEHEIGHT 11.0 * DEFAULT_RES +#define PAGEWIDTH 8.5 * DEFAULT_RES + +/* + * + * Simple macros. + * + */ + +#define ABS(A) ((A) >= 0 ? (A) : -(A)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) + diff --git a/sys/src/cmd/postscript/common/getopt.c b/sys/src/cmd/postscript/common/getopt.c new file mode 100755 index 000000000..3922c12b8 --- /dev/null +++ b/sys/src/cmd/postscript/common/getopt.c @@ -0,0 +1,56 @@ +#ifndef _POSIX_SOURCE +#include <u.h> +#include <libc.h> +#endif +#include <stdio.h> +#define ERR(str, chr) if(opterr){fprintf(stderr, "%s%s%c\n", argv[0], str, chr);} +int opterr = 1; +int optind = 1; +int optopt; +char *optarg; +char *strchr(); + +int +getopt (argc, argv, opts) +char **argv, *opts; +{ + static int sp = 1; + register c; + register char *cp; + + if (sp == 1) + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return EOF; + else if (strcmp(argv[optind], "--") == 0) { + optind++; + return EOF; + } + optopt = c = argv[optind][sp]; + if (c == ':' || (cp=strchr(opts, c)) == NULL) { + ERR (": illegal option -- ", c); + if (argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') { + if (argv[optind][sp+1] != '\0') + optarg = &argv[optind++][sp+1]; + else if (++optind >= argc) { + ERR (": option requires an argument -- ", c); + sp = 1; + return '?'; + } else + optarg = argv[optind++]; + sp = 1; + } else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return c; +} diff --git a/sys/src/cmd/postscript/common/glob.c b/sys/src/cmd/postscript/common/glob.c new file mode 100755 index 000000000..2826f4e5f --- /dev/null +++ b/sys/src/cmd/postscript/common/glob.c @@ -0,0 +1,29 @@ +/* + * + * Global varibles - for PostScript translators. + * + */ + +#include <stdio.h> +#include "gen.h" + +char **argv; /* global so everyone can use them */ +int argc; + +int x_stat = 0; /* program exit status */ +int debug = OFF; /* debug flag */ +int ignore = OFF; /* what we do with FATAL errors */ + +long lineno = 0; /* line number */ +long position = 0; /* byte position */ +char *prog_name = ""; /* and program name - for errors */ +char *temp_file = NULL; /* temporary file - for some programs */ +char *fontencoding = NULL; /* text font encoding scheme */ + +int dobbox = FALSE; /* enable BoundingBox stuff if TRUE */ +double pageheight = PAGEHEIGHT; /* only for BoundingBox calculations! */ +double pagewidth = PAGEWIDTH; + +int reading = UTFENCODING; /* input */ +int writing = WRITING; /* and output encoding */ + diff --git a/sys/src/cmd/postscript/common/misc.c b/sys/src/cmd/postscript/common/misc.c new file mode 100755 index 000000000..25bd37aac --- /dev/null +++ b/sys/src/cmd/postscript/common/misc.c @@ -0,0 +1,230 @@ +/* + * + * General purpose routines. + * + */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> + +#include "gen.h" +#include "ext.h" +#include "path.h" + +int nolist = 0; /* number of specified ranges */ +int olist[50]; /* processing range pairs */ + +/*****************************************************************************/ + +out_list(str) + + char *str; + +{ + + int start, stop; + +/* + * + * Grab page ranges from str, save them in olist[], and update the nolist + * count. Range syntax matches nroff/troff syntax. + * + */ + + while ( *str && nolist < sizeof(olist) - 2 ) { + start = stop = str_convert(&str, 0); + + if ( *str == '-' && *str++ ) + stop = str_convert(&str, 9999); + + if ( start > stop ) + error(FATAL, "illegal range %d-%d", start, stop); + + olist[nolist++] = start; + olist[nolist++] = stop; + + if ( *str != '\0' ) str++; + } /* End while */ + + olist[nolist] = 0; + +} /* End of out_list */ + +/*****************************************************************************/ + +in_olist(num) + + int num; + +{ + + int i; + +/* + * + * Return ON if num is in the current page range list. Print everything if + * there's no list. + * + */ + if ( nolist == 0 ) + return(ON); + + for ( i = 0; i < nolist; i += 2 ) + if ( num >= olist[i] && num <= olist[i+1] ) + return(ON); + + return(OFF); + +} /* End of in_olist */ + +/*****************************************************************************/ + +setencoding(name) + + char *name; + +{ + + char path[150]; + +/* + * + * Include the font encoding file selected by name. It's a full pathname if + * it begins with /, otherwise append suffix ".enc" and look for the file in + * ENCODINGDIR. Missing files are silently ignored. + * + */ + + if ( name == NULL ) + name = "Default"; + + if ( *name == '/' ) + strcpy(path, name); + else sprintf(path, "%s/%s.enc", ENCODINGDIR, name); + + if ( cat(path) == TRUE ) + writing = strncmp(name, "UTF", 3) == 0; + +} /* End of setencoding */ + +/*****************************************************************************/ + +cat(file) + + char *file; + +{ + + int fd_in; + int fd_out; + char buf[512]; + int count; + +/* + * + * Copy *file to stdout. Return FALSE is there was a problem. + * + */ + + fflush(stdout); + + if ( (fd_in = open(file, O_RDONLY)) == -1 ) + return(FALSE); + + fd_out = fileno(stdout); + while ( (count = read(fd_in, buf, sizeof(buf))) > 0 ) + write(fd_out, buf, count); + + close(fd_in); + + return(TRUE); + +} /* End of cat */ + +/*****************************************************************************/ + +str_convert(str, err) + + char **str; + int err; + +{ + + int i; + +/* + * + * Grab the next integer from **str and return its value or err if *str + * isn't an integer. *str is modified after each digit is read. + * + */ + + if ( ! isdigit(**str) ) + return(err); + + for ( i = 0; isdigit(**str); *str += 1 ) + i = 10 * i + **str - '0'; + + return(i); + +} /* End of str_convert */ + +/*****************************************************************************/ + +error(kind, mesg, a1, a2, a3) + + int kind; + char *mesg; + unsigned a1, a2, a3; + +{ + +/* + * + * Print an error message and quit if kind is FATAL. + * + */ + + if ( mesg != NULL && *mesg != '\0' ) { + fprintf(stderr, "%s: ", prog_name); + fprintf(stderr, mesg, a1, a2, a3); + if ( lineno > 0 ) + fprintf(stderr, " (line %d)", lineno); + if ( position > 0 ) + fprintf(stderr, " (near byte %d)", position); + putc('\n', stderr); + } /* End if */ + + if ( kind == FATAL && ignore == OFF ) { + if ( temp_file != NULL ) + unlink(temp_file); + exit(x_stat | 01); + } /* End if */ + +} /* End of error */ + +/*****************************************************************************/ + +void interrupt(sig) + + int sig; + +{ + +/* + * + * Signal handler for translators. + * + */ + + if ( temp_file != NULL ) + unlink(temp_file); + + exit(1); + +} /* End of interrupt */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/common/mkfile b/sys/src/cmd/postscript/common/mkfile new file mode 100755 index 000000000..821c2b1b6 --- /dev/null +++ b/sys/src/cmd/postscript/common/mkfile @@ -0,0 +1,24 @@ +</$objtype/mkfile + +<../config + +LIB=com.a$O +OFILES=bbox.$O\ + glob.$O\ + misc.$O\ + request.$O\ + rune.$O\ + tempnam.$O\ + getopt.$O\ + +HFILES=comments.h\ + gen.h\ + ext.h\ + request.h\ + path.h\ + rune.h\ + +</sys/src/cmd/mklib + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -B +CC=pcc diff --git a/sys/src/cmd/postscript/common/path.h b/sys/src/cmd/postscript/common/path.h new file mode 100755 index 000000000..afb9c4dad --- /dev/null +++ b/sys/src/cmd/postscript/common/path.h @@ -0,0 +1,32 @@ +/* + * + * pathname definitions for important files and directories. + * + */ + +#define DPOST "/sys/lib/postscript/prologues/dpost.ps" +#define POSTBGI "/sys/lib/postscript/prologues/postbgi.ps" +#define POSTDAISY "/sys/lib/postscript/prologues/postdaisy.ps" +#define POSTDMD "/sys/lib/postscript/prologues/postdmd.ps" +#define POSTMD "/sys/lib/postscript/prologues/postmd.ps" +#define POSTPLOT "/sys/lib/postscript/prologues/postplot.ps" +#define POSTPRINT "/sys/lib/postscript/prologues/postprint.ps" +#define POSTNPRINT "/sys/lib/postscript/prologues/postnprint.ps" +#define POSTTEK "/sys/lib/postscript/prologues/posttek.ps" +#define POSTGIF "/sys/lib/postscript/prologues/postgif.ps" + +#define BASELINE "/sys/lib/postscript/prologues/baseline.ps" +#define COLOR "/sys/lib/postscript/prologues/color.ps" +#define DRAW "/sys/lib/postscript/prologues/draw.ps" +#define FORMFILE "/sys/lib/postscript/prologues/forms.ps" +#define SHADEFILE "/sys/lib/postscript/prologues/shade.ps" +#define KERNING "/sys/lib/postscript/prologues/kerning.ps" +#define REQUESTFILE "/sys/lib/postscript/prologues/ps.requests" +#define ROUNDPAGE "/sys/lib/postscript/prologues/roundpage.ps" + +#define ENCODINGDIR "/sys/lib/postscript/prologues" +#define HOSTDIR "/sys/lib/postscript/font" +#define FONTDIR "/sys/lib/troff/font" +#define POSTLIBDIR "/sys/lib/postscript/prologues" +#define TEMPDIR "/tmp" + diff --git a/sys/src/cmd/postscript/common/request.c b/sys/src/cmd/postscript/common/request.c new file mode 100755 index 000000000..d8d7dd130 --- /dev/null +++ b/sys/src/cmd/postscript/common/request.c @@ -0,0 +1,119 @@ +/* + * + * Things used to handle special requests (eg. manual feed) globally or on a per + * page basis. Requests are passed through to the translator using the -R option. + * The argument to -R can be "request", "request:page", or "request:page:file". + * If page is omitted (as in the first form) or set to 0 request will be applied + * to the global environment. In all other cases it applies only to the selected + * page. If a file is given, page must be supplied, and the lookup is in that file + * rather than *requestfile. + * + */ + +#include <stdio.h> + +#include "gen.h" /* general purpose definitions */ +#include "request.h" /* a few special definitions */ +#include "path.h" /* for the default request file */ + +Request request[MAXREQUEST]; /* next page or global request */ +int nextreq = 0; /* goes in request[nextreq] */ +char *requestfile = REQUESTFILE; /* default lookup file */ + +/*****************************************************************************/ + +saverequest(want) + + char *want; /* grab code for this stuff */ + +{ + + char *page; /* and save it for this page */ + char *strtok(); + +/* + * + * Save the request until we get to appropriate page - don't even bother with + * the lookup right now. Format of *want string is "request", "request:page", or + * "request:page:file", and we assume we can change the string here as needed. + * If page is omitted or given as 0 the request will be done globally. If *want + * includes a file, request and page must also be given, and in that case *file + * will be used for the lookup. + * + */ + + if ( nextreq < MAXREQUEST ) { + request[nextreq].want = strtok(want, ": "); + if ( (page = strtok(NULL, ": ")) == NULL ) + request[nextreq].page = 0; + else request[nextreq].page = atoi(page); + if ( (request[nextreq].file = strtok(NULL, ": ")) == NULL ) + request[nextreq].file = requestfile; + nextreq++; + } else error(NON_FATAL, "too many requests - ignoring %s", want); + +} /* End of saverequest */ + +/*****************************************************************************/ + +writerequest(page, fp_out) + + int page; /* write everything for this page */ + FILE *fp_out; /* to this file */ + +{ + + int i; /* loop index */ + +/* + * + * Writes out all the requests that have been saved for page. Page 0 refers to + * the global environment and is done during initial setup. + * + */ + + for ( i = 0; i < nextreq; i++ ) + if ( request[i].page == page ) + dumprequest(request[i].want, request[i].file, fp_out); + +} /* End of writerequest */ + +/*****************************************************************************/ + +dumprequest(want, file, fp_out) + + char *want; /* look for this string */ + char *file; /* in this file */ + FILE *fp_out; /* and write the value out here */ + +{ + + char buf[100]; /* line buffer for reading *file */ + FILE *fp_in; + +/* + * + * Looks for *want in the request file and if it's found the associated value + * is copied to the output file. Keywords (ie. the *want strings) begin an @ in + * the first column of file, while the values (ie. the stuff that's copied to + * the output file) starts on the next line and extends to the next keyword or + * to the end of file. + * + */ + + if ( (fp_in = fopen(file, "r")) != NULL ) { + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) + if ( buf[0] == '@' && strncmp(want, &buf[1], strlen(want)) == 0 ) + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) + if ( buf[0] == '#' || buf[0] == '%' ) + continue; + else if ( buf[0] != '@' ) + fprintf(fp_out, "%s", buf); + else break; + fclose(fp_in); + } /* End if */ + +} /* End of dumprequest */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/common/request.h b/sys/src/cmd/postscript/common/request.h new file mode 100755 index 000000000..25d94d01a --- /dev/null +++ b/sys/src/cmd/postscript/common/request.h @@ -0,0 +1,22 @@ +/* + * + * Things used to handle special PostScript requests (like manual feed) globally + * or on a per page basis. All the translators I've supplied accept the -R option + * that can be used to insert special PostScript code before the global setup is + * done, or at the start of named pages. The argument to the -R option is a string + * that can be "request", "request:page", or "request:page:file". If page isn't + * given (as in the first form) or if it's 0 in the last two, the request applies + * to the global environment, otherwise request holds only for the named page. + * If a file name is given a page number must be supplied, and in that case the + * request will be looked up in that file. + * + */ + +#define MAXREQUEST 30 + +typedef struct { + char *want; + int page; + char *file; +} Request; + diff --git a/sys/src/cmd/postscript/common/rune.c b/sys/src/cmd/postscript/common/rune.c new file mode 100755 index 000000000..01ee6ba81 --- /dev/null +++ b/sys/src/cmd/postscript/common/rune.c @@ -0,0 +1,142 @@ +#include "rune.h" + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + + T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ + Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ + T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ + T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ + T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ + + Maskx = (1<<Bitx)-1, /* 0011 1111 */ + Testx = Maskx ^ 0xFF, /* 1100 0000 */ + + Bad = Runeerror, +}; + +int +chartorune(Rune *rune, char *str) +{ + int c, c1, c2; + long l; + + /* + * one character sequence + * 00000-0007F => T1 + */ + c = *(unsigned char*)str; + if(c < Tx) { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = *(unsigned char*)(str+1) ^ Tx; + if(c1 & Testx) + goto bad; + if(c < T3) { + if(c < T2) + goto bad; + l = ((c << Bitx) | c1) & Rune2; + if(l <= Rune1) + goto bad; + *rune = l; + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + c2 = *(unsigned char*)(str+2) ^ Tx; + if(c2 & Testx) + goto bad; + if(c < T4) { + l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; + if(l <= Rune2) + goto bad; + *rune = l; + return 3; + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, Rune *rune) +{ + long c; + + /* + * one character sequence + * 00000-0007F => 00-7F + */ + c = *rune; + if(c <= Rune1) { + str[0] = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + if(c <= Rune2) { + str[0] = T2 | (c >> 1*Bitx); + str[1] = Tx | (c & Maskx); + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; +} + +int +runelen(long c) +{ + Rune rune; + char str[10]; + + rune = c; + return runetochar(str, &rune); +} + +int +fullrune(char *str, int n) +{ + int c; + + if(n > 0) { + c = *(unsigned char*)str; + if(c < Tx) + return 1; + if(n > 1) + if(c < T3 || n > 2) + return 1; + } + return 0; +} diff --git a/sys/src/cmd/postscript/common/rune.h b/sys/src/cmd/postscript/common/rune.h new file mode 100755 index 000000000..9c1fd4fd0 --- /dev/null +++ b/sys/src/cmd/postscript/common/rune.h @@ -0,0 +1,19 @@ +/* + * + * Rune declarations - for supporting UTF encoding. + * + */ + +#define RUNELIB 1 + +#ifdef RUNELIB +typedef unsigned short Rune; + +enum +{ + UTFmax = 3, /* maximum bytes per rune */ + Runesync = 0x80, /* cannot represent part of a utf sequence (<) */ + Runeself = 0x80, /* rune and utf sequences are the same (<) */ + Runeerror = 0xFFFD, /* decoding error in utf */ +}; +#endif diff --git a/sys/src/cmd/postscript/common/tempnam.c b/sys/src/cmd/postscript/common/tempnam.c new file mode 100755 index 000000000..00d819cab --- /dev/null +++ b/sys/src/cmd/postscript/common/tempnam.c @@ -0,0 +1,36 @@ +#if defined(V9) || defined(BSD4_2) || defined(plan9) +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +char * +tempnam(char *dir, char *pfx) +{ + int pid; + char *tnm; + struct stat stb; + static int seq = 0; + + if (dir == NULL) + dir = "."; +#ifdef plan9 + /* our access emulation has a race when checking for write access */ + if (access(dir, R_OK|X_OK) == -1) +#else + if (access(dir, R_OK|W_OK|X_OK) == -1) +#endif + return NULL; + pid = getpid(); + tnm = malloc(strlen(dir) + 1 + strlen(pfx) + 2*20 + 1); + if (tnm == NULL) + return NULL; + do { + sprintf(tnm, "%s/%s.%d.%d", dir, pfx, pid, seq++); + errno = 0; + } while (stat(tnm, &stb) >= 0 && seq < 256); + return tnm; +} +#endif diff --git a/sys/src/cmd/postscript/config b/sys/src/cmd/postscript/config new file mode 100755 index 000000000..742b4560a --- /dev/null +++ b/sys/src/cmd/postscript/config @@ -0,0 +1,11 @@ +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +POSTBIN=$ROOT/$objtype/bin/aux +DKHOST=FALSE +DKSTREAMS=FALSE +ROUNDPAGE=TRUE + +FONTDIR=/sys/lib/troff/font +POSTLIB=/sys/lib/postscript/prologues diff --git a/sys/src/cmd/postscript/cropmarks/cropmarks.ps b/sys/src/cmd/postscript/cropmarks/cropmarks.ps new file mode 100755 index 000000000..256891a9a --- /dev/null +++ b/sys/src/cmd/postscript/cropmarks/cropmarks.ps @@ -0,0 +1,131 @@ +% +% Center pages, based on pageheight and pagewidth, and redefine showpage +% to put cropmarks at each corner. Device dependent code to expand the +% paper size goes in procedure expandpagesize. Currently only supports +% a Linotronic 200P typesetter using 12 inch wide paper. You'll have to +% add code to expandpagesize to support different typesetters or even a +% 200P that's running differently. +% + +/CropmarkDict 40 dict dup begin + +/expandpage true def +/magnification 1 def +/pageheight 11.0 def +/pagewidth 8.5 def +/scaletofit false def +/scaling 1 def + +/marklength .3 def % inches +/markstart .125 def % inches +/markend .04 def % inches +/marklinewidth .25 def % points + +/inch {72 mul} def +/min {2 copy gt {exch} if pop} def +/max {2 copy lt {exch} if pop} def + +/setup { + /markspace markstart marklength add markend add inch marklinewidth add def + /totalheight pageheight inch markspace 2 mul add def + /totalwidth pagewidth inch markspace 2 mul add def + + pagedimensions + checkpagesize + /scaling getscaling def + xcenter ycenter translate + scaling scaling scale + pagewidth inch 2 div neg pageheight inch 2 div neg translate + clippage +} def + +/pagedimensions { + clippath pathbbox newpath + 4 -1 roll exch 4 1 roll 4 copy + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def +} def + +/checkpagesize { + height totalheight lt width totalwidth lt or expandpage and { + expandpagesize + pagedimensions + } if +} def + +/expandpagesize { % device dependent code + /Product statusdict begin /product where {pop product}{()} ifelse end def + + Product (Linotype) eq { % Linotronic 200P and other models? + statusdict /setpageparams known { + /maxwidth 12.0 inch def % 12 inch wide paper? + totalheight maxwidth le { + totalheight + totalwidth + maxwidth totalheight sub 2 div + 0 + }{ + totalwidth maxwidth min + totalheight + maxwidth totalwidth maxwidth min sub 2 div + 1 + } ifelse + statusdict /setpageparams get exec + } if + } if +} def + +/getscaling { + scaletofit + {height totalheight div width totalwidth div min 1 min} + {1} + ifelse +} def + +/clippage { + newpath + 0 0 moveto + pagewidth inch 0 rlineto + 0 pageheight inch rlineto + pagewidth neg inch 0 rlineto + closepath clip + newpath +} def + +/cropmark { + gsave + translate + rotate + marklinewidth dup translate + 0 0 transform round exch round exch itransform translate + markstart inch 0 moveto marklength inch 0 rlineto stroke + 0 markstart inch moveto 0 marklength inch rlineto stroke + grestore +} bind def + +/@PreviousShowpage /showpage load def + +end def + +% +% Cropmarks - in the default coordinate system. +% + +/showpage { + gsave + CropmarkDict begin + initgraphics + marklinewidth setlinewidth + xcenter ycenter translate + scaling scaling scale + 0 pagewidth inch 2 div pageheight inch 2 div cropmark + 90 pagewidth inch neg 2 div pageheight inch 2 div cropmark + 180 pagewidth inch neg 2 div pageheight inch 2 div neg cropmark + 270 pagewidth inch 2 div pageheight inch 2 div neg cropmark + @PreviousShowpage + end + grestore +} bind def + diff --git a/sys/src/cmd/postscript/cropmarks/cropmarks.rc b/sys/src/cmd/postscript/cropmarks/cropmarks.rc new file mode 100755 index 000000000..43ada5c69 --- /dev/null +++ b/sys/src/cmd/postscript/cropmarks/cropmarks.rc @@ -0,0 +1,74 @@ +#!/bin/rc +# Center pages and put cropmarks at each corner. Physical page size +# is set with -w and -h. The default is 8.5 by 11.0 inches. Device +# dependent code to change paper size (e.g. with setpageparams) goes +# in the prologue. You may need to customize the device dependent +# code that we distribute. By default it only supports variable page +# sizes on Linotronic typesetters, and assumes those typesetters are +# using 12 inch wide paper. Use -d to disable execution of device +# dependent PostScript code. +# +# What's here was written quickly and will likely be very different +# in our next release. It should be part of a more general program!! +# + +POSTLIB=/sys/lib/postscript/prologues +PROLOGUE=$POSTLIB/cropmarks.ps + +EXPANDPAGE=true +PAGEWIDTH=8.5 +PAGEHEIGHT=11.0 +SCALETOFIT=false +XOFFSET=0.0 +YOFFSET=0.0 + +NONCONFORMING=%!PS +ENDPROLOG=%%EndProlog +BEGINSETUP=%%BeginSetup +ENDSETUP=%%EndSetup + +while (! ~ $#* 0 && ~ $1 -*) { + switch ($1) { + case -d; EXPANDPAGE=false + + case -h; shift; PAGEHEIGHT=$1 + case -h*; PAGEHEIGHT=`{echo $1 | sed s/-h//} + + case -s; SCALETOFIT=true + + case -w; shift; PAGEWIDTH=$1 + case -w*; PAGEWIDTH=`{echo $1 | sed s/-w//} + + case -x; shift; XOFFSET=$1 + case -x*; XOFFSET=`{echo $1 | sed s/-x//} + + case -y; shift; YOFFSET=$1 + case -y*; YOFFSET=`{echo $1 | sed s/-y//} + + case -L; shift; PROLOGUE=$1 + case -L*; PROLOGUE=`{echo $1 | sed s/-L//} + + case --; + + case -*; echo '$0: illegal option $1' >[1=2]; exit 1 + + } + shift +} + +echo $NONCONFORMING +cat $PROLOGUE +echo $ENDPROLOG +echo $BEGINSETUP +echo 'CropmarkDict begin' +echo '/pageheight '$PAGEHEIGHT' def' +echo '/pagewidth '$PAGEWIDTH' def' +echo '/expandpage '$EXPANDPAGE' def' +echo '/scaletofit '$SCALETOFIT' def' +echo '/xoffset '$XOFFSET' def' +echo '/yoffset '$YOFFSET' def' +echo 'setup' +echo 'end' +echo $ENDSETUP + +cat $* diff --git a/sys/src/cmd/postscript/cropmarks/mkfile b/sys/src/cmd/postscript/cropmarks/mkfile new file mode 100755 index 000000000..ce9dbd4df --- /dev/null +++ b/sys/src/cmd/postscript/cropmarks/mkfile @@ -0,0 +1,22 @@ +</$objtype/mkfile + +<../config + +all:V: cropmarks + +install:V: $POSTBIN/cropmarks $POSTLIB/cropmarks.ps + +installall:V: install + +$POSTLIB/cropmarks.ps: cropmarks.ps + cp $prereq $target + +$POSTBIN/cropmarks: cropmarks + cp $prereq $target + +cropmarks: cropmarks.rc + sed 's?^POSTLIB=.*?POSTLIB='$POSTLIB'?' cropmarks.rc >cropmarks + chmod 775 cropmarks + +clean nuke:V: + rm -f cropmarks diff --git a/sys/src/cmd/postscript/devpost.add/C1 b/sys/src/cmd/postscript/devpost.add/C1 new file mode 100755 index 000000000..19be6b2fd --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/C1 @@ -0,0 +1,161 @@ +name C1 +fontname CenturyOldStyle-Regular +ligatures fi fl 0 +spacewidth 25 +charset +! 26 2 33 +" 40 2 34 +dq " +# 50 2 35 +$ 50 3 36 +% 58 2 37 +& 79 2 38 +' 21 2 39 +( 40 3 40 +) 40 3 41 +* 50 2 42 ++ 50 0 43 +, 25 1 44 +hy 24 0 45 +- " +. 25 0 46 +/ 53 3 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 25 0 58 +; 25 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 40 2 63 +@ 85 2 64 +A 66 2 65 +B 69 2 66 +C 69 2 67 +D 76 2 68 +E 66 2 69 +F 61 2 70 +G 74 2 71 +H 76 2 72 +I 34 2 73 +J 40 3 74 +K 71 2 75 +L 58 2 76 +M 95 2 77 +N 76 2 78 +O 76 2 79 +P 61 2 80 +Q 76 3 81 +R 63 2 82 +S 55 2 83 +T 63 2 84 +U 74 2 85 +V 66 2 86 +W 95 2 87 +X 63 2 88 +Y 63 2 89 +Z 58 2 90 +[ 40 3 91 +\ 25 2 92 +bs " +] 40 3 93 +--- 50 2 94 +--- 50 1 95 +` 21 2 96 +a 47 0 97 +b 55 2 98 +c 47 0 99 +d 55 2 100 +e 50 0 101 +f 29 2 102 +g 55 1 103 +h 58 2 104 +i 26 2 105 +j 24 3 106 +k 55 2 107 +l 26 2 108 +m 84 0 109 +n 55 0 110 +o 53 0 111 +p 53 1 112 +q 55 1 113 +r 40 0 114 +s 45 0 115 +t 31 2 116 +u 55 0 117 +v 47 0 118 +w 71 0 119 +x 53 0 120 +y 50 1 121 +z 45 0 122 +{ 40 3 123 +--- 25 2 124 +} 40 3 125 +--- 50 0 126 +--- 26 1 161 +ct 50 2 162 +ps 50 2 163 +fr 9 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 21 2 169 +`` 40 2 170 +--- 47 0 171 +--- 29 0 172 +--- 29 0 173 +fi 58 2 174 +fl 55 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 25 0 180 +pg 66 3 182 +--- 66 0 183 +--- 21 1 184 +--- 40 1 185 +'' 40 2 186 +--- 47 0 187 +--- 100 0 188 +--- 92 2 189 +--- 40 1 191 +ga 29 2 193 +\` " +aa 29 2 194 +\' " +^a 37 2 195 +^ " +~a 50 2 196 +~ " +-a 47 2 197 +Ua 50 2 198 +.a 26 2 199 +:a 47 2 200 +oa 34 2 202 +,a 34 1 203 +"a 40 2 205 +Ca 37 1 206 +va 37 2 207 +em 100 0 208 +--- 103 2 225 +--- 34 2 227 +--- 58 2 232 +--- 76 2 233 +--- 108 2 234 +--- 34 2 235 +--- 76 0 241 +--- 26 0 245 +--- 26 2 248 +--- 53 0 249 +--- 84 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/C2 b/sys/src/cmd/postscript/devpost.add/C2 new file mode 100755 index 000000000..359341a67 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/C2 @@ -0,0 +1,161 @@ +name C2 +fontname CenturyOldStyle-Italic +ligatures fi fl 0 +spacewidth 27 +charset +! 31 2 33 +" 35 2 34 +dq " +# 54 0 35 +$ 54 3 36 +% 70 2 37 +& 75 2 38 +' 21 2 39 +( 46 3 40 +) 46 3 41 +* 59 2 42 ++ 54 0 43 +, 27 1 44 +hy 25 0 45 +- " +. 27 0 46 +/ 46 3 47 +0 54 2 48 +1 54 0 49 +2 54 2 50 +3 54 2 51 +4 54 0 52 +5 54 0 53 +6 54 2 54 +7 54 0 55 +8 54 2 56 +9 54 2 57 +: 27 0 58 +; 27 1 59 +--- 54 0 60 += 54 0 61 +--- 54 0 62 +? 48 2 63 +@ 78 2 64 +A 67 2 65 +B 68 2 66 +C 65 2 67 +D 75 2 68 +E 66 2 69 +F 61 2 70 +G 72 2 71 +H 77 2 72 +I 36 2 73 +J 34 3 74 +K 68 2 75 +L 58 2 76 +M 90 2 77 +N 74 2 78 +O 74 2 79 +P 59 2 80 +Q 75 3 81 +R 65 2 82 +S 57 2 83 +T 63 2 84 +U 72 2 85 +V 62 2 86 +W 88 2 87 +X 64 2 88 +Y 61 2 89 +Z 57 2 90 +[ 46 3 91 +\ 27 2 92 +bs " +] 46 3 93 +--- 54 2 94 +--- 50 1 95 +` 21 2 96 +a 54 0 97 +b 46 2 98 +c 41 0 99 +d 50 2 100 +e 42 0 101 +f 25 3 102 +g 45 1 103 +h 52 2 104 +i 31 2 105 +j 27 3 106 +k 48 2 107 +l 27 2 108 +m 82 0 109 +n 56 0 110 +o 47 0 111 +p 50 1 112 +q 49 1 113 +r 40 0 114 +s 35 0 115 +t 30 0 116 +u 56 0 117 +v 47 0 118 +w 69 0 119 +x 41 0 120 +y 40 1 121 +z 39 0 122 +{ 46 3 123 +--- 27 2 124 +} 46 3 125 +--- 54 0 126 +--- 31 1 161 +ct 54 0 162 +ps 54 2 163 +fr 5 2 164 +yn 54 0 165 +fn 54 3 166 +sc 59 3 167 +cr 54 0 168 +--- 19 2 169 +`` 37 2 170 +--- 45 0 171 +--- 29 0 172 +--- 29 0 173 +fi 52 3 174 +fl 52 3 175 +en 50 0 177 +\- " +dg 59 3 178 +dd 59 3 179 +--- 27 0 180 +pg 61 3 182 +--- 61 0 183 +--- 21 1 184 +--- 37 1 185 +'' 37 2 186 +--- 45 0 187 +--- 100 0 188 +--- 103 2 189 +--- 48 1 191 +ga 39 2 193 +\` " +aa 31 2 194 +\' " +^a 40 2 195 +^ " +~a 51 2 196 +~ " +-a 47 0 197 +Ua 51 2 198 +.a 26 2 199 +:a 46 2 200 +oa 32 2 202 +,a 35 1 203 +"a 39 2 205 +Ca 34 1 206 +va 40 2 207 +em 100 0 208 +--- 94 2 225 +--- 32 2 227 +--- 58 2 232 +--- 74 2 233 +--- 107 2 234 +--- 32 2 235 +--- 69 0 241 +--- 31 0 245 +--- 27 2 248 +--- 47 0 249 +--- 71 0 250 +--- 53 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/C3 b/sys/src/cmd/postscript/devpost.add/C3 new file mode 100755 index 000000000..eef7eef09 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/C3 @@ -0,0 +1,161 @@ +name C3 +fontname CenturyOldStyle-Bold +ligatures fi fl 0 +spacewidth 33 +charset +! 34 2 33 +" 40 2 34 +dq " +# 56 2 35 +$ 66 3 36 +% 79 2 37 +& 84 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 56 2 42 ++ 56 0 43 +, 33 1 44 +hy 32 0 45 +- " +. 33 0 46 +/ 51 3 47 +0 66 2 48 +1 66 2 49 +2 66 2 50 +3 66 2 51 +4 66 2 52 +5 66 2 53 +6 66 2 54 +7 66 2 55 +8 66 2 56 +9 66 2 57 +: 33 0 58 +; 33 1 59 +--- 56 0 60 += 56 0 61 +--- 56 0 62 +? 47 2 63 +@ 72 2 64 +A 69 2 65 +B 76 2 66 +C 70 2 67 +D 80 2 68 +E 71 2 69 +F 64 2 70 +G 78 2 71 +H 83 2 72 +I 41 2 73 +J 48 2 74 +K 76 2 75 +L 63 2 76 +M 94 2 77 +N 80 2 78 +O 81 2 79 +P 72 2 80 +Q 81 3 81 +R 72 2 82 +S 61 2 83 +T 60 2 84 +U 78 2 85 +V 64 2 86 +W 97 2 87 +X 68 2 88 +Y 67 2 89 +Z 59 2 90 +[ 39 3 91 +\ 28 2 92 +bs " +] 39 3 93 +--- 56 2 94 +--- 50 1 95 +` 28 2 96 +a 53 0 97 +b 60 2 98 +c 52 0 99 +d 62 2 100 +e 54 0 101 +f 30 2 102 +g 52 3 103 +h 62 2 104 +i 31 2 105 +j 27 3 106 +k 60 2 107 +l 30 2 108 +m 92 0 109 +n 62 0 110 +o 57 0 111 +p 61 1 112 +q 60 1 113 +r 44 0 114 +s 50 0 115 +t 33 2 116 +u 63 0 117 +v 50 0 118 +w 74 0 119 +x 53 0 120 +y 49 1 121 +z 44 0 122 +{ 39 3 123 +--- 28 2 124 +} 39 3 125 +--- 56 0 126 +--- 34 1 161 +ct 66 2 162 +ps 66 2 163 +fr 10 2 164 +yn 66 2 165 +fn 66 3 166 +sc 56 3 167 +cr 66 2 168 +--- 22 2 169 +`` 52 2 170 +--- 58 0 171 +--- 37 0 172 +--- 37 0 173 +fi 62 2 174 +fl 61 2 175 +en 50 0 177 +\- " +dg 56 3 178 +dd 56 3 179 +--- 33 0 180 +pg 62 3 182 +--- 62 0 183 +--- 28 1 184 +--- 52 1 185 +'' 52 2 186 +--- 58 0 187 +--- 100 0 188 +--- 118 2 189 +--- 47 1 191 +ga 34 2 193 +\` " +aa 34 2 194 +\' " +^a 45 2 195 +^ " +~a 56 2 196 +~ " +-a 53 2 197 +Ua 56 2 198 +.a 29 2 199 +:a 51 2 200 +oa 34 2 202 +,a 37 1 203 +"a 50 2 205 +Ca 38 1 206 +va 45 2 207 +em 100 0 208 +--- 109 2 225 +--- 40 2 227 +--- 63 2 232 +--- 81 2 233 +--- 114 2 234 +--- 40 2 235 +--- 83 0 241 +--- 31 0 245 +--- 30 2 248 +--- 57 0 249 +--- 90 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/F1 b/sys/src/cmd/postscript/devpost.add/F1 new file mode 100755 index 000000000..e6e95cd2c --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/F1 @@ -0,0 +1,161 @@ +name F1 +fontname FranklinGothic-Book +ligatures fi fl 0 +spacewidth 30 +charset +! 30 2 33 +" 46 2 34 +dq " +# 60 2 35 +$ 60 2 36 +% 70 2 37 +& 68 2 38 +' 30 2 39 +( 30 3 40 +) 30 3 41 +* 60 2 42 ++ 60 0 43 +, 30 1 44 +hy 22 0 45 +- " +. 30 0 46 +/ 52 3 47 +0 60 2 48 +1 60 2 49 +2 60 2 50 +3 60 2 51 +4 60 2 52 +5 60 2 53 +6 60 2 54 +7 60 2 55 +8 60 2 56 +9 60 2 57 +: 30 0 58 +; 30 1 59 +--- 60 0 60 += 60 0 61 +--- 60 0 62 +? 54 2 63 +@ 80 2 64 +A 56 2 65 +B 62 2 66 +C 62 2 67 +D 66 2 68 +E 56 2 69 +F 48 2 70 +G 66 2 71 +H 66 2 72 +I 26 2 73 +J 40 2 74 +K 62 2 75 +L 50 2 76 +M 82 2 77 +N 66 2 78 +O 66 2 79 +P 56 2 80 +Q 66 3 81 +R 62 2 82 +S 62 2 83 +T 50 2 84 +U 64 2 85 +V 56 2 86 +W 82 2 87 +X 54 2 88 +Y 56 2 89 +Z 54 2 90 +[ 30 3 91 +\ 52 2 92 +bs " +] 30 3 93 +--- 60 2 94 +--- 50 1 95 +` 30 2 96 +a 54 0 97 +b 54 2 98 +c 48 0 99 +d 54 2 100 +e 54 0 101 +f 30 2 102 +g 50 1 103 +h 54 2 104 +i 24 2 105 +j 22 3 106 +k 50 2 107 +l 24 2 108 +m 82 0 109 +n 54 0 110 +o 54 0 111 +p 54 1 112 +q 54 1 113 +r 32 0 114 +s 52 0 115 +t 32 2 116 +u 54 0 117 +v 44 0 118 +w 66 0 119 +x 44 0 120 +y 42 1 121 +z 42 0 122 +{ 30 3 123 +--- 26 2 124 +} 30 3 125 +--- 60 0 126 +--- 30 1 161 +ct 60 2 162 +ps 60 2 163 +fr 16 2 164 +yn 60 2 165 +fn 60 3 166 +sc 60 3 167 +cr 60 0 168 +--- 30 2 169 +`` 46 2 170 +--- 40 0 171 +--- 26 0 172 +--- 26 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 60 3 178 +dd 60 3 179 +--- 30 0 180 +pg 54 3 182 +--- 60 0 183 +--- 30 1 184 +--- 46 1 185 +'' 46 2 186 +--- 40 0 187 +--- 100 0 188 +--- 104 2 189 +--- 54 1 191 +ga 38 2 193 +\` " +aa 38 2 194 +\' " +^a 48 2 195 +^ " +~a 50 2 196 +~ " +-a 46 2 197 +Ua 48 2 198 +.a 24 2 199 +:a 40 2 200 +oa 32 2 202 +,a 32 1 203 +"a 50 2 205 +Ca 32 1 206 +va 48 2 207 +em 100 0 208 +--- 96 2 225 +--- 36 2 227 +--- 50 2 232 +--- 66 2 233 +--- 100 2 234 +--- 36 2 235 +--- 90 0 241 +--- 24 0 245 +--- 20 2 248 +--- 54 0 249 +--- 88 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/F2 b/sys/src/cmd/postscript/devpost.add/F2 new file mode 100755 index 000000000..c237ae2bd --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/F2 @@ -0,0 +1,161 @@ +name F2 +fontname FranklinGothic-BookOblique +ligatures fi fl 0 +spacewidth 30 +charset +! 30 2 33 +" 46 2 34 +dq " +# 60 2 35 +$ 60 2 36 +% 70 2 37 +& 68 2 38 +' 30 2 39 +( 30 3 40 +) 30 3 41 +* 60 2 42 ++ 60 0 43 +, 30 1 44 +hy 22 0 45 +- " +. 30 0 46 +/ 52 3 47 +0 60 2 48 +1 60 2 49 +2 60 2 50 +3 60 2 51 +4 60 2 52 +5 60 2 53 +6 60 2 54 +7 60 2 55 +8 60 2 56 +9 60 2 57 +: 30 0 58 +; 30 1 59 +--- 60 0 60 += 60 0 61 +--- 60 0 62 +? 54 2 63 +@ 80 2 64 +A 56 2 65 +B 62 2 66 +C 62 2 67 +D 66 2 68 +E 56 2 69 +F 48 2 70 +G 66 2 71 +H 66 2 72 +I 26 2 73 +J 40 2 74 +K 62 2 75 +L 50 2 76 +M 82 2 77 +N 66 2 78 +O 66 2 79 +P 56 2 80 +Q 66 3 81 +R 62 2 82 +S 62 2 83 +T 50 2 84 +U 64 2 85 +V 56 2 86 +W 82 2 87 +X 54 2 88 +Y 56 2 89 +Z 54 2 90 +[ 30 3 91 +\ 52 2 92 +bs " +] 30 3 93 +--- 60 2 94 +--- 50 1 95 +` 30 2 96 +a 54 0 97 +b 54 2 98 +c 48 0 99 +d 54 2 100 +e 54 0 101 +f 30 2 102 +g 50 1 103 +h 54 2 104 +i 24 2 105 +j 22 3 106 +k 50 2 107 +l 24 2 108 +m 82 0 109 +n 54 0 110 +o 54 0 111 +p 54 1 112 +q 54 1 113 +r 32 0 114 +s 52 0 115 +t 32 2 116 +u 54 0 117 +v 44 0 118 +w 66 0 119 +x 44 0 120 +y 42 1 121 +z 42 0 122 +{ 30 3 123 +--- 26 2 124 +} 30 3 125 +--- 60 0 126 +--- 30 1 161 +ct 60 2 162 +ps 60 2 163 +fr 16 2 164 +yn 60 2 165 +fn 60 3 166 +sc 60 3 167 +cr 60 0 168 +--- 30 2 169 +`` 46 2 170 +--- 40 0 171 +--- 26 0 172 +--- 26 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 60 3 178 +dd 60 3 179 +--- 30 0 180 +pg 54 3 182 +--- 60 0 183 +--- 30 1 184 +--- 46 1 185 +'' 46 2 186 +--- 40 0 187 +--- 100 0 188 +--- 104 2 189 +--- 54 1 191 +ga 38 2 193 +\` " +aa 38 2 194 +\' " +^a 48 2 195 +^ " +~a 50 2 196 +~ " +-a 46 2 197 +Ua 48 2 198 +.a 24 2 199 +:a 40 2 200 +oa 32 2 202 +,a 32 1 203 +"a 50 2 205 +Ca 32 1 206 +va 48 2 207 +em 100 0 208 +--- 96 2 225 +--- 36 2 227 +--- 50 2 232 +--- 66 2 233 +--- 100 2 234 +--- 36 2 235 +--- 90 0 241 +--- 24 0 245 +--- 20 2 248 +--- 54 0 249 +--- 88 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/F3 b/sys/src/cmd/postscript/devpost.add/F3 new file mode 100755 index 000000000..cedb0e451 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/F3 @@ -0,0 +1,161 @@ +name F3 +fontname FranklinGothic-Demi +ligatures fi fl 0 +spacewidth 30 +charset +! 32 2 33 +" 46 2 34 +dq " +# 60 2 35 +$ 60 2 36 +% 70 2 37 +& 72 2 38 +' 30 2 39 +( 38 3 40 +) 38 3 41 +* 60 2 42 ++ 60 0 43 +, 30 1 44 +hy 24 0 45 +- " +. 30 0 46 +/ 60 3 47 +0 60 2 48 +1 60 2 49 +2 60 2 50 +3 60 2 51 +4 60 2 52 +5 60 2 53 +6 60 2 54 +7 60 2 55 +8 60 2 56 +9 60 2 57 +: 30 0 58 +; 30 1 59 +--- 60 0 60 += 60 0 61 +--- 60 0 62 +? 54 2 63 +@ 80 2 64 +A 64 2 65 +B 66 2 66 +C 66 2 67 +D 66 2 68 +E 58 2 69 +F 54 2 70 +G 66 2 71 +H 66 2 72 +I 30 2 73 +J 40 2 74 +K 64 2 75 +L 50 2 76 +M 88 2 77 +N 66 2 78 +O 66 2 79 +P 62 2 80 +Q 66 3 81 +R 66 2 82 +S 60 2 83 +T 54 2 84 +U 66 2 85 +V 60 2 86 +W 90 2 87 +X 64 2 88 +Y 60 2 89 +Z 66 2 90 +[ 38 3 91 +\ 60 2 92 +bs " +] 38 3 93 +--- 60 2 94 +--- 50 1 95 +` 30 2 96 +a 54 0 97 +b 54 2 98 +c 54 0 99 +d 54 2 100 +e 54 0 101 +f 30 2 102 +g 56 3 103 +h 54 2 104 +i 26 2 105 +j 26 3 106 +k 56 2 107 +l 26 2 108 +m 82 0 109 +n 54 0 110 +o 54 0 111 +p 54 1 112 +q 54 1 113 +r 34 0 114 +s 50 0 115 +t 38 2 116 +u 54 0 117 +v 48 0 118 +w 74 0 119 +x 54 0 120 +y 48 1 121 +z 42 0 122 +{ 38 3 123 +--- 30 2 124 +} 38 3 125 +--- 60 0 126 +--- 32 1 161 +ct 60 2 162 +ps 60 2 163 +fr 8 2 164 +yn 60 2 165 +fn 60 3 166 +sc 60 3 167 +cr 60 0 168 +--- 30 2 169 +`` 48 2 170 +--- 40 0 171 +--- 26 0 172 +--- 26 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 60 3 178 +dd 60 3 179 +--- 30 0 180 +pg 54 3 182 +--- 60 0 183 +--- 30 1 184 +--- 48 1 185 +'' 48 2 186 +--- 40 0 187 +--- 100 0 188 +--- 104 2 189 +--- 54 1 191 +ga 38 2 193 +\` " +aa 40 2 194 +\' " +^a 50 2 195 +^ " +~a 50 2 196 +~ " +-a 46 2 197 +Ua 52 2 198 +.a 26 2 199 +:a 42 2 200 +oa 32 2 202 +,a 34 1 203 +"a 52 2 205 +Ca 34 1 206 +va 52 2 207 +em 100 0 208 +--- 90 2 225 +--- 36 2 227 +--- 52 2 232 +--- 66 2 233 +--- 96 2 234 +--- 36 2 235 +--- 82 0 241 +--- 26 0 245 +--- 26 2 248 +--- 54 0 249 +--- 86 0 250 +--- 66 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/F4 b/sys/src/cmd/postscript/devpost.add/F4 new file mode 100755 index 000000000..c3093a531 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/F4 @@ -0,0 +1,161 @@ +name F4 +fontname FranklinGothic-DemiOblique +ligatures fi fl 0 +spacewidth 30 +charset +! 32 2 33 +" 46 2 34 +dq " +# 60 2 35 +$ 60 2 36 +% 70 2 37 +& 72 2 38 +' 30 2 39 +( 38 3 40 +) 38 3 41 +* 60 2 42 ++ 60 0 43 +, 30 1 44 +hy 24 0 45 +- " +. 30 0 46 +/ 60 3 47 +0 60 2 48 +1 60 2 49 +2 60 2 50 +3 60 2 51 +4 60 2 52 +5 60 2 53 +6 60 2 54 +7 60 2 55 +8 60 2 56 +9 60 2 57 +: 30 0 58 +; 30 1 59 +--- 60 0 60 += 60 0 61 +--- 60 0 62 +? 54 2 63 +@ 80 2 64 +A 64 2 65 +B 66 2 66 +C 66 2 67 +D 66 2 68 +E 58 2 69 +F 54 2 70 +G 66 2 71 +H 66 2 72 +I 30 2 73 +J 40 2 74 +K 64 2 75 +L 50 2 76 +M 88 2 77 +N 66 2 78 +O 66 2 79 +P 62 2 80 +Q 66 3 81 +R 66 2 82 +S 60 2 83 +T 54 2 84 +U 66 2 85 +V 60 2 86 +W 90 2 87 +X 64 2 88 +Y 60 2 89 +Z 66 2 90 +[ 38 3 91 +\ 60 2 92 +bs " +] 38 3 93 +--- 60 2 94 +--- 50 1 95 +` 30 2 96 +a 54 0 97 +b 54 2 98 +c 54 0 99 +d 54 2 100 +e 54 0 101 +f 30 2 102 +g 56 3 103 +h 54 2 104 +i 26 2 105 +j 26 3 106 +k 56 2 107 +l 26 2 108 +m 82 0 109 +n 54 0 110 +o 54 0 111 +p 54 1 112 +q 54 1 113 +r 34 0 114 +s 50 0 115 +t 38 2 116 +u 54 0 117 +v 48 0 118 +w 74 0 119 +x 54 0 120 +y 48 1 121 +z 42 0 122 +{ 38 3 123 +--- 30 2 124 +} 38 3 125 +--- 60 0 126 +--- 32 1 161 +ct 60 2 162 +ps 60 2 163 +fr 8 2 164 +yn 60 2 165 +fn 60 3 166 +sc 60 3 167 +cr 60 0 168 +--- 30 2 169 +`` 48 2 170 +--- 40 0 171 +--- 26 0 172 +--- 26 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 60 3 178 +dd 60 3 179 +--- 30 0 180 +pg 54 3 182 +--- 60 0 183 +--- 30 1 184 +--- 48 1 185 +'' 48 2 186 +--- 40 0 187 +--- 100 0 188 +--- 104 2 189 +--- 54 1 191 +ga 38 2 193 +\` " +aa 40 2 194 +\' " +^a 50 2 195 +^ " +~a 50 2 196 +~ " +-a 46 2 197 +Ua 52 2 198 +.a 26 2 199 +:a 42 2 200 +oa 32 2 202 +,a 34 1 203 +"a 52 2 205 +Ca 34 1 206 +va 52 2 207 +em 100 0 208 +--- 90 2 225 +--- 36 2 227 +--- 52 2 232 +--- 66 2 233 +--- 96 2 234 +--- 36 2 235 +--- 82 0 241 +--- 26 0 245 +--- 26 2 248 +--- 54 0 249 +--- 86 0 250 +--- 66 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/F5 b/sys/src/cmd/postscript/devpost.add/F5 new file mode 100755 index 000000000..d4d45d43a --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/F5 @@ -0,0 +1,161 @@ +name F5 +fontname FranklinGothic-Heavy +ligatures fi fl 0 +spacewidth 30 +charset +! 32 2 33 +" 52 2 34 +dq " +# 60 2 35 +$ 60 2 36 +% 74 2 37 +& 78 2 38 +' 30 2 39 +( 38 3 40 +) 38 3 41 +* 60 2 42 ++ 60 0 43 +, 30 1 44 +hy 26 0 45 +- " +. 30 0 46 +/ 60 3 47 +0 60 2 48 +1 60 2 49 +2 60 2 50 +3 60 2 51 +4 60 2 52 +5 60 2 53 +6 60 2 54 +7 60 2 55 +8 60 2 56 +9 60 2 57 +: 30 0 58 +; 30 1 59 +--- 60 0 60 += 60 0 61 +--- 60 0 62 +? 60 2 63 +@ 80 2 64 +A 66 2 65 +B 66 2 66 +C 66 2 67 +D 68 2 68 +E 60 2 69 +F 54 2 70 +G 68 2 71 +H 68 2 72 +I 32 2 73 +J 44 2 74 +K 66 2 75 +L 54 2 76 +M 86 2 77 +N 70 2 78 +O 70 2 79 +P 66 2 80 +Q 70 3 81 +R 68 2 82 +S 66 2 83 +T 50 2 84 +U 66 2 85 +V 66 2 86 +W 92 2 87 +X 70 2 88 +Y 66 2 89 +Z 60 2 90 +[ 38 3 91 +\ 60 2 92 +bs " +] 38 3 93 +--- 60 2 94 +--- 50 1 95 +` 30 2 96 +a 58 0 97 +b 58 2 98 +c 54 0 99 +d 58 2 100 +e 60 0 101 +f 40 2 102 +g 58 3 103 +h 58 2 104 +i 30 2 105 +j 30 3 106 +k 58 2 107 +l 30 2 108 +m 86 0 109 +n 58 0 110 +o 60 0 111 +p 58 1 112 +q 58 1 113 +r 38 0 114 +s 54 0 115 +t 40 2 116 +u 60 0 117 +v 54 0 118 +w 78 0 119 +x 58 0 120 +y 54 1 121 +z 50 0 122 +{ 38 3 123 +--- 30 2 124 +} 38 3 125 +--- 60 0 126 +--- 32 1 161 +ct 60 2 162 +ps 60 2 163 +fr 12 2 164 +yn 60 2 165 +fn 60 3 166 +sc 60 3 167 +cr 60 0 168 +--- 30 2 169 +`` 52 2 170 +--- 42 0 171 +--- 26 0 172 +--- 26 0 173 +fi 62 2 174 +fl 60 2 175 +en 50 0 177 +\- " +dg 60 3 178 +dd 60 3 179 +--- 30 0 180 +pg 54 3 182 +--- 60 0 183 +--- 30 1 184 +--- 52 1 185 +'' 52 2 186 +--- 42 0 187 +--- 100 0 188 +--- 108 2 189 +--- 60 1 191 +ga 40 2 193 +\` " +aa 40 2 194 +\' " +^a 54 2 195 +^ " +~a 50 2 196 +~ " +-a 46 2 197 +Ua 52 2 198 +.a 28 2 199 +:a 44 2 200 +oa 34 2 202 +,a 34 1 203 +"a 60 2 205 +Ca 34 1 206 +va 54 2 207 +em 100 0 208 +--- 96 2 225 +--- 38 2 227 +--- 56 2 232 +--- 70 2 233 +--- 98 2 234 +--- 38 2 235 +--- 82 0 241 +--- 30 0 245 +--- 30 2 248 +--- 60 0 249 +--- 86 0 250 +--- 66 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/F6 b/sys/src/cmd/postscript/devpost.add/F6 new file mode 100755 index 000000000..f7edf3efa --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/F6 @@ -0,0 +1,161 @@ +name F6 +fontname FranklinGothic-HeavyOblique +ligatures fi fl 0 +spacewidth 30 +charset +! 32 2 33 +" 52 2 34 +dq " +# 60 2 35 +$ 60 2 36 +% 74 2 37 +& 78 2 38 +' 30 2 39 +( 38 3 40 +) 38 3 41 +* 60 2 42 ++ 60 0 43 +, 30 1 44 +hy 26 0 45 +- " +. 30 0 46 +/ 60 3 47 +0 60 2 48 +1 60 2 49 +2 60 2 50 +3 60 2 51 +4 60 2 52 +5 60 2 53 +6 60 2 54 +7 60 2 55 +8 60 2 56 +9 60 2 57 +: 30 0 58 +; 30 1 59 +--- 60 0 60 += 60 0 61 +--- 60 0 62 +? 60 2 63 +@ 80 2 64 +A 66 2 65 +B 66 2 66 +C 66 2 67 +D 68 2 68 +E 60 2 69 +F 54 2 70 +G 68 2 71 +H 68 2 72 +I 32 2 73 +J 44 2 74 +K 66 2 75 +L 54 2 76 +M 86 2 77 +N 70 2 78 +O 70 2 79 +P 66 2 80 +Q 70 3 81 +R 68 2 82 +S 66 2 83 +T 50 2 84 +U 66 2 85 +V 66 2 86 +W 92 2 87 +X 70 2 88 +Y 66 2 89 +Z 60 2 90 +[ 38 3 91 +\ 60 2 92 +bs " +] 38 3 93 +--- 60 2 94 +--- 50 1 95 +` 30 2 96 +a 58 0 97 +b 58 2 98 +c 54 0 99 +d 58 2 100 +e 60 0 101 +f 40 2 102 +g 58 3 103 +h 58 2 104 +i 30 2 105 +j 30 3 106 +k 58 2 107 +l 30 2 108 +m 86 0 109 +n 58 0 110 +o 60 0 111 +p 58 1 112 +q 58 1 113 +r 38 0 114 +s 54 0 115 +t 40 2 116 +u 60 0 117 +v 54 0 118 +w 78 0 119 +x 58 0 120 +y 54 1 121 +z 50 0 122 +{ 38 3 123 +or 30 2 124 +} 38 3 125 +--- 60 0 126 +--- 32 1 161 +ct 60 2 162 +ps 60 2 163 +fr 12 2 164 +yn 60 2 165 +fn 60 3 166 +sc 60 3 167 +cr 60 0 168 +--- 30 2 169 +`` 52 2 170 +--- 42 0 171 +--- 26 0 172 +--- 26 0 173 +fi 62 2 174 +fl 60 2 175 +en 50 0 177 +\- " +dg 60 3 178 +dd 60 3 179 +--- 30 0 180 +pg 54 3 182 +--- 60 0 183 +--- 30 1 184 +--- 52 1 185 +'' 52 2 186 +--- 42 0 187 +--- 100 0 188 +--- 108 2 189 +--- 60 1 191 +ga 40 2 193 +\` " +aa 40 2 194 +\' " +^a 54 2 195 +^ " +~a 50 2 196 +~ " +-a 46 2 197 +Ua 52 2 198 +.a 28 2 199 +:a 44 2 200 +oa 34 2 202 +,a 34 1 203 +"a 60 2 205 +Ca 34 1 206 +va 54 2 207 +em 100 0 208 +--- 96 2 225 +--- 38 2 227 +--- 56 2 232 +--- 70 2 233 +--- 98 2 234 +--- 38 2 235 +--- 82 0 241 +--- 30 0 245 +--- 30 2 248 +--- 60 0 249 +--- 86 0 250 +--- 66 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/G1 b/sys/src/cmd/postscript/devpost.add/G1 new file mode 100755 index 000000000..6ad946b74 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/G1 @@ -0,0 +1,161 @@ +name G1 +fontname Garamond-Light +ligatures fi fl 0 +spacewidth 32 +charset +! 22 2 33 +" 34 2 34 +dq " +# 60 2 35 +$ 50 2 36 +% 76 2 37 +& 70 2 38 +' 22 2 39 +( 36 3 40 +) 36 3 41 +* 34 2 42 ++ 56 0 43 +, 26 1 44 +hy 32 0 45 +- " +. 26 0 46 +/ 40 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 26 0 58 +; 26 1 59 +--- 56 0 60 += 56 0 61 +--- 56 0 62 +? 30 2 63 +@ 74 3 64 +A 64 2 65 +B 64 2 66 +C 62 2 67 +D 74 2 68 +E 56 2 69 +F 52 2 70 +G 74 2 71 +H 74 2 72 +I 32 2 73 +J 32 2 74 +K 66 2 75 +L 48 2 76 +M 80 2 77 +N 70 2 78 +O 78 2 79 +P 56 2 80 +Q 78 3 81 +R 58 2 82 +S 48 2 83 +T 58 2 84 +U 70 2 85 +V 64 2 86 +W 92 2 87 +X 64 2 88 +Y 66 2 89 +Z 60 2 90 +[ 24 3 91 +\ 52 2 92 +bs " +] 24 3 93 +--- 56 2 94 +--- 50 1 95 +` 22 2 96 +a 48 0 97 +b 56 2 98 +c 46 0 99 +d 56 2 100 +e 50 0 101 +f 30 2 102 +g 52 1 103 +h 56 2 104 +i 26 2 105 +j 22 3 106 +k 54 2 107 +l 26 2 108 +m 82 0 109 +n 56 0 110 +o 56 0 111 +p 58 1 112 +q 56 1 113 +r 34 0 114 +s 40 0 115 +t 28 2 116 +u 56 0 117 +v 50 0 118 +w 78 0 119 +x 52 0 120 +y 50 1 121 +z 46 0 122 +{ 26 3 123 +--- 56 3 124 +} 26 3 125 +--- 56 0 126 +--- 22 1 161 +ct 50 2 162 +ps 64 2 163 +fr 16 2 164 +yn 66 2 165 +fn 50 3 166 +sc 36 3 167 +cr 50 2 168 +--- 20 2 169 +`` 38 2 170 +--- 26 0 171 +--- 16 0 172 +--- 16 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 40 3 178 +dd 40 3 179 +--- 26 0 180 +pg 62 3 182 +--- 62 0 183 +--- 22 1 184 +--- 36 1 185 +'' 38 2 186 +--- 26 0 187 +--- 100 0 188 +--- 108 2 189 +--- 30 1 191 +ga 36 2 193 +\` " +aa 36 2 194 +\' " +^a 42 2 195 +^ " +~a 42 2 196 +~ " +-a 38 2 197 +Ua 40 2 198 +.a 22 2 199 +:a 40 2 200 +oa 28 2 202 +,a 32 1 203 +"a 38 2 205 +Ca 30 1 206 +va 42 2 207 +em 100 0 208 +--- 94 2 225 +--- 34 2 227 +--- 48 2 232 +--- 78 2 233 +--- 100 2 234 +--- 34 2 235 +--- 74 0 241 +--- 26 0 245 +--- 26 2 248 +--- 56 0 249 +--- 88 0 250 +--- 56 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/G2 b/sys/src/cmd/postscript/devpost.add/G2 new file mode 100755 index 000000000..0f9b00008 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/G2 @@ -0,0 +1,161 @@ +name G2 +fontname Garamond-LightItalic +ligatures fi fl 0 +spacewidth 27 +charset +! 26 2 33 +" 35 2 34 +dq " +# 54 2 35 +$ 55 2 36 +% 78 2 37 +& 64 2 38 +' 25 2 39 +( 38 3 40 +) 38 3 41 +* 32 2 42 ++ 57 0 43 +, 27 1 44 +hy 33 0 45 +- " +. 27 0 46 +/ 30 2 47 +0 55 2 48 +1 55 2 49 +2 55 2 50 +3 55 2 51 +4 55 2 52 +5 55 2 53 +6 55 2 54 +7 55 2 55 +8 55 2 56 +9 55 2 57 +: 27 0 58 +; 27 1 59 +--- 57 0 60 += 57 0 61 +--- 57 0 62 +? 35 2 63 +@ 69 3 64 +A 64 2 65 +B 63 2 66 +C 63 2 67 +D 72 2 68 +E 55 2 69 +F 52 2 70 +G 71 2 71 +H 73 2 72 +I 31 2 73 +J 30 2 74 +K 63 2 75 +L 46 2 76 +M 80 2 77 +N 66 2 78 +O 72 2 79 +P 58 2 80 +Q 73 3 81 +R 58 2 82 +S 46 2 83 +T 54 2 84 +U 63 2 85 +V 62 2 86 +W 90 2 87 +X 65 2 88 +Y 58 2 89 +Z 59 2 90 +[ 23 3 91 +\ 51 2 92 +bs " +] 23 3 93 +--- 57 2 94 +--- 50 1 95 +` 25 2 96 +a 57 0 97 +b 52 2 98 +c 46 0 99 +d 57 2 100 +e 44 0 101 +f 30 2 102 +g 48 1 103 +h 56 2 104 +i 30 2 105 +j 27 3 106 +k 49 2 107 +l 26 2 108 +m 84 0 109 +n 62 0 110 +o 50 0 111 +p 51 1 112 +q 52 1 113 +r 39 0 114 +s 36 0 115 +t 28 2 116 +u 61 0 117 +v 46 0 118 +w 73 0 119 +x 53 0 120 +y 47 1 121 +z 51 0 122 +{ 26 3 123 +--- 57 3 124 +} 26 3 125 +--- 57 0 126 +--- 26 1 161 +ct 55 2 162 +ps 65 2 163 +fr 12 2 164 +yn 55 2 165 +fn 55 3 166 +sc 36 3 167 +cr 56 2 168 +--- 19 2 169 +`` 41 2 170 +--- 27 0 171 +--- 16 0 172 +--- 16 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 42 3 178 +dd 42 3 179 +--- 27 0 180 +pg 61 3 182 +--- 62 0 183 +--- 25 1 184 +--- 41 1 185 +'' 41 2 186 +--- 27 0 187 +--- 100 0 188 +--- 113 2 189 +--- 35 1 191 +ga 39 2 193 +\` " +aa 34 2 194 +\' " +^a 43 2 195 +^ " +~a 46 2 196 +~ " +-a 38 2 197 +Ua 43 2 198 +.a 21 2 199 +:a 36 2 200 +oa 29 2 202 +,a 33 1 203 +"a 32 2 205 +Ca 29 1 206 +va 43 2 207 +em 100 0 208 +--- 80 2 225 +--- 37 2 227 +--- 47 2 232 +--- 72 2 233 +--- 92 2 234 +--- 37 2 235 +--- 78 0 241 +--- 30 0 245 +--- 29 2 248 +--- 50 0 249 +--- 81 0 250 +--- 59 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/G3 b/sys/src/cmd/postscript/devpost.add/G3 new file mode 100755 index 000000000..5f6ddc970 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/G3 @@ -0,0 +1,161 @@ +name G3 +fontname Garamond-Bold +ligatures fi fl 0 +spacewidth 28 +charset +! 28 2 33 +" 40 2 34 +dq " +# 60 2 35 +$ 56 2 36 +% 88 2 37 +& 76 2 38 +' 26 2 39 +( 40 3 40 +) 40 3 41 +* 34 2 42 ++ 56 0 43 +, 28 1 44 +hy 30 0 45 +- " +. 28 0 46 +/ 44 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 56 0 60 += 56 0 61 +--- 56 0 62 +? 42 2 63 +@ 72 3 64 +A 66 2 65 +B 64 2 66 +C 66 2 67 +D 76 2 68 +E 60 2 69 +F 56 2 70 +G 72 2 71 +H 78 2 72 +I 36 2 73 +J 40 2 74 +K 74 2 75 +L 54 2 76 +M 86 2 77 +N 72 2 78 +O 76 2 79 +P 60 2 80 +Q 76 3 81 +R 66 2 82 +S 52 2 83 +T 60 2 84 +U 70 2 85 +V 64 2 86 +W 94 2 87 +X 70 2 88 +Y 68 2 89 +Z 62 2 90 +[ 28 3 91 +\ 54 2 92 +bs " +] 28 3 93 +--- 56 2 94 +--- 50 1 95 +` 26 2 96 +a 52 0 97 +b 60 2 98 +c 50 0 99 +d 60 2 100 +e 52 0 101 +f 36 2 102 +g 54 1 103 +h 66 2 104 +i 32 2 105 +j 30 3 106 +k 60 2 107 +l 32 2 108 +m 94 0 109 +n 66 0 110 +o 60 0 111 +p 64 1 112 +q 60 1 113 +r 46 0 114 +s 46 0 115 +t 34 2 116 +u 60 0 117 +v 54 0 118 +w 82 0 119 +x 62 0 120 +y 56 1 121 +z 48 0 122 +{ 28 3 123 +--- 56 3 124 +} 28 3 125 +--- 56 0 126 +--- 28 1 161 +ct 56 2 162 +ps 68 2 163 +fr 56 2 164 +yn 72 2 165 +fn 66 3 166 +sc 40 3 167 +cr 56 2 168 +--- 22 2 169 +`` 44 2 170 +--- 34 0 171 +--- 20 0 172 +--- 20 0 173 +fi 70 2 174 +fl 70 2 175 +en 50 0 177 +\- " +dg 54 3 178 +dd 54 3 179 +--- 28 0 180 +pg 66 3 182 +--- 62 0 183 +--- 26 1 184 +--- 44 1 185 +'' 44 2 186 +--- 34 0 187 +--- 100 0 188 +--- 126 2 189 +--- 42 1 191 +ga 40 2 193 +\` " +aa 40 2 194 +\' " +^a 50 2 195 +^ " +~a 52 2 196 +~ " +-a 52 2 197 +Ua 48 2 198 +.a 30 2 199 +:a 44 2 200 +oa 32 2 202 +,a 32 1 203 +"a 42 2 205 +Ca 34 1 206 +va 50 2 207 +em 100 0 208 +--- 96 2 225 +--- 36 2 227 +--- 54 2 232 +--- 76 2 233 +--- 100 2 234 +--- 36 2 235 +--- 80 0 241 +--- 32 0 245 +--- 34 2 248 +--- 60 0 249 +--- 92 0 250 +--- 64 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/G4 b/sys/src/cmd/postscript/devpost.add/G4 new file mode 100755 index 000000000..b35b361fd --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/G4 @@ -0,0 +1,161 @@ +name G4 +fontname Garamond-BoldItalic +ligatures fi fl 0 +spacewidth 28 +charset +! 24 2 33 +" 40 2 34 +dq " +# 56 2 35 +$ 56 2 36 +% 76 2 37 +& 74 2 38 +' 22 2 39 +( 48 3 40 +) 48 3 41 +* 54 2 42 ++ 56 0 43 +, 24 1 44 +hy 30 0 45 +- " +. 24 0 46 +/ 44 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 24 0 58 +; 24 1 59 +--- 56 0 60 += 56 0 61 +--- 56 0 62 +? 40 2 63 +@ 76 3 64 +A 64 2 65 +B 64 2 66 +C 64 2 67 +D 76 2 68 +E 64 2 69 +F 60 2 70 +G 72 2 71 +H 84 2 72 +I 42 2 73 +J 40 2 74 +K 76 2 75 +L 56 2 76 +M 88 2 77 +N 74 2 78 +O 74 2 79 +P 68 2 80 +Q 74 3 81 +R 72 2 82 +S 52 2 83 +T 58 2 84 +U 72 2 85 +V 64 2 86 +W 90 2 87 +X 72 2 88 +Y 62 2 89 +Z 62 2 90 +[ 34 3 91 +\ 54 2 92 +bs " +] 34 3 93 +--- 56 2 94 +--- 50 1 95 +` 22 2 96 +a 62 0 97 +b 56 2 98 +c 50 0 99 +d 62 2 100 +e 52 0 101 +f 38 2 102 +g 56 1 103 +h 64 2 104 +i 34 2 105 +j 32 3 106 +k 60 2 107 +l 28 2 108 +m 86 0 109 +n 58 0 110 +o 60 0 111 +p 64 1 112 +q 60 1 113 +r 50 0 114 +s 50 0 115 +t 34 2 116 +u 64 0 117 +v 52 0 118 +w 82 0 119 +x 66 0 120 +y 54 1 121 +z 56 0 122 +{ 34 3 123 +--- 56 3 124 +} 34 3 125 +--- 56 0 126 +--- 24 1 161 +ct 56 2 162 +ps 56 2 163 +fr 18 2 164 +yn 56 2 165 +fn 56 3 166 +sc 54 3 167 +cr 56 2 168 +--- 22 2 169 +`` 42 2 170 +--- 42 0 171 +--- 24 0 172 +--- 24 0 173 +fi 70 2 174 +fl 66 2 175 +en 50 0 177 +\- " +dg 54 3 178 +dd 54 3 179 +--- 24 0 180 +pg 70 3 182 +--- 62 0 183 +--- 22 1 184 +--- 42 1 185 +'' 42 2 186 +--- 42 0 187 +--- 100 0 188 +--- 114 2 189 +--- 40 1 191 +ga 42 2 193 +\` " +aa 38 2 194 +\' " +^a 50 2 195 +^ " +~a 56 2 196 +~ " +-a 52 2 197 +Ua 50 2 198 +.a 26 2 199 +:a 48 2 200 +oa 32 2 202 +,a 38 1 203 +"a 38 2 205 +Ca 34 1 206 +va 50 2 207 +em 100 0 208 +--- 100 2 225 +--- 40 2 227 +--- 56 2 232 +--- 76 2 233 +--- 104 2 234 +--- 38 2 235 +--- 88 0 241 +--- 34 0 245 +--- 28 2 248 +--- 60 0 249 +--- 90 0 250 +--- 64 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/Gb b/sys/src/cmd/postscript/devpost.add/Gb new file mode 100755 index 000000000..c95b5c1a8 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/Gb @@ -0,0 +1,161 @@ +name Gb +fontname Goudy-Bold +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 50 2 34 +dq " +# 61 2 35 +$ 56 2 36 +% 89 2 37 +& 89 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 50 2 42 ++ 61 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 28 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 33 0 58 +; 33 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 39 2 63 +@ 75 3 64 +A 78 2 65 +B 67 2 66 +C 72 2 67 +D 78 2 68 +E 61 2 69 +F 56 2 70 +G 78 2 71 +H 83 2 72 +I 39 2 73 +J 39 2 74 +K 72 2 75 +L 61 2 76 +M 89 2 77 +N 83 2 78 +O 78 2 79 +P 61 2 80 +Q 78 3 81 +R 72 2 82 +S 56 2 83 +T 72 2 84 +U 83 2 85 +V 78 2 86 +W 100 2 87 +X 72 2 88 +Y 67 2 89 +Z 61 2 90 +[ 33 3 91 +\ 61 2 92 +bs " +] 33 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 44 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 44 0 101 +f 33 2 102 +g 44 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 56 2 107 +l 28 2 108 +m 78 0 109 +n 56 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 39 0 114 +s 39 0 115 +t 33 2 116 +u 56 0 117 +v 50 0 118 +w 72 0 119 +x 50 0 120 +y 50 1 121 +z 39 0 122 +{ 33 3 123 +--- 61 3 124 +} 33 3 125 +--- 61 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 50 3 167 +cr 56 2 168 +--- 28 2 169 +`` 50 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 28 0 180 +pg 63 3 182 +--- 61 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 100 2 225 +--- 28 2 227 +--- 61 2 232 +--- 78 2 233 +--- 100 2 234 +--- 30 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 50 0 249 +--- 78 0 250 +--- 56 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/Gi b/sys/src/cmd/postscript/devpost.add/Gi new file mode 100755 index 000000000..ae88b7344 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/Gi @@ -0,0 +1,161 @@ +name Gi +fontname Goudy-Italic +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 44 2 34 +dq " +# 61 2 35 +$ 50 2 36 +% 83 2 37 +& 83 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 50 2 42 ++ 61 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 33 0 58 +; 33 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 39 2 63 +@ 75 3 64 +A 72 2 65 +B 61 2 66 +C 72 2 67 +D 72 2 68 +E 61 2 69 +F 56 2 70 +G 78 2 71 +H 78 2 72 +I 33 2 73 +J 33 2 74 +K 67 2 75 +L 56 2 76 +M 89 2 77 +N 78 2 78 +O 78 2 79 +P 56 2 80 +Q 78 3 81 +R 61 2 82 +S 50 2 83 +T 67 2 84 +U 78 2 85 +V 67 2 86 +W 94 2 87 +X 67 2 88 +Y 56 2 89 +Z 56 2 90 +[ 28 3 91 +\ 61 2 92 +bs " +] 28 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 44 0 97 +b 44 2 98 +c 39 0 99 +d 44 2 100 +e 39 0 101 +f 28 2 102 +g 39 1 103 +h 44 2 104 +i 22 2 105 +j 22 3 106 +k 44 2 107 +l 22 2 108 +m 72 0 109 +n 50 0 110 +o 44 0 111 +p 44 1 112 +q 44 1 113 +r 33 0 114 +s 33 0 115 +t 28 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 28 3 123 +--- 61 3 124 +} 28 3 125 +--- 61 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 61 2 168 +--- 28 2 169 +`` 44 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 33 0 180 +pg 63 3 182 +--- 61 0 183 +--- 28 1 184 +--- 44 1 185 +'' 44 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 94 2 225 +--- 50 2 227 +--- 56 2 232 +--- 78 2 233 +--- 94 2 234 +--- 50 2 235 +--- 67 0 241 +--- 22 0 245 +--- 22 2 248 +--- 44 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/Gr b/sys/src/cmd/postscript/devpost.add/Gr new file mode 100755 index 000000000..b19a6a37a --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/Gr @@ -0,0 +1,161 @@ +name Gr +fontname Goudy-Regular +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 37 2 34 +dq " +# 61 2 35 +$ 50 2 36 +% 83 2 37 +& 83 2 38 +' 22 2 39 +( 39 3 40 +) 39 3 41 +* 50 2 42 ++ 61 0 43 +, 25 1 44 +hy 33 0 45 +- " +. 25 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 25 0 58 +; 25 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 33 2 63 +@ 75 3 64 +A 78 2 65 +B 61 2 66 +C 72 2 67 +D 72 2 68 +E 56 2 69 +F 50 2 70 +G 78 2 71 +H 78 2 72 +I 33 2 73 +J 33 2 74 +K 67 2 75 +L 56 2 76 +M 89 2 77 +N 78 2 78 +O 78 2 79 +P 56 2 80 +Q 78 3 81 +R 67 2 82 +S 56 2 83 +T 67 2 84 +U 78 2 85 +V 72 2 86 +W 100 2 87 +X 67 2 88 +Y 61 2 89 +Z 56 2 90 +[ 28 3 91 +\ 61 2 92 +bs " +] 28 3 93 +--- 61 2 94 +--- 50 1 95 +` 22 2 96 +a 44 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 44 0 101 +f 28 2 102 +g 44 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 78 0 109 +n 56 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 33 0 115 +t 33 2 116 +u 50 0 117 +v 50 0 118 +w 67 0 119 +x 50 0 120 +y 44 1 121 +z 33 0 122 +{ 28 3 123 +--- 61 3 124 +} 28 3 125 +--- 61 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 22 2 169 +`` 39 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 25 0 180 +pg 63 3 182 +--- 61 0 183 +--- 22 1 184 +--- 39 1 185 +'' 39 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 33 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 100 2 225 +--- 39 2 227 +--- 56 2 232 +--- 78 2 233 +--- 100 2 234 +--- 43 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 50 0 249 +--- 78 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/Gx b/sys/src/cmd/postscript/devpost.add/Gx new file mode 100755 index 000000000..fdfd2de55 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/Gx @@ -0,0 +1,161 @@ +name Gx +fontname Goudy-BoldItalic +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 50 2 34 +dq " +# 61 2 35 +$ 56 2 36 +% 83 2 37 +& 83 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 50 2 42 ++ 61 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 33 0 58 +; 33 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 39 2 63 +@ 75 3 64 +A 72 2 65 +B 67 2 66 +C 67 2 67 +D 78 2 68 +E 67 2 69 +F 61 2 70 +G 72 2 71 +H 78 2 72 +I 39 2 73 +J 44 2 74 +K 72 2 75 +L 61 2 76 +M 94 2 77 +N 78 2 78 +O 78 2 79 +P 67 2 80 +Q 78 3 81 +R 72 2 82 +S 50 2 83 +T 72 2 84 +U 78 2 85 +V 67 2 86 +W 94 2 87 +X 72 2 88 +Y 61 2 89 +Z 61 2 90 +[ 39 3 91 +\ 61 2 92 +bs " +] 39 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 44 0 101 +f 28 2 102 +g 44 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 78 0 109 +n 56 0 110 +o 44 0 111 +p 50 1 112 +q 50 1 113 +r 39 0 114 +s 39 0 115 +t 33 2 116 +u 56 0 117 +v 44 0 118 +w 72 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 39 3 123 +--- 61 3 124 +} 39 3 125 +--- 61 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 50 3 167 +cr 61 2 168 +--- 28 2 169 +`` 50 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 33 0 180 +pg 63 3 182 +--- 61 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 89 2 225 +--- 30 2 227 +--- 61 2 232 +--- 78 2 233 +--- 94 2 234 +--- 30 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 44 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H1 b/sys/src/cmd/postscript/devpost.add/H1 new file mode 100755 index 000000000..94de6bda7 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H1 @@ -0,0 +1,161 @@ +name H1 +fontname Helvetica-Condensed-Light +ligatures fi fl 0 +spacewidth 22 +charset +! 22 2 33 +" 31 2 34 +dq " +# 44 2 35 +$ 44 2 36 +% 78 2 37 +& 61 2 38 +' 16 2 39 +( 28 3 40 +) 28 3 41 +* 39 2 42 ++ 44 0 43 +, 22 1 44 +hy 33 0 45 +- " +. 22 0 46 +/ 28 2 47 +0 44 2 48 +1 44 2 49 +2 44 2 50 +3 44 2 51 +4 44 2 52 +5 44 2 53 +6 44 2 54 +7 44 2 55 +8 44 2 56 +9 44 2 57 +: 22 0 58 +; 22 1 59 +--- 44 0 60 += 44 0 61 +--- 44 0 62 +? 39 2 63 +@ 80 3 64 +A 50 2 65 +B 50 2 66 +C 56 2 67 +D 56 2 68 +E 44 2 69 +F 44 2 70 +G 56 2 71 +H 56 2 72 +I 22 2 73 +J 39 2 74 +K 50 2 75 +L 44 2 76 +M 72 2 77 +N 56 2 78 +O 56 2 79 +P 50 2 80 +Q 56 3 81 +R 50 2 82 +S 50 2 83 +T 44 2 84 +U 56 2 85 +V 50 2 86 +W 72 2 87 +X 50 2 88 +Y 50 2 89 +Z 44 2 90 +[ 28 3 91 +\ 22 2 92 +bs " +] 28 3 93 +--- 44 2 94 +--- 50 1 95 +` 22 2 96 +a 39 0 97 +b 44 2 98 +c 39 0 99 +d 44 2 100 +e 39 0 101 +f 22 2 102 +g 44 1 103 +h 44 2 104 +i 22 2 105 +j 22 3 106 +k 39 2 107 +l 22 2 108 +m 67 0 109 +n 44 0 110 +o 44 0 111 +p 44 1 112 +q 44 1 113 +r 28 0 114 +s 39 0 115 +t 22 2 116 +u 44 0 117 +v 39 0 118 +w 56 0 119 +x 39 0 120 +y 39 1 121 +z 33 0 122 +{ 35 3 123 +--- 22 3 124 +} 35 3 125 +--- 44 0 126 +--- 22 1 161 +ct 44 2 162 +ps 44 2 163 +fr 17 2 164 +yn 44 2 165 +fn 44 3 166 +sc 44 3 167 +cr 44 2 168 +--- 20 2 169 +`` 33 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 44 2 174 +fl 44 2 175 +en 50 0 177 +\- " +dg 44 3 178 +dd 44 3 179 +--- 22 0 180 +pg 56 3 182 +--- 61 0 183 +--- 22 1 184 +--- 33 1 185 +'' 33 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 72 2 225 +--- 27 2 227 +--- 44 2 232 +--- 56 2 233 +--- 78 2 234 +--- 27 2 235 +--- 61 0 241 +--- 20 0 245 +--- 22 2 248 +--- 44 0 249 +--- 67 0 250 +--- 44 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H2 b/sys/src/cmd/postscript/devpost.add/H2 new file mode 100755 index 000000000..c67ed79bc --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H2 @@ -0,0 +1,161 @@ +name H2 +fontname Helvetica-Condensed-LightOblique +ligatures fi fl 0 +spacewidth 22 +charset +! 22 2 33 +" 31 2 34 +dq " +# 44 2 35 +$ 44 2 36 +% 78 2 37 +& 61 2 38 +' 16 2 39 +( 28 3 40 +) 28 3 41 +* 39 2 42 ++ 44 0 43 +, 22 1 44 +hy 33 0 45 +- " +. 22 0 46 +/ 28 2 47 +0 44 2 48 +1 44 2 49 +2 44 2 50 +3 44 2 51 +4 44 2 52 +5 44 2 53 +6 44 2 54 +7 44 2 55 +8 44 2 56 +9 44 2 57 +: 22 0 58 +; 22 1 59 +--- 44 0 60 += 44 0 61 +--- 44 0 62 +? 39 2 63 +@ 80 3 64 +A 50 2 65 +B 50 2 66 +C 56 2 67 +D 56 2 68 +E 44 2 69 +F 44 2 70 +G 56 2 71 +H 56 2 72 +I 22 2 73 +J 39 2 74 +K 50 2 75 +L 44 2 76 +M 72 2 77 +N 56 2 78 +O 56 2 79 +P 50 2 80 +Q 56 3 81 +R 50 2 82 +S 50 2 83 +T 44 2 84 +U 56 2 85 +V 50 2 86 +W 72 2 87 +X 50 2 88 +Y 50 2 89 +Z 44 2 90 +[ 28 3 91 +\ 22 2 92 +bs " +] 28 3 93 +--- 44 2 94 +--- 50 1 95 +` 22 2 96 +a 39 0 97 +b 44 2 98 +c 39 0 99 +d 44 2 100 +e 39 0 101 +f 22 2 102 +g 44 1 103 +h 44 2 104 +i 22 2 105 +j 22 3 106 +k 39 2 107 +l 22 2 108 +m 67 0 109 +n 44 0 110 +o 44 0 111 +p 44 1 112 +q 44 1 113 +r 28 0 114 +s 39 0 115 +t 22 2 116 +u 44 0 117 +v 39 0 118 +w 56 0 119 +x 39 0 120 +y 39 1 121 +z 33 0 122 +{ 35 3 123 +--- 22 3 124 +} 35 3 125 +--- 44 0 126 +--- 22 1 161 +ct 44 2 162 +ps 44 2 163 +fr 17 2 164 +yn 44 2 165 +fn 44 3 166 +sc 44 3 167 +cr 44 2 168 +--- 20 2 169 +`` 33 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 44 2 174 +fl 44 2 175 +en 50 0 177 +\- " +dg 44 3 178 +dd 44 3 179 +--- 22 0 180 +pg 56 3 182 +--- 61 0 183 +--- 22 1 184 +--- 33 1 185 +'' 33 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 72 2 225 +--- 27 2 227 +--- 44 2 232 +--- 56 2 233 +--- 78 2 234 +--- 27 2 235 +--- 61 0 241 +--- 20 0 245 +--- 22 2 248 +--- 44 0 249 +--- 67 0 250 +--- 44 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H3 b/sys/src/cmd/postscript/devpost.add/H3 new file mode 100755 index 000000000..bbda3bf38 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H3 @@ -0,0 +1,161 @@ +name H3 +fontname Helvetica-Condensed +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 25 2 34 +dq " +# 50 2 35 +$ 50 2 36 +% 83 2 37 +& 67 2 38 +' 22 2 39 +( 33 3 40 +) 33 3 41 +* 50 2 42 ++ 50 0 43 +, 25 1 44 +hy 33 0 45 +- " +. 25 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 25 0 58 +; 25 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 50 2 63 +@ 80 3 64 +A 56 2 65 +B 56 2 66 +C 56 2 67 +D 61 2 68 +E 50 2 69 +F 44 2 70 +G 61 2 71 +H 61 2 72 +I 28 2 73 +J 44 2 74 +K 56 2 75 +L 50 2 76 +M 78 2 77 +N 61 2 78 +O 61 2 79 +P 56 2 80 +Q 61 3 81 +R 61 2 82 +S 56 2 83 +T 50 2 84 +U 61 2 85 +V 56 2 86 +W 83 2 87 +X 56 2 88 +Y 56 2 89 +Z 50 2 90 +[ 33 3 91 +\ 25 2 92 +bs " +] 33 3 93 +--- 50 2 94 +--- 50 1 95 +` 22 2 96 +a 44 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 44 0 101 +f 28 2 102 +g 50 1 103 +h 50 2 104 +i 22 2 105 +j 22 3 106 +k 44 2 107 +l 22 2 108 +m 78 0 109 +n 50 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 44 0 115 +t 28 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 27 3 123 +--- 25 3 124 +} 27 3 125 +--- 48 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 25 2 169 +`` 39 2 170 +--- 50 0 171 +--- 28 0 172 +--- 28 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 28 0 180 +pg 44 3 182 +--- 33 0 183 +--- 22 1 184 +--- 39 1 185 +'' 39 2 186 +--- 50 0 187 +--- 100 0 188 +--- 111 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 83 2 225 +--- 30 2 227 +--- 50 2 232 +--- 61 2 233 +--- 83 2 234 +--- 30 2 235 +--- 67 0 241 +--- 22 0 245 +--- 22 2 248 +--- 50 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H4 b/sys/src/cmd/postscript/devpost.add/H4 new file mode 100755 index 000000000..7a9b2a6c0 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H4 @@ -0,0 +1,161 @@ +name H4 +fontname Helvetica-Condensed-Oblique +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 25 2 34 +dq " +# 50 2 35 +$ 50 2 36 +% 83 2 37 +& 67 2 38 +' 22 2 39 +( 33 3 40 +) 33 3 41 +* 50 2 42 ++ 50 0 43 +, 25 1 44 +hy 33 0 45 +- " +. 25 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 25 0 58 +; 25 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 50 2 63 +@ 80 3 64 +A 56 2 65 +B 56 2 66 +C 56 2 67 +D 61 2 68 +E 50 2 69 +F 44 2 70 +G 61 2 71 +H 61 2 72 +I 28 2 73 +J 44 2 74 +K 56 2 75 +L 50 2 76 +M 78 2 77 +N 61 2 78 +O 61 2 79 +P 56 2 80 +Q 61 3 81 +R 61 2 82 +S 56 2 83 +T 50 2 84 +U 61 2 85 +V 56 2 86 +W 83 2 87 +X 56 2 88 +Y 56 2 89 +Z 50 2 90 +[ 33 3 91 +\ 25 2 92 +bs " +] 33 3 93 +--- 50 2 94 +--- 50 1 95 +` 22 2 96 +a 44 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 44 0 101 +f 28 2 102 +g 50 1 103 +h 50 2 104 +i 22 2 105 +j 22 3 106 +k 44 2 107 +l 22 2 108 +m 78 0 109 +n 50 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 44 0 115 +t 28 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 27 3 123 +--- 25 3 124 +} 27 3 125 +--- 48 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 25 2 169 +`` 39 2 170 +--- 50 0 171 +--- 28 0 172 +--- 28 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 28 0 180 +pg 44 3 182 +--- 33 0 183 +--- 22 1 184 +--- 39 1 185 +'' 39 2 186 +--- 50 0 187 +--- 100 0 188 +--- 111 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 83 2 225 +--- 30 2 227 +--- 50 2 232 +--- 61 2 233 +--- 83 2 234 +--- 30 2 235 +--- 67 0 241 +--- 22 0 245 +--- 22 2 248 +--- 50 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H5 b/sys/src/cmd/postscript/devpost.add/H5 new file mode 100755 index 000000000..48a564532 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H5 @@ -0,0 +1,161 @@ +name H5 +fontname Helvetica-Condensed-Bold +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 33 2 34 +dq " +# 50 2 35 +$ 50 2 36 +% 83 2 37 +& 67 2 38 +' 28 2 39 +( 33 3 40 +) 33 3 41 +* 50 2 42 ++ 50 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 28 0 58 +; 28 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 50 2 63 +@ 83 3 64 +A 56 2 65 +B 56 2 66 +C 56 2 67 +D 61 2 68 +E 50 2 69 +F 50 2 70 +G 61 2 71 +H 61 2 72 +I 28 2 73 +J 44 2 74 +K 56 2 75 +L 50 2 76 +M 78 2 77 +N 61 2 78 +O 61 2 79 +P 56 2 80 +Q 61 3 81 +R 61 2 82 +S 56 2 83 +T 50 2 84 +U 61 2 85 +V 56 2 86 +W 83 2 87 +X 56 2 88 +Y 56 2 89 +Z 50 2 90 +[ 33 3 91 +\ 25 2 92 +bs " +] 33 3 93 +--- 50 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 50 0 101 +f 28 2 102 +g 50 1 103 +h 50 2 104 +i 28 2 105 +j 28 3 106 +k 44 2 107 +l 28 2 108 +m 78 0 109 +n 50 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 44 0 115 +t 28 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 27 3 123 +--- 25 3 124 +} 27 3 125 +--- 50 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 25 2 169 +`` 50 2 170 +--- 50 0 171 +--- 28 0 172 +--- 28 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 33 0 180 +pg 55 3 182 +--- 42 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 111 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 78 2 225 +--- 30 2 227 +--- 50 2 232 +--- 61 2 233 +--- 83 2 234 +--- 30 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 50 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H6 b/sys/src/cmd/postscript/devpost.add/H6 new file mode 100755 index 000000000..e02a0c14d --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H6 @@ -0,0 +1,161 @@ +name H6 +fontname Helvetica-Condensed-BoldOblique +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 33 2 34 +dq " +# 50 2 35 +$ 50 2 36 +% 83 2 37 +& 67 2 38 +' 28 2 39 +( 33 3 40 +) 33 3 41 +* 50 2 42 ++ 50 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 28 0 58 +; 28 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 50 2 63 +@ 83 3 64 +A 56 2 65 +B 56 2 66 +C 56 2 67 +D 61 2 68 +E 50 2 69 +F 50 2 70 +G 61 2 71 +H 61 2 72 +I 28 2 73 +J 44 2 74 +K 56 2 75 +L 50 2 76 +M 78 2 77 +N 61 2 78 +O 61 2 79 +P 56 2 80 +Q 61 3 81 +R 61 2 82 +S 56 2 83 +T 50 2 84 +U 61 2 85 +V 56 2 86 +W 83 2 87 +X 56 2 88 +Y 56 2 89 +Z 50 2 90 +[ 33 3 91 +\ 25 2 92 +bs " +] 33 3 93 +--- 50 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 50 2 98 +c 44 0 99 +d 50 2 100 +e 50 0 101 +f 28 2 102 +g 50 1 103 +h 50 2 104 +i 28 2 105 +j 28 3 106 +k 44 2 107 +l 28 2 108 +m 78 0 109 +n 50 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 44 0 115 +t 28 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 27 3 123 +--- 25 3 124 +} 27 3 125 +--- 50 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 25 2 169 +`` 50 2 170 +--- 50 0 171 +--- 28 0 172 +--- 28 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 33 0 180 +pg 55 3 182 +--- 42 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 111 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 78 2 225 +--- 30 2 227 +--- 50 2 232 +--- 61 2 233 +--- 83 2 234 +--- 30 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 50 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H7 b/sys/src/cmd/postscript/devpost.add/H7 new file mode 100755 index 000000000..8fb6c4809 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H7 @@ -0,0 +1,161 @@ +name H7 +fontname Helvetica-Condensed-Black +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 33 2 34 +dq " +# 50 2 35 +$ 50 2 36 +% 83 2 37 +& 67 2 38 +' 28 2 39 +( 28 3 40 +) 28 3 41 +* 50 2 42 ++ 50 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 28 0 58 +; 28 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 50 2 63 +@ 83 3 64 +A 56 2 65 +B 56 2 66 +C 56 2 67 +D 56 2 68 +E 50 2 69 +F 50 2 70 +G 56 2 71 +H 56 2 72 +I 28 2 73 +J 44 2 74 +K 56 2 75 +L 44 2 76 +M 78 2 77 +N 56 2 78 +O 56 2 79 +P 56 2 80 +Q 56 3 81 +R 56 2 82 +S 50 2 83 +T 50 2 84 +U 56 2 85 +V 56 2 86 +W 78 2 87 +X 56 2 88 +Y 56 2 89 +Z 44 2 90 +[ 28 3 91 +\ 25 2 92 +bs " +] 28 3 93 +--- 50 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 50 2 98 +c 50 0 99 +d 50 2 100 +e 50 0 101 +f 33 2 102 +g 50 1 103 +h 50 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 72 0 109 +n 50 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 44 0 115 +t 33 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 27 3 123 +--- 25 3 124 +} 27 3 125 +--- 50 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 25 2 169 +`` 50 2 170 +--- 50 0 171 +--- 28 0 172 +--- 28 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 33 0 180 +pg 55 3 182 +--- 42 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 111 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 78 2 225 +--- 30 2 227 +--- 44 2 232 +--- 56 2 233 +--- 78 2 234 +--- 30 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 50 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/H8 b/sys/src/cmd/postscript/devpost.add/H8 new file mode 100755 index 000000000..164aa9ad0 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/H8 @@ -0,0 +1,161 @@ +name H8 +fontname Helvetica-Condensed-BlackOblique +ligatures fi fl 0 +spacewidth 25 +charset +! 33 2 33 +" 33 2 34 +dq " +# 50 2 35 +$ 50 2 36 +% 83 2 37 +& 67 2 38 +' 28 2 39 +( 28 3 40 +) 28 3 41 +* 50 2 42 ++ 50 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 28 0 58 +; 28 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 50 2 63 +@ 83 3 64 +A 56 2 65 +B 56 2 66 +C 56 2 67 +D 56 2 68 +E 50 2 69 +F 50 2 70 +G 56 2 71 +H 56 2 72 +I 28 2 73 +J 44 2 74 +K 56 2 75 +L 44 2 76 +M 78 2 77 +N 56 2 78 +O 56 2 79 +P 56 2 80 +Q 56 3 81 +R 56 2 82 +S 50 2 83 +T 50 2 84 +U 56 2 85 +V 56 2 86 +W 78 2 87 +X 56 2 88 +Y 56 2 89 +Z 44 2 90 +[ 28 3 91 +\ 25 2 92 +bs " +] 28 3 93 +--- 50 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 50 2 98 +c 50 0 99 +d 50 2 100 +e 50 0 101 +f 33 2 102 +g 50 1 103 +h 50 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 72 0 109 +n 50 0 110 +o 50 0 111 +p 50 1 112 +q 50 1 113 +r 33 0 114 +s 44 0 115 +t 33 2 116 +u 50 0 117 +v 44 0 118 +w 67 0 119 +x 44 0 120 +y 44 1 121 +z 39 0 122 +{ 27 3 123 +--- 25 3 124 +} 27 3 125 +--- 50 0 126 +--- 33 1 161 +ct 50 2 162 +ps 50 2 163 +fr 17 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 25 2 169 +`` 50 2 170 +--- 50 0 171 +--- 28 0 172 +--- 28 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 33 0 180 +pg 55 3 182 +--- 42 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 111 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 78 2 225 +--- 30 2 227 +--- 44 2 232 +--- 56 2 233 +--- 78 2 234 +--- 30 2 235 +--- 72 0 241 +--- 28 0 245 +--- 28 2 248 +--- 50 0 249 +--- 72 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/HC b/sys/src/cmd/postscript/devpost.add/HC new file mode 100755 index 000000000..70ceee144 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/HC @@ -0,0 +1,161 @@ +name HC +fontname Helvetica-Black +ligatures fi fl 0 +spacewidth 33 +charset +! 33 2 33 +" 50 2 34 +dq " +# 66 2 35 +$ 67 2 36 +% 100 2 37 +& 89 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 56 2 42 ++ 66 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 67 2 48 +1 67 2 49 +2 67 2 50 +3 67 2 51 +4 67 2 52 +5 67 2 53 +6 67 2 54 +7 67 2 55 +8 67 2 56 +9 67 2 57 +: 33 0 58 +; 33 1 59 +--- 66 0 60 += 66 0 61 +--- 66 0 62 +? 61 2 63 +@ 74 3 64 +A 78 2 65 +B 78 2 66 +C 78 2 67 +D 78 2 68 +E 72 2 69 +F 67 2 70 +G 83 2 71 +H 83 2 72 +I 39 2 73 +J 67 2 74 +K 83 2 75 +L 67 2 76 +M 94 2 77 +N 83 2 78 +O 83 2 79 +P 72 2 80 +Q 83 3 81 +R 78 2 82 +S 72 2 83 +T 72 2 84 +U 83 2 85 +V 78 2 86 +W 100 2 87 +X 78 2 88 +Y 78 2 89 +Z 72 2 90 +[ 39 3 91 +\ 28 2 92 +bs " +] 39 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 67 0 97 +b 67 2 98 +c 67 0 99 +d 67 2 100 +e 67 0 101 +f 38 2 102 +g 67 1 103 +h 67 2 104 +i 33 2 105 +j 33 3 106 +k 67 2 107 +l 33 2 108 +m 100 0 109 +n 67 0 110 +o 67 0 111 +p 67 1 112 +q 67 1 113 +r 44 0 114 +s 61 0 115 +t 44 2 116 +u 67 0 117 +v 61 0 118 +w 94 0 119 +x 67 0 120 +y 61 1 121 +z 56 0 122 +{ 39 3 123 +--- 28 3 124 +} 39 3 125 +--- 66 0 126 +--- 33 1 161 +ct 67 2 162 +ps 67 2 163 +fr 17 2 164 +yn 67 2 165 +fn 67 3 166 +sc 67 3 167 +cr 66 2 168 +--- 28 2 169 +`` 50 2 170 +--- 67 0 171 +--- 33 0 172 +--- 33 0 173 +fi 67 2 174 +fl 67 2 175 +en 50 0 177 +\- " +dg 67 3 178 +dd 67 3 179 +--- 33 0 180 +pg 85 3 182 +--- 50 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 67 0 187 +--- 100 0 188 +--- 100 2 189 +--- 61 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 100 2 225 +--- 40 2 227 +--- 67 2 232 +--- 83 2 233 +--- 100 2 234 +--- 40 2 235 +--- 100 0 241 +--- 33 0 245 +--- 33 2 248 +--- 67 0 249 +--- 100 0 250 +--- 67 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/HK b/sys/src/cmd/postscript/devpost.add/HK new file mode 100755 index 000000000..1008dfaa3 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/HK @@ -0,0 +1,161 @@ +name HK +fontname Helvetica-LightOblique +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 28 2 34 +dq " +# 66 2 35 +$ 56 2 36 +% 89 2 37 +& 67 2 38 +' 22 2 39 +( 33 3 40 +) 33 3 41 +* 39 2 42 ++ 66 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 28 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 66 0 60 += 66 0 61 +--- 66 0 62 +? 50 2 63 +@ 80 3 64 +A 67 2 65 +B 67 2 66 +C 72 2 67 +D 72 2 68 +E 61 2 69 +F 56 2 70 +G 78 2 71 +H 72 2 72 +I 28 2 73 +J 50 2 74 +K 67 2 75 +L 56 2 76 +M 83 2 77 +N 72 2 78 +O 78 2 79 +P 61 2 80 +Q 78 3 81 +R 67 2 82 +S 61 2 83 +T 56 2 84 +U 72 2 85 +V 61 2 86 +W 89 2 87 +X 61 2 88 +Y 61 2 89 +Z 61 2 90 +[ 33 3 91 +\ 28 2 92 +bs " +] 33 3 93 +--- 66 2 94 +--- 50 1 95 +` 22 2 96 +a 56 0 97 +b 61 2 98 +c 56 0 99 +d 61 2 100 +e 56 0 101 +f 28 2 102 +g 61 1 103 +h 56 2 104 +i 22 2 105 +j 22 3 106 +k 50 2 107 +l 22 2 108 +m 83 0 109 +n 56 0 110 +o 56 0 111 +p 61 1 112 +q 61 1 113 +r 33 0 114 +s 50 0 115 +t 28 2 116 +u 56 0 117 +v 50 0 118 +w 72 0 119 +x 50 0 120 +y 50 1 121 +z 50 0 122 +{ 33 3 123 +--- 22 3 124 +} 33 3 125 +--- 66 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 56 3 167 +cr 56 2 168 +--- 22 2 169 +`` 39 2 170 +--- 56 0 171 +--- 39 0 172 +--- 39 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 56 3 178 +dd 56 3 179 +--- 28 0 180 +pg 65 3 182 +--- 50 0 183 +--- 22 1 184 +--- 39 1 185 +'' 39 2 186 +--- 56 0 187 +--- 100 0 188 +--- 100 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 100 2 225 +--- 33 2 227 +--- 56 2 232 +--- 78 2 233 +--- 100 2 234 +--- 33 2 235 +--- 89 0 241 +--- 22 0 245 +--- 22 2 248 +--- 56 0 249 +--- 94 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/HL b/sys/src/cmd/postscript/devpost.add/HL new file mode 100755 index 000000000..349335db3 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/HL @@ -0,0 +1,161 @@ +name HL +fontname Helvetica-Light +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 28 2 34 +dq " +# 66 2 35 +$ 56 2 36 +% 89 2 37 +& 67 2 38 +' 22 2 39 +( 33 3 40 +) 33 3 41 +* 39 2 42 ++ 66 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 28 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 66 0 60 += 66 0 61 +--- 66 0 62 +? 50 2 63 +@ 80 3 64 +A 67 2 65 +B 67 2 66 +C 72 2 67 +D 72 2 68 +E 61 2 69 +F 56 2 70 +G 78 2 71 +H 72 2 72 +I 28 2 73 +J 50 2 74 +K 67 2 75 +L 56 2 76 +M 83 2 77 +N 72 2 78 +O 78 2 79 +P 61 2 80 +Q 78 3 81 +R 67 2 82 +S 61 2 83 +T 56 2 84 +U 72 2 85 +V 61 2 86 +W 89 2 87 +X 61 2 88 +Y 61 2 89 +Z 61 2 90 +[ 33 3 91 +\ 28 2 92 +bs " +] 33 3 93 +--- 66 2 94 +--- 50 1 95 +` 22 2 96 +a 56 0 97 +b 61 2 98 +c 56 0 99 +d 61 2 100 +e 56 0 101 +f 28 2 102 +g 61 1 103 +h 56 2 104 +i 22 2 105 +j 22 3 106 +k 50 2 107 +l 22 2 108 +m 83 0 109 +n 56 0 110 +o 56 0 111 +p 61 1 112 +q 61 1 113 +r 33 0 114 +s 50 0 115 +t 28 2 116 +u 56 0 117 +v 50 0 118 +w 72 0 119 +x 50 0 120 +y 50 1 121 +z 50 0 122 +{ 33 3 123 +--- 22 3 124 +} 33 3 125 +--- 66 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 56 3 167 +cr 56 2 168 +--- 22 2 169 +`` 39 2 170 +--- 56 0 171 +--- 39 0 172 +--- 39 0 173 +fi 50 2 174 +fl 50 2 175 +en 50 0 177 +\- " +dg 56 3 178 +dd 56 3 179 +--- 28 0 180 +pg 65 3 182 +--- 50 0 183 +--- 22 1 184 +--- 39 1 185 +'' 39 2 186 +--- 56 0 187 +--- 100 0 188 +--- 100 2 189 +--- 50 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 100 2 225 +--- 33 2 227 +--- 56 2 232 +--- 78 2 233 +--- 100 2 234 +--- 33 2 235 +--- 89 0 241 +--- 22 0 245 +--- 22 2 248 +--- 56 0 249 +--- 94 0 250 +--- 50 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/HY b/sys/src/cmd/postscript/devpost.add/HY new file mode 100755 index 000000000..7a050d65b --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/HY @@ -0,0 +1,161 @@ +name HY +fontname Helvetica-BlackOblique +ligatures fi fl 0 +spacewidth 33 +charset +! 33 2 33 +" 50 2 34 +dq " +# 66 2 35 +$ 67 2 36 +% 100 2 37 +& 89 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 56 2 42 ++ 66 0 43 +, 33 1 44 +hy 33 0 45 +- " +. 33 0 46 +/ 28 2 47 +0 67 2 48 +1 67 2 49 +2 67 2 50 +3 67 2 51 +4 67 2 52 +5 67 2 53 +6 67 2 54 +7 67 2 55 +8 67 2 56 +9 67 2 57 +: 33 0 58 +; 33 1 59 +--- 66 0 60 += 66 0 61 +--- 66 0 62 +? 61 2 63 +@ 74 3 64 +A 78 2 65 +B 78 2 66 +C 78 2 67 +D 78 2 68 +E 72 2 69 +F 67 2 70 +G 83 2 71 +H 83 2 72 +I 39 2 73 +J 67 2 74 +K 83 2 75 +L 67 2 76 +M 94 2 77 +N 83 2 78 +O 83 2 79 +P 72 2 80 +Q 83 3 81 +R 78 2 82 +S 72 2 83 +T 72 2 84 +U 83 2 85 +V 78 2 86 +W 100 2 87 +X 78 2 88 +Y 78 2 89 +Z 72 2 90 +[ 39 3 91 +\ 28 2 92 +bs " +] 39 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 67 0 97 +b 67 2 98 +c 67 0 99 +d 67 2 100 +e 67 0 101 +f 38 2 102 +g 67 1 103 +h 67 2 104 +i 33 2 105 +j 33 3 106 +k 67 2 107 +l 33 2 108 +m 100 0 109 +n 67 0 110 +o 67 0 111 +p 67 1 112 +q 67 1 113 +r 44 0 114 +s 61 0 115 +t 44 2 116 +u 67 0 117 +v 61 0 118 +w 94 0 119 +x 67 0 120 +y 61 1 121 +z 56 0 122 +{ 39 3 123 +--- 28 3 124 +} 39 3 125 +--- 66 0 126 +--- 33 1 161 +ct 67 2 162 +ps 67 2 163 +fr 17 2 164 +yn 67 2 165 +fn 67 3 166 +sc 67 3 167 +cr 66 2 168 +--- 28 2 169 +`` 50 2 170 +--- 67 0 171 +--- 33 0 172 +--- 33 0 173 +fi 67 2 174 +fl 67 2 175 +en 50 0 177 +\- " +dg 67 3 178 +dd 67 3 179 +--- 33 0 180 +pg 85 3 182 +--- 50 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 67 0 187 +--- 100 0 188 +--- 100 2 189 +--- 61 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 100 2 225 +--- 40 2 227 +--- 67 2 232 +--- 83 2 233 +--- 100 2 234 +--- 40 2 235 +--- 100 0 241 +--- 33 0 245 +--- 33 2 248 +--- 67 0 249 +--- 100 0 250 +--- 67 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/MU b/sys/src/cmd/postscript/devpost.add/MU new file mode 100755 index 000000000..7be9d2a75 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/MU @@ -0,0 +1,173 @@ +fontname Sonata +name MU +charset +--- 15 0 32 +--- 21 0 33 +--- 51 2 34 +--- 22 1 35 +--- 51 3 36 +--- 52 1 37 +--- 61 3 38 +--- 13 0 39 +--- 17 2 40 +--- 17 2 41 +--- 36 0 42 +--- 30 0 43 +--- 18 1 44 +--- 30 0 45 +--- 9 0 46 +--- 17 2 47 +--- 36 1 48 +--- 25 1 49 +--- 34 1 50 +--- 32 1 51 +--- 33 1 52 +--- 30 1 53 +--- 33 1 54 +--- 34 1 55 +--- 33 1 56 +--- 33 1 57 +--- 15 1 58 +--- 27 2 59 +--- 100 2 61 +--- 42 0 62 +--- 69 2 63 +--- 20 0 64 +--- 30 1 65 +--- 67 2 66 +--- 42 1 67 +--- 81 0 68 +--- 30 1 69 +--- 83 2 70 +--- 15 0 71 +--- 30 1 72 +--- 11 0 73 +--- 0 1 74 +--- 0 1 75 +--- 41 1 76 +--- 59 0 77 +--- 30 0 79 +--- 80 1 80 +--- 30 3 81 +--- 20 3 82 +--- 60 3 83 +--- 62 0 84 +--- 66 2 85 +--- 72 2 86 +--- 61 0 87 +--- 30 1 88 +--- 56 1 89 +--- 65 3 90 +--- 15 2 91 +--- 0 2 92 +--- 46 2 93 +--- 6 2 94 +--- 50 0 95 +--- 50 0 96 +--- 30 3 97 +--- 20 3 98 +--- 42 1 99 +--- 75 0 100 +--- 55 3 101 +--- 52 3 102 +--- 14 2 103 +--- 30 3 104 +--- 10 1 105 +--- 0 2 106 +--- 0 2 107 +--- 4 2 108 +--- 6 0 109 +--- 18 1 110 +--- 12 1 111 +--- 45 1 112 +--- 30 3 113 +--- 56 3 114 +--- 23 0 115 +--- 52 2 116 +--- 66 1 117 +--- 26 2 118 +--- 41 0 119 +--- 56 3 120 +--- 30 3 121 +--- 29 0 122 +--- 13 2 123 +--- 0 1 124 +--- 46 2 125 +--- 34 0 126 +--- 17 2 160 +--- 79 2 161 +--- 25 0 162 +--- 24 0 163 +--- 21 0 164 +--- 26 0 165 +--- 23 0 166 +--- 30 3 167 +--- 21 3 168 +--- 15 2 169 +--- 25 0 170 +--- 8 2 172 +--- 30 0 173 +--- 13 0 174 +--- 30 1 175 +--- 23 0 176 +--- 30 1 177 +--- 30 0 178 +--- 34 0 179 +--- 30 3 180 +--- 85 0 181 +--- 31 0 183 +--- 120 1 184 +--- 82 1 185 +--- 37 1 186 +--- 22 0 187 +--- 23 0 188 +--- 48 0 189 +--- 30 2 190 +--- 30 3 191 +--- 30 0 192 +--- 20 0 193 +--- 41 2 194 +--- 57 2 195 +--- 78 3 196 +--- 14 1 197 +--- 56 3 198 +--- 0 0 199 +--- 0 1 200 +--- 28 2 201 +--- 28 0 202 +--- 26 1 206 +--- 30 0 207 +--- 30 0 208 +--- 30 0 209 +--- 26 2 210 +--- 46 2 211 +--- 61 2 212 +--- 28 2 214 +--- 56 2 215 +--- 47 2 217 +--- 56 2 218 +--- 27 0 220 +--- 50 2 221 +--- 44 1 222 +--- 23 0 224 +--- 30 1 225 +--- 30 1 226 +--- 15 0 227 +--- 7 1 228 +--- 35 3 229 +--- 56 1 231 +--- 28 0 232 +--- 9 1 233 +--- 30 3 234 +--- 105 3 236 +--- 15 1 237 +--- 31 0 238 +--- 30 1 239 +--- 0 2 240 +--- 4 2 241 +--- 37 2 242 +--- 28 0 243 +--- 28 3 244 +--- 0 0 246 +--- 30 0 250 +--- 0 1 251 diff --git a/sys/src/cmd/postscript/devpost.add/OA b/sys/src/cmd/postscript/devpost.add/OA new file mode 100755 index 000000000..a5d5e6a78 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/OA @@ -0,0 +1,161 @@ +fontname Optima-Regular +name OA +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 33 2 34 +dq " +# 61 2 35 +$ 56 2 36 +% 89 2 37 +& 72 2 38 +' 28 2 39 +( 28 3 40 +) 28 3 41 +* 44 2 42 ++ 61 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 28 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 39 2 63 +@ 80 3 64 +A 67 2 65 +B 61 2 66 +C 67 2 67 +D 78 2 68 +E 50 2 69 +F 50 2 70 +G 78 2 71 +H 78 2 72 +I 28 2 73 +J 28 2 74 +K 61 2 75 +L 50 2 76 +M 89 2 77 +N 78 2 78 +O 83 2 79 +P 56 2 80 +Q 83 3 81 +R 61 2 82 +S 50 2 83 +T 56 2 84 +U 78 2 85 +V 67 2 86 +W 100 2 87 +X 61 2 88 +Y 61 2 89 +Z 61 2 90 +[ 33 3 91 +\ 50 2 92 +bs " +] 33 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 56 2 98 +c 50 0 99 +d 56 2 100 +e 50 0 101 +f 28 2 102 +g 50 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 83 0 109 +n 56 0 110 +o 56 0 111 +p 56 1 112 +q 56 1 113 +r 33 0 114 +s 39 0 115 +t 28 2 116 +u 56 0 117 +v 50 0 118 +w 78 0 119 +x 50 0 120 +y 50 1 121 +z 50 0 122 +{ 33 3 123 +--- 33 3 124 +} 33 3 125 +--- 61 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 50 3 167 +cr 56 2 168 +--- 28 2 169 +`` 44 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 28 0 180 +pg 80 3 182 +--- 61 0 183 +--- 28 1 184 +--- 44 1 185 +'' 44 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 83 2 225 +--- 32 2 227 +--- 50 2 232 +--- 83 2 233 +--- 100 2 234 +--- 34 2 235 +--- 78 0 241 +--- 28 0 245 +--- 28 2 248 +--- 56 0 249 +--- 89 0 250 +--- 56 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/OB b/sys/src/cmd/postscript/devpost.add/OB new file mode 100755 index 000000000..e6564bf95 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/OB @@ -0,0 +1,161 @@ +name OB +fontname Optima-Bold +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 33 2 34 +dq " +# 61 2 35 +$ 56 2 36 +% 100 2 37 +& 72 2 38 +' 28 2 39 +( 33 3 40 +) 33 3 41 +* 44 2 42 ++ 61 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 39 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 44 2 63 +@ 75 3 64 +A 67 2 65 +B 61 2 66 +C 67 2 67 +D 78 2 68 +E 50 2 69 +F 50 2 70 +G 78 2 71 +H 78 2 72 +I 33 2 73 +J 33 2 74 +K 61 2 75 +L 50 2 76 +M 89 2 77 +N 78 2 78 +O 83 2 79 +P 56 2 80 +Q 83 3 81 +R 61 2 82 +S 50 2 83 +T 56 2 84 +U 78 2 85 +V 67 2 86 +W 100 2 87 +X 61 2 88 +Y 61 2 89 +Z 61 2 90 +[ 33 3 91 +\ 52 2 92 +bs " +] 33 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 56 2 98 +c 50 0 99 +d 56 2 100 +e 50 0 101 +f 32 2 102 +g 50 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 83 0 109 +n 56 0 110 +o 56 0 111 +p 56 1 112 +q 56 1 113 +r 39 0 114 +s 39 0 115 +t 33 2 116 +u 56 0 117 +v 50 0 118 +w 78 0 119 +x 50 0 120 +y 50 1 121 +z 50 0 122 +{ 33 3 123 +--- 61 3 124 +} 33 3 125 +--- 61 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 56 3 167 +cr 56 2 168 +--- 28 2 169 +`` 50 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 61 2 174 +fl 61 2 175 +en 50 0 177 +\- " +dg 56 3 178 +dd 56 3 179 +--- 28 0 180 +pg 70 3 182 +--- 61 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 44 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 89 2 225 +--- 33 2 227 +--- 50 2 232 +--- 83 2 233 +--- 100 2 234 +--- 34 2 235 +--- 78 0 241 +--- 28 0 245 +--- 28 2 248 +--- 56 0 249 +--- 89 0 250 +--- 56 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/OI b/sys/src/cmd/postscript/devpost.add/OI new file mode 100755 index 000000000..2297e422f --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/OI @@ -0,0 +1,161 @@ +name OI +fontname Optima-Oblique +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 33 2 34 +dq " +# 61 2 35 +$ 56 2 36 +% 89 2 37 +& 72 2 38 +' 28 2 39 +( 28 3 40 +) 28 3 41 +* 44 2 42 ++ 61 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 28 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 39 2 63 +@ 80 3 64 +A 67 2 65 +B 61 2 66 +C 67 2 67 +D 78 2 68 +E 50 2 69 +F 50 2 70 +G 78 2 71 +H 78 2 72 +I 28 2 73 +J 28 2 74 +K 61 2 75 +L 50 2 76 +M 89 2 77 +N 78 2 78 +O 83 2 79 +P 56 2 80 +Q 83 3 81 +R 61 2 82 +S 50 2 83 +T 56 2 84 +U 78 2 85 +V 67 2 86 +W 100 2 87 +X 61 2 88 +Y 61 2 89 +Z 61 2 90 +[ 33 3 91 +\ 50 2 92 +bs " +] 33 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 56 2 98 +c 50 0 99 +d 56 2 100 +e 50 0 101 +f 28 2 102 +g 50 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 83 0 109 +n 56 0 110 +o 56 0 111 +p 56 1 112 +q 56 1 113 +r 33 0 114 +s 39 0 115 +t 28 2 116 +u 56 0 117 +v 50 0 118 +w 78 0 119 +x 50 0 120 +y 50 1 121 +z 50 0 122 +{ 33 3 123 +--- 33 3 124 +} 33 3 125 +--- 61 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 50 3 167 +cr 56 2 168 +--- 28 2 169 +`` 44 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 56 2 174 +fl 56 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 28 0 180 +pg 80 3 182 +--- 61 0 183 +--- 28 1 184 +--- 44 1 185 +'' 44 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 39 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 83 2 225 +--- 32 2 227 +--- 50 2 232 +--- 83 2 233 +--- 100 2 234 +--- 34 2 235 +--- 78 0 241 +--- 28 0 245 +--- 28 2 248 +--- 56 0 249 +--- 89 0 250 +--- 56 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/OX b/sys/src/cmd/postscript/devpost.add/OX new file mode 100755 index 000000000..622dd6792 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/OX @@ -0,0 +1,161 @@ +name OX +fontname Optima-BoldOblique +ligatures fi fl 0 +spacewidth 28 +charset +! 33 2 33 +" 33 2 34 +dq " +# 61 2 35 +$ 56 2 36 +% 100 2 37 +& 72 2 38 +' 28 2 39 +( 33 3 40 +) 33 3 41 +* 44 2 42 ++ 61 0 43 +, 28 1 44 +hy 33 0 45 +- " +. 28 0 46 +/ 39 2 47 +0 56 2 48 +1 56 2 49 +2 56 2 50 +3 56 2 51 +4 56 2 52 +5 56 2 53 +6 56 2 54 +7 56 2 55 +8 56 2 56 +9 56 2 57 +: 28 0 58 +; 28 1 59 +--- 61 0 60 += 61 0 61 +--- 61 0 62 +? 44 2 63 +@ 75 3 64 +A 67 2 65 +B 61 2 66 +C 67 2 67 +D 78 2 68 +E 50 2 69 +F 50 2 70 +G 78 2 71 +H 78 2 72 +I 33 2 73 +J 33 2 74 +K 61 2 75 +L 50 2 76 +M 89 2 77 +N 78 2 78 +O 83 2 79 +P 56 2 80 +Q 83 3 81 +R 61 2 82 +S 50 2 83 +T 56 2 84 +U 78 2 85 +V 67 2 86 +W 100 2 87 +X 61 2 88 +Y 61 2 89 +Z 61 2 90 +[ 33 3 91 +\ 52 2 92 +bs " +] 33 3 93 +--- 61 2 94 +--- 50 1 95 +` 28 2 96 +a 50 0 97 +b 56 2 98 +c 50 0 99 +d 56 2 100 +e 50 0 101 +f 32 2 102 +g 50 1 103 +h 56 2 104 +i 28 2 105 +j 28 3 106 +k 50 2 107 +l 28 2 108 +m 83 0 109 +n 56 0 110 +o 56 0 111 +p 56 1 112 +q 56 1 113 +r 39 0 114 +s 39 0 115 +t 33 2 116 +u 56 0 117 +v 50 0 118 +w 78 0 119 +x 50 0 120 +y 50 1 121 +z 50 0 122 +{ 33 3 123 +--- 61 3 124 +} 33 3 125 +--- 61 0 126 +--- 33 1 161 +ct 56 2 162 +ps 56 2 163 +fr 17 2 164 +yn 56 2 165 +fn 56 3 166 +sc 56 3 167 +cr 56 2 168 +--- 28 2 169 +`` 50 2 170 +--- 50 0 171 +--- 33 0 172 +--- 33 0 173 +fi 61 2 174 +fl 61 2 175 +en 50 0 177 +\- " +dg 56 3 178 +dd 56 3 179 +--- 28 0 180 +pg 70 3 182 +--- 61 0 183 +--- 28 1 184 +--- 50 1 185 +'' 50 2 186 +--- 50 0 187 +--- 100 0 188 +--- 100 2 189 +--- 44 1 191 +ga 33 2 193 +\` " +aa 33 2 194 +\' " +^a 33 2 195 +^ " +~a 33 2 196 +~ " +-a 33 2 197 +Ua 33 2 198 +.a 33 2 199 +:a 33 2 200 +oa 33 2 202 +,a 33 1 203 +"a 33 2 205 +Ca 33 1 206 +va 33 2 207 +em 100 0 208 +--- 89 2 225 +--- 33 2 227 +--- 50 2 232 +--- 83 2 233 +--- 100 2 234 +--- 34 2 235 +--- 78 0 241 +--- 28 0 245 +--- 28 2 248 +--- 56 0 249 +--- 89 0 250 +--- 56 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/a1 b/sys/src/cmd/postscript/devpost.add/a1 new file mode 100755 index 000000000..9d50cb4d5 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/a1 @@ -0,0 +1,161 @@ +name a1 +fontname CenturyOldStyleAbstract-Regular +ligatures fi fl 0 +spacewidth 25 +charset +! 26 2 33 +" 40 2 34 +dq " +# 50 2 35 +$ 50 3 36 +% 58 2 37 +& 79 2 38 +' 21 2 39 +( 40 3 40 +) 40 3 41 +* 50 2 42 ++ 50 0 43 +, 25 1 44 +hy 24 0 45 +- " +. 25 0 46 +/ 53 3 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 25 0 58 +; 25 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 40 2 63 +@ 85 2 64 +A 66 2 65 +B 69 2 66 +C 69 2 67 +D 76 2 68 +E 66 2 69 +F 61 2 70 +G 74 2 71 +H 76 2 72 +I 34 2 73 +J 40 3 74 +K 71 2 75 +L 58 2 76 +M 95 2 77 +N 76 2 78 +O 76 2 79 +P 61 2 80 +Q 76 3 81 +R 63 2 82 +S 55 2 83 +T 63 2 84 +U 74 2 85 +V 66 2 86 +W 95 2 87 +X 63 2 88 +Y 63 2 89 +Z 58 2 90 +[ 40 3 91 +\ 25 2 92 +bs " +] 40 3 93 +--- 50 2 94 +--- 50 1 95 +` 21 2 96 +a 47 0 97 +b 55 2 98 +c 47 0 99 +d 55 2 100 +e 50 0 101 +f 29 2 102 +g 55 1 103 +h 58 2 104 +i 26 2 105 +j 24 3 106 +k 55 2 107 +l 26 2 108 +m 84 0 109 +n 55 0 110 +o 53 0 111 +p 53 1 112 +q 55 1 113 +r 40 0 114 +s 45 0 115 +t 31 2 116 +u 55 0 117 +v 47 0 118 +w 71 0 119 +x 53 0 120 +y 50 1 121 +z 45 0 122 +{ 40 3 123 +--- 25 2 124 +} 40 3 125 +--- 50 0 126 +--- 26 1 161 +ct 50 2 162 +ps 50 2 163 +fr 9 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 21 2 169 +`` 40 2 170 +--- 47 0 171 +--- 29 0 172 +--- 29 0 173 +fi 58 2 174 +fl 55 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 25 0 180 +pg 66 3 182 +--- 66 0 183 +--- 21 1 184 +--- 40 1 185 +'' 40 2 186 +--- 47 0 187 +--- 100 0 188 +--- 92 2 189 +--- 40 1 191 +ga 29 2 193 +\` " +aa 29 2 194 +\' " +^a 37 2 195 +^ " +~a 50 2 196 +~ " +-a 47 2 197 +Ua 50 2 198 +.a 26 2 199 +:a 47 2 200 +oa 34 2 202 +,a 34 1 203 +"a 40 2 205 +Ca 37 1 206 +va 37 2 207 +em 100 0 208 +--- 103 2 225 +--- 34 2 227 +--- 58 2 232 +--- 76 2 233 +--- 108 2 234 +--- 34 2 235 +--- 76 0 241 +--- 26 0 245 +--- 26 2 248 +--- 53 0 249 +--- 84 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/a2 b/sys/src/cmd/postscript/devpost.add/a2 new file mode 100755 index 000000000..0f133dacd --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/a2 @@ -0,0 +1,161 @@ +name a2 +fontname CenturyOldStyleAbstract-Italic +ligatures fi fl 0 +spacewidth 27 +charset +! 31 2 33 +" 35 2 34 +dq " +# 54 0 35 +$ 54 3 36 +% 70 2 37 +& 75 2 38 +' 21 2 39 +( 46 3 40 +) 46 3 41 +* 59 2 42 ++ 54 0 43 +, 27 1 44 +hy 25 0 45 +- " +. 27 0 46 +/ 46 3 47 +0 54 2 48 +1 54 0 49 +2 54 2 50 +3 54 2 51 +4 54 0 52 +5 54 0 53 +6 54 2 54 +7 54 0 55 +8 54 2 56 +9 54 2 57 +: 27 0 58 +; 27 1 59 +--- 54 0 60 += 54 0 61 +--- 54 0 62 +? 48 2 63 +@ 78 2 64 +A 67 2 65 +B 68 2 66 +C 65 2 67 +D 75 2 68 +E 66 2 69 +F 61 2 70 +G 72 2 71 +H 77 2 72 +I 36 2 73 +J 34 3 74 +K 68 2 75 +L 58 2 76 +M 90 2 77 +N 74 2 78 +O 74 2 79 +P 59 2 80 +Q 75 3 81 +R 65 2 82 +S 57 2 83 +T 63 2 84 +U 72 2 85 +V 62 2 86 +W 88 2 87 +X 64 2 88 +Y 61 2 89 +Z 57 2 90 +[ 46 3 91 +\ 27 2 92 +bs " +] 46 3 93 +--- 54 2 94 +--- 50 1 95 +` 21 2 96 +a 54 0 97 +b 46 2 98 +c 41 0 99 +d 50 2 100 +e 42 0 101 +f 25 3 102 +g 45 1 103 +h 52 2 104 +i 31 2 105 +j 27 3 106 +k 48 2 107 +l 27 2 108 +m 82 0 109 +n 56 0 110 +o 47 0 111 +p 50 1 112 +q 49 1 113 +r 40 0 114 +s 35 0 115 +t 30 0 116 +u 56 0 117 +v 47 0 118 +w 69 0 119 +x 41 0 120 +y 40 1 121 +z 39 0 122 +{ 46 3 123 +--- 27 2 124 +} 46 3 125 +--- 54 0 126 +--- 31 1 161 +ct 54 0 162 +ps 54 2 163 +fr 5 2 164 +yn 54 0 165 +fn 54 3 166 +sc 59 3 167 +cr 54 0 168 +--- 19 2 169 +`` 37 2 170 +--- 45 0 171 +--- 29 0 172 +--- 29 0 173 +fi 52 3 174 +fl 52 3 175 +en 50 0 177 +\- " +dg 59 3 178 +dd 59 3 179 +--- 27 0 180 +pg 61 3 182 +--- 61 0 183 +--- 21 1 184 +--- 37 1 185 +'' 37 2 186 +--- 45 0 187 +--- 100 0 188 +--- 103 2 189 +--- 48 1 191 +ga 39 2 193 +\` " +aa 31 2 194 +\' " +^a 40 2 195 +^ " +~a 51 2 196 +~ " +-a 47 0 197 +Ua 51 2 198 +.a 26 2 199 +:a 46 2 200 +oa 32 2 202 +,a 35 1 203 +"a 39 2 205 +Ca 34 1 206 +va 40 2 207 +em 100 0 208 +--- 94 2 225 +--- 32 2 227 +--- 58 2 232 +--- 74 2 233 +--- 107 2 234 +--- 32 2 235 +--- 69 0 241 +--- 31 0 245 +--- 27 2 248 +--- 47 0 249 +--- 71 0 250 +--- 53 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/c1 b/sys/src/cmd/postscript/devpost.add/c1 new file mode 100755 index 000000000..19be6b2fd --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/c1 @@ -0,0 +1,161 @@ +name C1 +fontname CenturyOldStyle-Regular +ligatures fi fl 0 +spacewidth 25 +charset +! 26 2 33 +" 40 2 34 +dq " +# 50 2 35 +$ 50 3 36 +% 58 2 37 +& 79 2 38 +' 21 2 39 +( 40 3 40 +) 40 3 41 +* 50 2 42 ++ 50 0 43 +, 25 1 44 +hy 24 0 45 +- " +. 25 0 46 +/ 53 3 47 +0 50 2 48 +1 50 2 49 +2 50 2 50 +3 50 2 51 +4 50 2 52 +5 50 2 53 +6 50 2 54 +7 50 2 55 +8 50 2 56 +9 50 2 57 +: 25 0 58 +; 25 1 59 +--- 50 0 60 += 50 0 61 +--- 50 0 62 +? 40 2 63 +@ 85 2 64 +A 66 2 65 +B 69 2 66 +C 69 2 67 +D 76 2 68 +E 66 2 69 +F 61 2 70 +G 74 2 71 +H 76 2 72 +I 34 2 73 +J 40 3 74 +K 71 2 75 +L 58 2 76 +M 95 2 77 +N 76 2 78 +O 76 2 79 +P 61 2 80 +Q 76 3 81 +R 63 2 82 +S 55 2 83 +T 63 2 84 +U 74 2 85 +V 66 2 86 +W 95 2 87 +X 63 2 88 +Y 63 2 89 +Z 58 2 90 +[ 40 3 91 +\ 25 2 92 +bs " +] 40 3 93 +--- 50 2 94 +--- 50 1 95 +` 21 2 96 +a 47 0 97 +b 55 2 98 +c 47 0 99 +d 55 2 100 +e 50 0 101 +f 29 2 102 +g 55 1 103 +h 58 2 104 +i 26 2 105 +j 24 3 106 +k 55 2 107 +l 26 2 108 +m 84 0 109 +n 55 0 110 +o 53 0 111 +p 53 1 112 +q 55 1 113 +r 40 0 114 +s 45 0 115 +t 31 2 116 +u 55 0 117 +v 47 0 118 +w 71 0 119 +x 53 0 120 +y 50 1 121 +z 45 0 122 +{ 40 3 123 +--- 25 2 124 +} 40 3 125 +--- 50 0 126 +--- 26 1 161 +ct 50 2 162 +ps 50 2 163 +fr 9 2 164 +yn 50 2 165 +fn 50 3 166 +sc 50 3 167 +cr 50 2 168 +--- 21 2 169 +`` 40 2 170 +--- 47 0 171 +--- 29 0 172 +--- 29 0 173 +fi 58 2 174 +fl 55 2 175 +en 50 0 177 +\- " +dg 50 3 178 +dd 50 3 179 +--- 25 0 180 +pg 66 3 182 +--- 66 0 183 +--- 21 1 184 +--- 40 1 185 +'' 40 2 186 +--- 47 0 187 +--- 100 0 188 +--- 92 2 189 +--- 40 1 191 +ga 29 2 193 +\` " +aa 29 2 194 +\' " +^a 37 2 195 +^ " +~a 50 2 196 +~ " +-a 47 2 197 +Ua 50 2 198 +.a 26 2 199 +:a 47 2 200 +oa 34 2 202 +,a 34 1 203 +"a 40 2 205 +Ca 37 1 206 +va 37 2 207 +em 100 0 208 +--- 103 2 225 +--- 34 2 227 +--- 58 2 232 +--- 76 2 233 +--- 108 2 234 +--- 34 2 235 +--- 76 0 241 +--- 26 0 245 +--- 26 2 248 +--- 53 0 249 +--- 84 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/c2 b/sys/src/cmd/postscript/devpost.add/c2 new file mode 100755 index 000000000..359341a67 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/c2 @@ -0,0 +1,161 @@ +name C2 +fontname CenturyOldStyle-Italic +ligatures fi fl 0 +spacewidth 27 +charset +! 31 2 33 +" 35 2 34 +dq " +# 54 0 35 +$ 54 3 36 +% 70 2 37 +& 75 2 38 +' 21 2 39 +( 46 3 40 +) 46 3 41 +* 59 2 42 ++ 54 0 43 +, 27 1 44 +hy 25 0 45 +- " +. 27 0 46 +/ 46 3 47 +0 54 2 48 +1 54 0 49 +2 54 2 50 +3 54 2 51 +4 54 0 52 +5 54 0 53 +6 54 2 54 +7 54 0 55 +8 54 2 56 +9 54 2 57 +: 27 0 58 +; 27 1 59 +--- 54 0 60 += 54 0 61 +--- 54 0 62 +? 48 2 63 +@ 78 2 64 +A 67 2 65 +B 68 2 66 +C 65 2 67 +D 75 2 68 +E 66 2 69 +F 61 2 70 +G 72 2 71 +H 77 2 72 +I 36 2 73 +J 34 3 74 +K 68 2 75 +L 58 2 76 +M 90 2 77 +N 74 2 78 +O 74 2 79 +P 59 2 80 +Q 75 3 81 +R 65 2 82 +S 57 2 83 +T 63 2 84 +U 72 2 85 +V 62 2 86 +W 88 2 87 +X 64 2 88 +Y 61 2 89 +Z 57 2 90 +[ 46 3 91 +\ 27 2 92 +bs " +] 46 3 93 +--- 54 2 94 +--- 50 1 95 +` 21 2 96 +a 54 0 97 +b 46 2 98 +c 41 0 99 +d 50 2 100 +e 42 0 101 +f 25 3 102 +g 45 1 103 +h 52 2 104 +i 31 2 105 +j 27 3 106 +k 48 2 107 +l 27 2 108 +m 82 0 109 +n 56 0 110 +o 47 0 111 +p 50 1 112 +q 49 1 113 +r 40 0 114 +s 35 0 115 +t 30 0 116 +u 56 0 117 +v 47 0 118 +w 69 0 119 +x 41 0 120 +y 40 1 121 +z 39 0 122 +{ 46 3 123 +--- 27 2 124 +} 46 3 125 +--- 54 0 126 +--- 31 1 161 +ct 54 0 162 +ps 54 2 163 +fr 5 2 164 +yn 54 0 165 +fn 54 3 166 +sc 59 3 167 +cr 54 0 168 +--- 19 2 169 +`` 37 2 170 +--- 45 0 171 +--- 29 0 172 +--- 29 0 173 +fi 52 3 174 +fl 52 3 175 +en 50 0 177 +\- " +dg 59 3 178 +dd 59 3 179 +--- 27 0 180 +pg 61 3 182 +--- 61 0 183 +--- 21 1 184 +--- 37 1 185 +'' 37 2 186 +--- 45 0 187 +--- 100 0 188 +--- 103 2 189 +--- 48 1 191 +ga 39 2 193 +\` " +aa 31 2 194 +\' " +^a 40 2 195 +^ " +~a 51 2 196 +~ " +-a 47 0 197 +Ua 51 2 198 +.a 26 2 199 +:a 46 2 200 +oa 32 2 202 +,a 35 1 203 +"a 39 2 205 +Ca 34 1 206 +va 40 2 207 +em 100 0 208 +--- 94 2 225 +--- 32 2 227 +--- 58 2 232 +--- 74 2 233 +--- 107 2 234 +--- 32 2 235 +--- 69 0 241 +--- 31 0 245 +--- 27 2 248 +--- 47 0 249 +--- 71 0 250 +--- 53 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/c3 b/sys/src/cmd/postscript/devpost.add/c3 new file mode 100755 index 000000000..eef7eef09 --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/c3 @@ -0,0 +1,161 @@ +name C3 +fontname CenturyOldStyle-Bold +ligatures fi fl 0 +spacewidth 33 +charset +! 34 2 33 +" 40 2 34 +dq " +# 56 2 35 +$ 66 3 36 +% 79 2 37 +& 84 2 38 +' 28 2 39 +( 39 3 40 +) 39 3 41 +* 56 2 42 ++ 56 0 43 +, 33 1 44 +hy 32 0 45 +- " +. 33 0 46 +/ 51 3 47 +0 66 2 48 +1 66 2 49 +2 66 2 50 +3 66 2 51 +4 66 2 52 +5 66 2 53 +6 66 2 54 +7 66 2 55 +8 66 2 56 +9 66 2 57 +: 33 0 58 +; 33 1 59 +--- 56 0 60 += 56 0 61 +--- 56 0 62 +? 47 2 63 +@ 72 2 64 +A 69 2 65 +B 76 2 66 +C 70 2 67 +D 80 2 68 +E 71 2 69 +F 64 2 70 +G 78 2 71 +H 83 2 72 +I 41 2 73 +J 48 2 74 +K 76 2 75 +L 63 2 76 +M 94 2 77 +N 80 2 78 +O 81 2 79 +P 72 2 80 +Q 81 3 81 +R 72 2 82 +S 61 2 83 +T 60 2 84 +U 78 2 85 +V 64 2 86 +W 97 2 87 +X 68 2 88 +Y 67 2 89 +Z 59 2 90 +[ 39 3 91 +\ 28 2 92 +bs " +] 39 3 93 +--- 56 2 94 +--- 50 1 95 +` 28 2 96 +a 53 0 97 +b 60 2 98 +c 52 0 99 +d 62 2 100 +e 54 0 101 +f 30 2 102 +g 52 3 103 +h 62 2 104 +i 31 2 105 +j 27 3 106 +k 60 2 107 +l 30 2 108 +m 92 0 109 +n 62 0 110 +o 57 0 111 +p 61 1 112 +q 60 1 113 +r 44 0 114 +s 50 0 115 +t 33 2 116 +u 63 0 117 +v 50 0 118 +w 74 0 119 +x 53 0 120 +y 49 1 121 +z 44 0 122 +{ 39 3 123 +--- 28 2 124 +} 39 3 125 +--- 56 0 126 +--- 34 1 161 +ct 66 2 162 +ps 66 2 163 +fr 10 2 164 +yn 66 2 165 +fn 66 3 166 +sc 56 3 167 +cr 66 2 168 +--- 22 2 169 +`` 52 2 170 +--- 58 0 171 +--- 37 0 172 +--- 37 0 173 +fi 62 2 174 +fl 61 2 175 +en 50 0 177 +\- " +dg 56 3 178 +dd 56 3 179 +--- 33 0 180 +pg 62 3 182 +--- 62 0 183 +--- 28 1 184 +--- 52 1 185 +'' 52 2 186 +--- 58 0 187 +--- 100 0 188 +--- 118 2 189 +--- 47 1 191 +ga 34 2 193 +\` " +aa 34 2 194 +\' " +^a 45 2 195 +^ " +~a 56 2 196 +~ " +-a 53 2 197 +Ua 56 2 198 +.a 29 2 199 +:a 51 2 200 +oa 34 2 202 +,a 37 1 203 +"a 50 2 205 +Ca 38 1 206 +va 45 2 207 +em 100 0 208 +--- 109 2 225 +--- 40 2 227 +--- 63 2 232 +--- 81 2 233 +--- 114 2 234 +--- 40 2 235 +--- 83 0 241 +--- 31 0 245 +--- 30 2 248 +--- 57 0 249 +--- 90 0 250 +--- 58 2 251 diff --git a/sys/src/cmd/postscript/devpost.add/devpost.add.mk b/sys/src/cmd/postscript/devpost.add/devpost.add.mk new file mode 100755 index 000000000..2a6b9ebeb --- /dev/null +++ b/sys/src/cmd/postscript/devpost.add/devpost.add.mk @@ -0,0 +1,49 @@ +MAKE=/bin/make +MAKEFILE=devpost.add.mk + +SYSTEM=SYSV +VERSION=3.2 + +GROUP=bin +OWNER=bin + +FONTDIR=/usr/lib/font +FONTFILES=?? + +all : + +install : all + @if [ ! -d $(FONTDIR) ]; then \ + mkdir $(FONTDIR); \ + chmod 755 $(FONTDIR); \ + chgrp $(GROUP) $(FONTDIR); \ + chown $(OWNER) $(FONTDIR); \ + fi + @if [ ! -d $(FONTDIR)/devpost ]; then \ + mkdir $(FONTDIR)/devpost; \ + chmod 755 $(FONTDIR)/devpost; \ + chgrp $(GROUP) $(FONTDIR)/devpost; \ + chown $(OWNER) $(FONTDIR)/devpost; \ + fi + cp $(FONTFILES) $(FONTDIR)/devpost + @for i in $(FONTFILES); do \ + chmod 644 $(FONTDIR)/devpost/$$i; \ + chgrp $(GROUP) $(FONTDIR)/devpost/$$i; \ + chown $(OWNER) $(FONTDIR)/devpost/$$i; \ + done + +clean : + +clobber : clean + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^FONTDIR=.*'FONTDIR=$(FONTDIR)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE) + diff --git a/sys/src/cmd/postscript/download/README b/sys/src/cmd/postscript/download/README new file mode 100755 index 000000000..9bfce12a8 --- /dev/null +++ b/sys/src/cmd/postscript/download/README @@ -0,0 +1,11 @@ + +A simple program that scans PostScript files for %%DocumentFonts: +comments and prepends requested host resident font files to the +input. Written for Unix 4.0 lp. + +Downloaded fonts are the ones named in the %%DocumentFonts: comment +and listed in a special map file (which can be selected using the +-m option). See example.map and comments in download.c for examples +of map files. By default map files and font files are in *hostfontdir. +It's initialized using HOSTDIR (file ../common/path.h). + diff --git a/sys/src/cmd/postscript/download/download.c b/sys/src/cmd/postscript/download/download.c new file mode 100755 index 000000000..78a0341cf --- /dev/null +++ b/sys/src/cmd/postscript/download/download.c @@ -0,0 +1,543 @@ +/* + * + * download - host resident font downloader + * + * Prepends host resident fonts to PostScript input files. The program assumes + * the input files are part of a single PostScript job and that requested fonts + * can be downloaded at the start of each input file. Downloaded fonts are the + * ones named in a %%DocumentFonts: comment and listed in a special map table. + * Map table pathnames (supplied using the -m option) that begin with a / are + * taken as is. Otherwise the final pathname is built using *hostfontdir (-H + * option), *mapname (-m option), and *suffix. + * + * The map table consists of fontname-filename pairs, separated by white space. + * Comments are introduced by % (as in PostScript) and extend to the end of the + * current line. The only fonts that can be downloaded are the ones listed in + * the active map table that point the program to a readable Unix file. A request + * for an unlisted font or inaccessible file is ignored. All font requests are + * ignored if the map table can't be read. In that case the program simply copies + * the input files to stdout. + * + * An example (but not one to follow) of what can be in a map table is, + * + * % + * % Map requests for Bookman-Light to file *hostfontdir/KR + * % + * + * Bookman-Light KR % Keeping everything (including the map + * % table) in *hostfontdir seems like the + * % cleanest approach. + * + * % + * % Map Palatino-Roman to file *hostfontdir/palatino/Roman + * % + * Palatino-Roman palatino/Roman + * + * % Map ZapfDingbats to file /usr/lib/host/dingbats + * + * ZapfDingbats /usr/lib/host/dingbats + * + * Once again, file names that begin with a / are taken as is. All others have + * *hostfontdir/ prepended to the file string associated with a particular font. + * + * Map table can be associated with a printer model (e.g. a LaserWriter), a + * printer destination, or whatever - the choice is up to an administrator. + * By destination may be best if your spooler is running several private + * printers. Host resident fonts are usually purchased under a license that + * restricts their use to a limited number of printers. A font licensed for + * a single printer should only be used on that printer. + * + * Was written quickly, so there's much room for improvement. Undoubtedly should + * be a more general program (e.g. scan for other comments). + * + */ + +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <string.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for temporary directory */ +#include "ext.h" /* external variable declarations */ +#include "download.h" /* a few special definitions */ + +char *temp_dir = TEMPDIR; /* temp directory - for copying stdin */ +char *hostfontdir = HOSTDIR; /* host resident directory */ +char *mapname = "map"; /* map table - usually in *hostfontdir */ +char *suffix = ""; /* appended to the map table pathname */ +Map *map = NULL; /* device font map table */ +char *stringspace = NULL; /* for storing font and file strings */ +int next = 0; /* next free slot in map[] */ + +char *residentfonts = NULL; /* list of printer resident fonts */ +char *printer = NULL; /* printer name - only for Unix 4.0 lp */ + +char buf[2048]; /* input file line buffer */ +char *comment = DOCUMENTFONTS; /* look for this comment */ +int atend = FALSE; /* TRUE only if a comment says so */ + +FILE *fp_in = stdin; /* next input file */ +FILE *fp_temp = NULL; /* for copying stdin */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * Host resident font downloader. The input files are assumed to be part of a + * single PostScript job. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* just for error messages */ + + init_signals(); /* sets up interrupt handling */ + options(); /* first get command line options */ + readmap(); /* read the font map table */ + readresident(); /* and the optional resident font list */ + arguments(); /* then process non-option arguments */ + done(); /* and clean things up */ + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Makes sure we handle interrupts properly. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + char *optnames = "c:fm:p:r:H:T:DI"; + + extern char *optarg; /* used by getopt() */ + extern int optind; + +/* + * + * Reads and processes the command line options. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'c': /* look for this comment */ + comment = optarg; + break; + + case 'f': /* force a complete input file scan */ + atend = TRUE; + break; + + case 'm': /* printer map table name */ + mapname = optarg; + break; + + case 'p': /* printer name - for Unix 4.0 lp */ + printer = optarg; + break; + + case 'r': /* resident font list */ + residentfonts = optarg; + break; + + case 'H': /* host resident font directory */ + hostfontdir = optarg; + break; + + case 'T': /* temporary file directory */ + temp_dir = optarg; + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +readmap() + +{ + + char *path; + char *ptr; + int fd; + struct stat sbuf; + +/* + * + * Initializes the map table by reading an ASCII mapping file. If mapname begins + * with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are + * combined to build the final pathname. If we can open the file we read it all + * into memory, erase comments, and separate the font and file name pairs. When + * we leave next points to the next free slot in the map[] array. If it's zero + * nothing was in the file or we couldn't open it. + * + */ + + if ( hostfontdir == NULL || mapname == NULL ) + return; + + if ( *mapname != '/' ) { + if ( (path = (char *)malloc(strlen(hostfontdir) + strlen(mapname) + + strlen(suffix) + 2)) == NULL ) + error(FATAL, "no memory"); + sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix); + } else path = mapname; + + if ( (fd = open(path, 0)) != -1 ) { + if ( fstat(fd, &sbuf) == -1 ) + error(FATAL, "can't fstat %s", path); + if ( (stringspace = (char *)malloc(sbuf.st_size + 2)) == NULL ) + error(FATAL, "no memory"); + if ( read(fd, stringspace, sbuf.st_size) == -1 ) + error(FATAL, "can't read %s", path); + close(fd); + + stringspace[sbuf.st_size] = '\n'; /* just to be safe */ + stringspace[sbuf.st_size+1] = '\0'; + for ( ptr = stringspace; *ptr != '\0'; ptr++ ) /* erase comments */ + if ( *ptr == '%' ) + for ( ; *ptr != '\n' ; ptr++ ) + *ptr = ' '; + + for ( ptr = stringspace; ; next++ ) { + if ( (next % 50) == 0 ) + map = allocate(map, next+50); + map[next].downloaded = FALSE; + map[next].font = strtok(ptr, " \t\n"); + map[next].file = strtok(ptr = NULL, " \t\n"); + if ( map[next].font == NULL ) + break; + if ( map[next].file == NULL ) + error(FATAL, "map table format error - check %s", path); + } /* End for */ + } /* End if */ + +} /* End of readmap */ + +/*****************************************************************************/ + +readresident() + +{ + + FILE *fp; + char *path; + int ch; + int n; + +/* + * + * Reads a file that lists the resident fonts for a particular printer and marks + * each font as already downloaded. Nothing's done if the file can't be read or + * there's no mapping file. Comments, as in the map file, begin with a % and + * extend to the end of the line. Added for Unix 4.0 lp. + * + */ + + if ( next == 0 || (printer == NULL && residentfonts == NULL) ) + return; + + if ( printer != NULL ) { /* use Unix 4.0 lp pathnames */ + sprintf(buf, "%s/printers/%s", HOSTDIR, printer); + path = buf; + } else path = residentfonts; + + if ( (fp = fopen(path, "r")) != NULL ) { + while ( fscanf(fp, "%s", buf) != EOF ) + if ( buf[0] == '%' ) + while ( (ch = getc(fp)) != EOF && ch != '\n' ) ; + else if ( (n = lookup(buf)) < next ) + map[n].downloaded = TRUE; + fclose(fp); + } /* End if */ + +} /* End of readresident */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll translate stdin. Assumes input files are part of a single PostScript + * job and fonts can be downloaded at the start of each file. + * + */ + + if ( argc < 1 ) + download(); + else { + while ( argc > 0 ) { + fp_temp = NULL; + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + download(); + if ( fp_in != stdin ) + fclose(fp_in); + if ( fp_temp != NULL ) + fclose(fp_temp); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Clean things up before we quit. + * + */ + + if ( temp_file != NULL ) + unlink(temp_file); + +} /* End of done */ + +/*****************************************************************************/ + +download() + +{ + + int infontlist = FALSE; + +/* + * + * If next is zero the map table is empty and all we do is copy the input file + * to stdout. Otherwise we read the input file looking for %%DocumentFonts: or + * continuation comments, add any accessible fonts to the output file, and then + * append the input file. When reading stdin we append lines to fp_temp and + * recover them when we're ready to copy the input file. fp_temp will often + * only contain part of stdin - if there's no %%DocumentFonts: (atend) comment + * we stop reading fp_in after the header. + * + */ + + if ( next > 0 ) { + if ( fp_in == stdin ) { + if ( (temp_file = tempnam(temp_dir, "post")) == NULL ) + error(FATAL, "can't generate temp file name"); + if ( (fp_temp = fopen(temp_file, "w+r")) == NULL ) + error(FATAL, "can't open %s", temp_file); + unlink(temp_file); + } /* End if */ + + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) { + if ( fp_temp != NULL ) + fprintf(fp_temp, "%s", buf); + if ( buf[0] != '%' || buf[1] != '%' ) { + if ( (buf[0] != '%' || buf[1] != '!') && atend == FALSE ) + break; + infontlist = FALSE; + } else if ( strncmp(buf, comment, strlen(comment)) == 0 ) { + copyfonts(buf); + infontlist = TRUE; + } else if ( buf[2] == '+' && infontlist == TRUE ) + copyfonts(buf); + else infontlist = FALSE; + } /* End while */ + } /* End if */ + + copyinput(); + +} /* End of download */ + +/*****************************************************************************/ + +copyfonts(list) + + char *list; + +{ + + char *font; + char *path; + int n; + +/* + * + * list points to a %%DocumentFonts: or continuation comment. What follows the + * the keyword will be a list of fonts separated by white space (or (atend)). + * Look for each font in the map table and if it's found copy the font file to + * stdout (once only). + * + */ + + strtok(list, " \n"); /* skip to the font list */ + + while ( (font = strtok(NULL, " \t\n")) != NULL ) { + if ( strcmp(font, ATEND) == 0 ) { + atend = TRUE; + break; + } /* End if */ + if ( (n = lookup(font)) < next ) { + if ( *map[n].file != '/' ) { + if ( (path = (char *)malloc(strlen(hostfontdir)+strlen(map[n].file)+2)) == NULL ) + error(FATAL, "no memory"); + sprintf(path, "%s/%s", hostfontdir, map[n].file); + cat(path); + free(path); + } else cat(map[n].file); + map[n].downloaded = TRUE; + } /* End if */ + } /* End while */ + +} /* End of copyfonts */ + +/*****************************************************************************/ + +copyinput() + +{ + +/* + * + * Copies the input file to stdout. If fp_temp isn't NULL seek to the start and + * add it to the output file - it's a partial (or complete) copy of stdin made + * by download(). Then copy fp_in, but only seek to the start if it's not stdin. + * + */ + + if ( fp_temp != NULL ) { + fseek(fp_temp, 0L, 0); + while ( fgets(buf, sizeof(buf), fp_temp) != NULL ) + printf("%s", buf); + } /* End if */ + + if ( fp_in != stdin ) + fseek(fp_in, 0L, 0); + + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) + printf("%s", buf); + +} /* End of copyinput */ + +/*****************************************************************************/ + +lookup(font) + + char *font; + +{ + + int i; + +/* + * + * Looks for *font in the map table. Return the map table index if found and + * not yet downloaded - otherwise return next. + * + */ + + for ( i = 0; i < next; i++ ) + if ( strcmp(font, map[i].font) == 0 ) { + if ( map[i].downloaded == TRUE ) + i = next; + break; + } /* End if */ + + return(i); + +} /* End of lookup */ + +/*****************************************************************************/ + +Map *allocate(ptr, num) + + Map *ptr; + int num; + +{ + +/* + * + * Allocates space for num Map elements. Calls malloc() if ptr is NULL and + * realloc() otherwise. + * + */ + + if ( ptr == NULL ) + ptr = (Map *)malloc(num * sizeof(Map)); + else ptr = (Map *)realloc(ptr, num * sizeof(Map)); + + if ( ptr == NULL ) + error(FATAL, "no map memory"); + + return(ptr); + +} /* End of allocate */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/download/download.h b/sys/src/cmd/postscript/download/download.h new file mode 100755 index 000000000..f88cc57ad --- /dev/null +++ b/sys/src/cmd/postscript/download/download.h @@ -0,0 +1,14 @@ +/* + * + * The font data for a printer is saved in an array of the following type. + * + */ + +typedef struct map { + char *font; /* a request for this PostScript font */ + char *file; /* means copy this unix file */ + int downloaded; /* TRUE after *file is downloaded */ +} Map; + +Map *allocate(); + diff --git a/sys/src/cmd/postscript/download/mkfile b/sys/src/cmd/postscript/download/mkfile new file mode 100755 index 000000000..a153f5b6c --- /dev/null +++ b/sys/src/cmd/postscript/download/mkfile @@ -0,0 +1,27 @@ +</$objtype/mkfile + +<../config +TARG=download + +OFILES=download.$O + +COMMONDIR=../common + +HFILES=download.h\ + $COMMONDIR/comments.h\ + $COMMONDIR/gen.h\ + $COMMONDIR/path.h\ + $COMMONDIR/ext.h\ + +LIB=$COMMONDIR/com.a$O +BIN=$POSTBIN + +</sys/src/cmd/mkone +CC=pcc +LD=pcc +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B + +$LIB: + cd $COMMONDIR + mk install + mk clean diff --git a/sys/src/cmd/postscript/g3p9bit/btab b/sys/src/cmd/postscript/g3p9bit/btab new file mode 100755 index 000000000..45ca2c80a --- /dev/null +++ b/sys/src/cmd/postscript/g3p9bit/btab @@ -0,0 +1,109 @@ +{"0000110111", 0}, +{"010", 1}, +{"11", 2}, +{"10", 3}, +{"011", 4}, +{"0011", 5}, +{"0010", 6}, +{"00011", 7}, +{"000101", 8}, +{"000100", 9}, +{"0000100", 10}, +{"0000101", 11}, +{"0000111", 12}, +{"00000100", 13}, +{"00000111", 14}, +{"000011000", 15}, +{"0000010111", 16}, +{"0000011000", 17}, +{"0000001000", 18}, +{"00001100111", 19}, +{"00001101000", 20}, +{"00001101100", 21}, +{"00000110111", 22}, +{"00000101000", 23}, +{"00000010111", 24}, +{"00000011000", 25}, +{"000011001010", 26}, +{"000011001011", 27}, +{"000011001100", 28}, +{"000011001101", 29}, +{"000001101000", 30}, +{"000001101001", 31}, +{"000001101010", 32}, +{"000001101011", 33}, +{"000011010010", 34}, +{"000011010011", 35}, +{"000011010100", 36}, +{"000011010101", 37}, +{"000011010110", 38}, +{"000011010111", 39}, +{"000001101100", 40}, +{"000001101101", 41}, +{"000011011010", 42}, +{"000011011011", 43}, +{"000001010100", 44}, +{"000001010101", 45}, +{"000001010110", 46}, +{"000001010111", 47}, +{"000001100100", 48}, +{"000001100101", 49}, +{"000001010010", 50}, +{"000001010011", 51}, +{"000000100100", 52}, +{"000000110111", 53}, +{"000000111000", 54}, +{"000000100111", 55}, +{"000000101000", 56}, +{"000001011000", 57}, +{"000001011001", 58}, +{"000000101011", 59}, +{"000000101100", 60}, +{"000001011010", 61}, +{"000001100110", 62}, +{"000001100111", 63}, + +{"0000001111", 64}, +{"000011001000", 128}, +{"000011001001", 192}, +{"000001011011", 256}, +{"000000110011", 320}, +{"000000110100", 384}, +{"000000110101", 448}, +{"0000001101100", 512}, +{"0000001101101", 576}, +{"0000001001010", 640}, +{"0000001001011", 704}, +{"0000001001100", 768}, +{"0000001001101", 832}, +{"0000001110010", 896}, +{"0000001110011", 960}, +{"0000001110100", 1024}, +{"0000001110101", 1088}, +{"0000001110110", 1152}, +{"0000001110111", 1216}, +{"0000001010010", 1280}, +{"0000001010011", 1344}, +{"0000001010100", 1408}, +{"0000001010101", 1472}, +{"0000001011010", 1536}, +{"0000001011011", 1600}, +{"0000001100100", 1664}, +{"0000001100101", 1728}, + +{"00000001000", 1792}, +{"00000001100", 1856}, +{"00000001101", 1920}, +{"000000010010", 1984}, +{"000000010011", 2048}, +{"000000010100", 2112}, +{"000000010101", 2176}, +{"000000010110", 2240}, +{"000000010111", 2304}, +{"000000011100", 2368}, +{"000000011101", 2432}, +{"000000011110", 2496}, +{"000000011111", 2560}, + +{"000000000001", -1}, +{"000000000000", -2}, diff --git a/sys/src/cmd/postscript/g3p9bit/g3p9bit.c b/sys/src/cmd/postscript/g3p9bit/g3p9bit.c new file mode 100755 index 000000000..2650d8b08 --- /dev/null +++ b/sys/src/cmd/postscript/g3p9bit/g3p9bit.c @@ -0,0 +1,455 @@ +#include <u.h> +#include <libc.h> + +enum +{ + ERR, + EOL, + MAKE, + TERM, +}; + +enum +{ + White, + Black, +}; + +typedef struct Tab +{ + ushort run; + ushort bits; + int code; +} Tab; + +Tab wtab[8192]; +Tab btab[8192]; +uchar bitrev[256]; +uchar bitnonrev[256]; + +int readrow(uchar *rev, int*); +void initwbtab(void); +void sync(uchar*); +int readfile(int, char*, char*); + +int nbytes; +uchar *bytes; +uchar *pixels; +uchar *buf; +int y; +uint bitoffset; +uint word24; + +enum +{ + Bytes = 1024*1024, + Lines = 1410, /* 1100 for A4, 1410 for B4 */ + Dots = 1728, +}; + +void +error(char *fmt, ...) +{ + char buf[256]; + va_list arg; + + if(fmt){ + va_start(arg, fmt); + vseprint(buf, buf+sizeof buf, fmt, arg); + va_end(arg); + fprint(2, "g3: %s\n", buf); + } + exits(fmt); +} + +void +usage(void) +{ + fprint(2, "usage: g3p9bit [-gy] file\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int y, fd, n, m; + char *t; + char *file, err[ERRMAX], tbuf[5*12+1]; + int gray=0; + int yscale=1; + + ARGBEGIN{ + case 'g': + /* do simulated 2bit gray to compress x */ + gray++; + break; + case 'y': + /* double each scan line to double the y resolution */ + yscale=2; + break; + default: + usage(); + }ARGEND + + if(argc > 1) + usage(); + + initwbtab(); + buf = malloc(1024*1024); + t = malloc((Dots/8)*Lines); + if(buf==nil || t==nil) + error("malloc failed: %r\n"); + pixels = (uchar*)t; + + file = "<stdin>"; + fd = 0; + if(argc > 0){ + file = argv[0]; + fd = open(file, OREAD); + if(fd < 0) + error("can't open %s", file); + } + y = readfile(fd, file, err); + if(y < 0) + error(err); + sprint(tbuf, "%11d %11d %11d %11d %11d ", gray, 0, 0, Dots/(gray+1), y*yscale); + write(1, tbuf, 5*12); + n = (Dots/8)*y*yscale; + /* write in pieces; brazil pipes work badly with huge counts */ + while(n > 0){ + if(yscale > 1) /* write one scan line */ + m = Dots/8; + else{ /* write lots */ + m = n; + if(m > 8192) + m = 8192; + } + for(y=0; y<yscale; y++){ + if(write(1, t, m) != m) + error("write error"); + n -= m; + } + t += m; + } + if(err[0]) + error(err); + error(nil); +} + +enum{ + Hvres, + Hbaud, + Hwidth, + Hlength, + Hcomp, + HenabECM, + HenabBFT, + Hmsperscan, +}; + +int defhdr[8] = { + 0, /* 98 lpi */ + 0, /* 2400 baud */ + 0, /* 1728 pixels in 215mm */ + 0, /* A4, 297mm */ + 0, /* 1-D modified huffman */ + 0, /* disable ECM */ + 0, /* disable BFT */ + 3, /* 10 ms per scan */ +}; + +int +crackhdr(uchar *ap, int *hdr) +{ + char *p, *q; + int i; + + p = (char*)ap; + q = p; + for(i=0; i<8; i++){ + if(*p<'0' || '9'<*p) + return -1; + hdr[i] = strtol(p, &q, 0); + p = q+1; + } + return p-(char*)ap; +} + +int +readfile(int f, char *file, char *err) +{ + int i, r, lines; + uchar *rev; + int hdr[8]; + + err[0] = 0; + memset(pixels, 0, (Dots/8) * Lines); + nbytes = readn(f, buf, 1024*1024); + if(nbytes==1024*1024 || nbytes<=100){ + bad: + sprint(err, "g3: file improper size or format: %s", file); + return -1; + } + bytes = buf; + if(bytes[0]=='I' && bytes[1]=='I' && bytes[2]=='*'){ /* dumb PC format */ + bytes += 0xf3; + nbytes -= 0xf3; + rev = bitrev; + memmove(hdr, defhdr, sizeof defhdr); + }else if(bytes[0] == 0 && strcmp((char*)bytes+1, "PC Research, Inc") == 0){ /* digifax format */ + memmove(hdr, defhdr, sizeof defhdr); + if(bytes[45] == 0x40 && bytes[29] == 1) /* high resolution */ + hdr[Hvres] = 1; + else + hdr[Hvres] = 0; + /* hdr[26] | (hdr[27]<<8) is page number */ + + bytes += 64; + nbytes -= 64; + rev = bitnonrev; + }else{ + while(nbytes > 2){ + if(bytes[0]=='\n'){ + if(strncmp((char*)bytes+1, "FDCS=", 5) == 0){ + i = crackhdr(bytes+6, hdr); + if(i < 0){ + sprint(err, "g3: bad FDCS in header: %s", file); + return -1; + } + if(hdr[Hwidth] != 0){ + sprint(err, "g3: unsupported width: %s", file); + return -1; + } + if(hdr[Hcomp] != 0){ + sprint(err, "g3: unsupported compression: %s", file); + return -1; + } + bytes += i+1; + nbytes -= i+1; + continue; + } + if(bytes[1] == '\n'){ + bytes += 2; + nbytes -= 2; + break; + } + } + bytes++; + nbytes--; + } + if(nbytes < 2) + goto bad; + rev = bitnonrev; + } + bitoffset = 24; + word24 = 0; + sync(rev); + lines = Lines; + if(hdr[Hvres] == 1) + lines *= 2; + for(y=0; y<lines; y++){ + r = readrow(rev, hdr); + if(r < 0) + break; + if(r == 0) + sync(rev); + } + if(hdr[Hvres] == 1) + y /= 2; +// if(y < 100) +// goto bad; + return y; +} + +int +readrow(uchar *rev, int *hdr) +{ + int bo, state; + Tab *tab, *t; + int x, oldx, x2, oldx2, dx, xx; + uint w24; + uchar *p, *q; + + state = White; + oldx = 0; + bo = bitoffset; + w24 = word24; + x = y; + if(hdr[Hvres] == 1) /* high resolution */ + x /= 2; + p = pixels + x*Dots/8; + x = 0; + +loop: + if(x > Dots) + return 0; + if(state == White) + tab = wtab; + else + tab = btab; + if(bo > (24-13)) { + do { + if(nbytes <= 0) + return -1; + w24 = (w24<<8) | rev[*bytes]; + bo -= 8; + bytes++; + nbytes--; + } while(bo >= 8); + } + + t = tab + ((w24 >> (24-13-bo)) & 8191); + x += t->run; + bo += t->bits; + if(t->code == TERM){ + if(state == White) + oldx = x; + else{ + oldx2 = oldx; + x2 = x; + xx = oldx2&7; + q = p+oldx2/8; + if(x2/8 == oldx2/8) /* all in one byte, but if((x2&7)==0), do harder case */ + *q |= (0xFF>>xx) & (0xFF<<(8-(x2&7))); + else{ + dx = x2 - oldx2; + /* leading edge */ + if(xx){ + *q++ |= 0xFF>>xx; + dx -= 8-xx; + } + /* middle */ + while(dx >= 8){ + *q++ = 0xFF; + dx -= 8; + } + /* trailing edge */ + if(dx) + *q |= 0xFF<<(8-dx); + } + } + state ^= White^Black; + goto loop; + } + if(t->code == ERR){ + bitoffset = bo; + word24 = w24; + return 0; + } + if(t->code == EOL){ + bitoffset = bo; + word24 = w24; + return 1; + } + goto loop; +} + + +void +sync(uchar *rev) +{ + Tab *t; + int c; + + c = 0; +loop: + if(bitoffset > (24-13)) { + do { + if(nbytes <= 0) + return; + word24 = (word24<<8) | rev[*bytes]; + bitoffset -= 8; + bytes++; + nbytes--; + } while(bitoffset >= 8); + } + t = wtab + ((word24 >> (24-13-bitoffset)) & 8191); + if(t->code != EOL) { + bitoffset++; + c++; + goto loop; + } + bitoffset += t->bits; +} + +typedef struct File +{ + char *val; + int code; +}File; + +File ibtab[] = { +#include "btab" +{nil, 0} +}; + +File iwtab[] = { +#include "wtab" +{nil, 0} +}; + +int +binary(char *s) +{ + int n; + + n = 0; + while(*s) + n = n*2 + *s++-'0'; + return n; +} + +void +tabinit(File *file, Tab *tab) +{ + int i, j, v, r, l; + char *b; + + for(v=0; v<8192; v++) { + tab[v].run = 0; + tab[v].bits = 1; + tab[v].code = ERR; + } + for(i=0; b=file[i].val; i++){ + l = strlen(b); + v = binary(b); + r = file[i].code; + if(l > 13) + fprint(2, "g3: oops1 l = %d %s\n", l, b); + + v = v<<(13-l); + for(j=0; j<(1<<((13-l))); j++) { + if(tab[v].code != ERR) + fprint(2, "g3: oops2 %d %s\n", r, b); + tab[v].run = r; + tab[v].bits = l; + tab[v].code = TERM; + if(r < 0) { + tab[v].run = 0; + tab[v].code = EOL; + if(r < -1) { + tab[v].bits = 1; + tab[v].code = MAKE; + } + } + if(r >= 64) { + tab[v].code = MAKE; + } + v++; + } + } + + for(i=0; i<256; i++) + for(j=0; j<8; j++) + if(i & (1<<j)) + bitrev[i] |= 0x80 >> j; + for(i=0; i<256; i++) + bitnonrev[i] = i; +} + +void +initwbtab(void) +{ + tabinit(iwtab, wtab); + tabinit(ibtab, btab); +} diff --git a/sys/src/cmd/postscript/g3p9bit/mkfile b/sys/src/cmd/postscript/g3p9bit/mkfile new file mode 100755 index 000000000..2475a75bc --- /dev/null +++ b/sys/src/cmd/postscript/g3p9bit/mkfile @@ -0,0 +1,14 @@ +</$objtype/mkfile + +<../config + +TARG=g3p9bit + +OFILES=g3p9bit.$O + +HFILES=wtab btab + +BIN=$POSTBIN + +</sys/src/cmd/mkone + diff --git a/sys/src/cmd/postscript/g3p9bit/wtab b/sys/src/cmd/postscript/g3p9bit/wtab new file mode 100755 index 000000000..580b68a48 --- /dev/null +++ b/sys/src/cmd/postscript/g3p9bit/wtab @@ -0,0 +1,109 @@ +{"00110101", 0}, +{"000111", 1}, +{"0111", 2}, +{"1000", 3}, +{"1011", 4}, +{"1100", 5}, +{"1110", 6}, +{"1111", 7}, +{"10011", 8}, +{"10100", 9}, +{"00111", 10}, +{"01000", 11}, +{"001000", 12}, +{"000011", 13}, +{"110100", 14}, +{"110101", 15}, +{"101010", 16}, +{"101011", 17}, +{"0100111", 18}, +{"0001100", 19}, +{"0001000", 20}, +{"0010111", 21}, +{"0000011", 22}, +{"0000100", 23}, +{"0101000", 24}, +{"0101011", 25}, +{"0010011", 26}, +{"0100100", 27}, +{"0011000", 28}, +{"00000010", 29}, +{"00000011", 30}, +{"00011010", 31}, +{"00011011", 32}, +{"00010010", 33}, +{"00010011", 34}, +{"00010100", 35}, +{"00010101", 36}, +{"00010110", 37}, +{"00010111", 38}, +{"00101000", 39}, +{"00101001", 40}, +{"00101010", 41}, +{"00101011", 42}, +{"00101100", 43}, +{"00101101", 44}, +{"00000100", 45}, +{"00000101", 46}, +{"00001010", 47}, +{"00001011", 48}, +{"01010010", 49}, +{"01010011", 50}, +{"01010100", 51}, +{"01010101", 52}, +{"00100100", 53}, +{"00100101", 54}, +{"01011000", 55}, +{"01011001", 56}, +{"01011010", 57}, +{"01011011", 58}, +{"01001010", 59}, +{"01001011", 60}, +{"00110010", 61}, +{"00110011", 62}, +{"00110100", 63}, + +{"11011", 64}, +{"10010", 128}, +{"010111", 192}, +{"0110111", 256}, +{"00110110", 320}, +{"00110111", 384}, +{"01100100", 448}, +{"01100101", 512}, +{"01101000", 576}, +{"01100111", 640}, +{"011001100", 704}, +{"011001101", 768}, +{"011010010", 832}, +{"011010011", 896}, +{"011010100", 960}, +{"011010101", 1024}, +{"011010110", 1088}, +{"011010111", 1152}, +{"011011000", 1216}, +{"011011001", 1280}, +{"011011010", 1344}, +{"011011011", 1408}, +{"010011000", 1472}, +{"010011001", 1536}, +{"010011010", 1600}, +{"011000", 1664}, +{"010011011", 1728}, + +{"00000001000", 1792}, +{"00000001100", 1856}, +{"00000001101", 1920}, +{"000000010010", 1984}, +{"000000010011", 2048}, +{"000000010100", 2112}, +{"000000010101", 2176}, +{"000000010110", 2240}, +{"000000010111", 2304}, +{"000000011100", 2368}, +{"000000011101", 2432}, +{"000000011110", 2496}, +{"000000011111", 2560}, + +{"000000000001", -1}, +{"000000000000", -2}, diff --git a/sys/src/cmd/postscript/grabit/grabit.ps b/sys/src/cmd/postscript/grabit/grabit.ps new file mode 100755 index 000000000..dab313c51 --- /dev/null +++ b/sys/src/cmd/postscript/grabit/grabit.ps @@ -0,0 +1,522 @@ +% +% Dump a PostScript object, occasionally in a form that can be sent back +% through the interpreter. Similiar to Adobe's == procedure, but output +% is usually easier to read. No binding so operators like rcheck and exec +% can be conviently redefined. +% + +/GrabitDict 100 dict dup begin + +/recursive true def +/scratchstring 200 string def +/slowdown 100 def + +/column 0 def +/lastcolumn 80 def +/level 0 def +/multiline 100 array def +/nextname 0 def +/arraylength 0 def +/lengthonly false def + +/GrabitSetup { + counttomark {OmitNames exch true put} repeat pop + 0 0 moveto % for hardcopy output +} def + +/OmitNames 30 dict def % ignore these names +/OtherDicts 200 dict def % unrecognized dictionaries + +% +% All strings returned to the host go through Print. First pass through an +% array has lengthonly set to true. +% + +/Print { + dup type /stringtype ne {scratchstring cvs} if + lengthonly { + length arraylength add /arraylength exch def + }{ + dup length column add /column exch def + print flush + slowdown {1 pop} repeat + } ifelse +} def + +/Indent {level {( ) Print} repeat} def +/Newline {(\n) Print lengthonly not {/column 0 def} if} def + +/NextLevel {/level level 1 add def multiline level 0 put} def +/LastLevel {/level level 1 sub def} def + +% +% Make a unique name for each unrecognized dictionary and remember the name +% and dictionary in OtherDicts. +% + +/Register { + dup type /dicttype eq { + /nextname nextname 1 add def + dup (UnknownDict ) dup + (UnknownDict) length nextname ( ) cvs putinterval + 0 (UnknownDict) length nextname ( ) cvs length add getinterval cvn + exch OtherDicts 3 1 roll put + } if +} def + +% +% Replace array or dictionary values by known names. Lookups are in the +% standard PostScript dictionaries and in OtherDicts. If found replace +% the value by the name and make it executable so nametype omits the +% leading /. +% + +/Replace { + false + 1 index type /dicttype eq {pop true} if + 1 index type /arraytype eq 2 index xcheck not and {pop true} if + { + false + [userdict systemdict statusdict serverdict OtherDicts] { + { + 3 index eq + {exch pop exch pop cvx true exit} + {pop} + ifelse + } forall + dup {exit} if + } forall + pop + } if +} def + +% +% Simple type handlers. In some cases (e.g. savetype) what's returned can't +% be sent back through the interpreter. +% + +/booleantype {{(true )}{(false )} ifelse Print} def +/marktype {pop (mark ) Print} def +/nulltype {pop (null ) Print} def +/integertype {Print ( ) Print} def +/realtype {Print ( ) Print} def +/filetype {pop (-file- ) Print} def +/fonttype {pop (-fontID- ) Print} def +/savetype {pop (-saveobj- ) Print} def + +% +% Special formatting for operators is enabled if the flag in multiline +% (for the current level) is set to 1. In that case each operator, after +% being printed, is looked up in OperatorDict. If found the value is used +% as an index into the OperatorProcs array and the object at that index +% is retrieved and executed. Currently only used to choose the operators +% that end a line. +% + +/operatortype { + dup Print ( ) Print + multiline level get 1 eq { + scratchstring cvs cvn dup OperatorDict exch known { + OperatorDict exch get + OperatorProcs exch get exec + }{ + pop + column lastcolumn gt {Newline Indent} if + } ifelse + }{pop} ifelse +} def + +% +% Executable names are passed to operatortype. Non-executable names get a +% leading /. +% + +/nametype { + dup xcheck { + operatortype + }{ + (/) Print Print ( ) Print + } ifelse +} def + +% +% Arrays are processed in two passes. The first computes the length of the +% string returned to the host without any special formatting. If it extends +% past the last column special formatting is enabled by setting a flag in +% array multiline. Arrays are processed in a for loop so the last element +% easily recognized. At that point special fortmatting is disabled. +% + +/packedarraytype {arraytype} def + +/arraytype { + NextLevel + lengthonly not { + /lengthonly true def + /arraylength 0 def + dup dup type exec + arraylength 20 gt arraylength column add lastcolumn gt and { + multiline level 1 put + } if + /lengthonly false def + } if + + dup rcheck not { + (-array- ) Print pop + }{ + dup xcheck {({)}{([)} ifelse Print + multiline level get 0 ne {Newline Indent}{( ) Print} ifelse + 0 1 2 index length 1 sub { + 2 copy exch length 1 sub eq multiline level get 1 eq and { + multiline level 2 put + } if + 2 copy get exch pop + dup type /dicttype eq { + Replace + dup type /dicttype eq { + dup Register Replace + recursive { + 2 copy cvlit + /def load 3 1 roll + count 3 roll + } if + exch pop + } if + } if + dup type exec + dup xcheck not multiline level get 1 eq and { + 0 index type /arraytype eq + 1 index type /packedarray eq or + 1 index type /stringtype eq or {Newline Indent} if + } if + } for + multiline level get 0 ne {Newline LastLevel Indent NextLevel} if + xcheck {(} )}{(] )} ifelse Print + } ifelse + LastLevel +} def + +% +% Dictionary handler. Try to replace the value by a name before processing +% the dictionary. +% + +/dicttype { + dup + rcheck not { + (-dictionary- ) Print pop + }{ + dup maxlength Print ( dict dup begin) Print Newline + NextLevel + { + 1 index OmitNames exch known { + pop pop + }{ + Indent + Replace % arrays and dicts by known names + Register % new dictionaries in OtherDicts + exch + cvlit dup type exec % key first - force a / + dup type exec % then the value + (def) Print Newline + } ifelse + } forall + LastLevel + Indent + (end ) Print + } ifelse +} def + +% +% Strings containing characters not in AsciiDict are returned in hex. All +% others are ASCII strings and use AsciiDict for character mapping. +% + +/onecharstring ( ) def +/twocharstring ( ) def + +/stringtype { + dup + rcheck not { + (-string- ) Print + }{ + /hexit false def + dup { + onecharstring 0 3 -1 roll put + AsciiDict onecharstring cvn known not { + /hexit true def exit + } if + } forall + + hexit {(<)}{(\()} ifelse Print + 0 1 2 index length 1 sub { + 2 copy 1 getinterval exch pop + hexit { + 0 get /n exch def + n -4 bitshift 16#F and 16 twocharstring cvrs pop + n 16#F and twocharstring 1 1 getinterval 16 exch cvrs pop + twocharstring + }{cvn AsciiDict exch get} ifelse + Print + column lastcolumn gt { + hexit not {(\\) Print} if + Newline + } if + } for + hexit {(> )}{(\) )} ifelse Print + } ifelse + pop +} def + +% +% ASCII characters and replacement strings. Ensures the returned string will +% reproduce the original when passed through the scanner. Strings containing +% characters not in this list should be returned as hex strings. +% + +/AsciiDict 128 dict dup begin + (\n) cvn (\\n) def + (\r) cvn (\\r) def + (\t) cvn (\\t) def + (\b) cvn (\\b) def + (\f) cvn (\\f) def + ( ) cvn ( ) def + (!) cvn (!) def + (") cvn (") def + (#) cvn (#) def + ($) cvn ($) def + (%) cvn (\\%) def + (&) cvn (&) def + (') cvn (') def + (\() cvn (\\\() def + (\)) cvn (\\\)) def + (*) cvn (*) def + (+) cvn (+) def + (,) cvn (,) def + (-) cvn (-) def + (.) cvn (.) def + (/) cvn (/) def + (0) cvn (0) def + (1) cvn (1) def + (2) cvn (2) def + (3) cvn (3) def + (4) cvn (4) def + (5) cvn (5) def + (6) cvn (6) def + (7) cvn (7) def + (8) cvn (8) def + (9) cvn (9) def + (:) cvn (:) def + (;) cvn (;) def + (<) cvn (<) def + (=) cvn (=) def + (>) cvn (>) def + (?) cvn (?) def + (@) cvn (@) def + (A) cvn (A) def + (B) cvn (B) def + (C) cvn (C) def + (D) cvn (D) def + (E) cvn (E) def + (F) cvn (F) def + (G) cvn (G) def + (H) cvn (H) def + (I) cvn (I) def + (J) cvn (J) def + (K) cvn (K) def + (L) cvn (L) def + (M) cvn (M) def + (N) cvn (N) def + (O) cvn (O) def + (P) cvn (P) def + (Q) cvn (Q) def + (R) cvn (R) def + (S) cvn (S) def + (T) cvn (T) def + (U) cvn (U) def + (V) cvn (V) def + (W) cvn (W) def + (X) cvn (X) def + (Y) cvn (Y) def + (Z) cvn (Z) def + ([) cvn ([) def + (\\) cvn (\\\\) def + (]) cvn (]) def + (^) cvn (^) def + (_) cvn (_) def + (`) cvn (`) def + (a) cvn (a) def + (b) cvn (b) def + (c) cvn (c) def + (d) cvn (d) def + (e) cvn (e) def + (f) cvn (f) def + (g) cvn (g) def + (h) cvn (h) def + (i) cvn (i) def + (j) cvn (j) def + (k) cvn (k) def + (l) cvn (l) def + (m) cvn (m) def + (n) cvn (n) def + (o) cvn (o) def + (p) cvn (p) def + (q) cvn (q) def + (r) cvn (r) def + (s) cvn (s) def + (t) cvn (t) def + (u) cvn (u) def + (v) cvn (v) def + (w) cvn (w) def + (x) cvn (x) def + (y) cvn (y) def + (z) cvn (z) def + ({) cvn ({) def + (|) cvn (|) def + (}) cvn (}) def + (~) cvn (~) def +end def + +% +% OperatorDict can help format procedure listings. The value assigned to each +% name is used as an index into the OperatorProcs array. The procedure at that +% index is fetched and executed after the named operator is printed. What's in +% OperatorDict is a matter of taste rather than correctness. The default list +% represents our choice of which of Adobe's operators should end a line. +% + +/OperatorProcs [{} {Newline Indent}] def + +/OperatorDict 250 dict def + +OperatorDict /arc 1 put +OperatorDict /arcn 1 put +OperatorDict /ashow 1 put +OperatorDict /awidthshow 1 put +OperatorDict /banddevice 1 put +OperatorDict /begin 1 put +OperatorDict /charpath 1 put +OperatorDict /clear 1 put +OperatorDict /cleardictstack 1 put +OperatorDict /cleartomark 1 put +OperatorDict /clip 1 put +OperatorDict /clippath 1 put +OperatorDict /closefile 1 put +OperatorDict /closepath 1 put +OperatorDict /concat 1 put +OperatorDict /copypage 1 put +OperatorDict /curveto 1 put +OperatorDict /def 1 put +OperatorDict /end 1 put +OperatorDict /eoclip 1 put +OperatorDict /eofill 1 put +OperatorDict /erasepage 1 put +OperatorDict /exec 1 put +OperatorDict /exit 1 put +OperatorDict /fill 1 put +OperatorDict /flattenpath 1 put +OperatorDict /flush 1 put +OperatorDict /flushfile 1 put +OperatorDict /for 1 put +OperatorDict /forall 1 put +OperatorDict /framedevice 1 put +OperatorDict /grestore 1 put +OperatorDict /grestoreall 1 put +OperatorDict /gsave 1 put +OperatorDict /handleerror 1 put +OperatorDict /if 1 put +OperatorDict /ifelse 1 put +OperatorDict /image 1 put +OperatorDict /imagemask 1 put +OperatorDict /initclip 1 put +OperatorDict /initgraphics 1 put +OperatorDict /initmatrix 1 put +OperatorDict /kshow 1 put +OperatorDict /lineto 1 put +OperatorDict /loop 1 put +OperatorDict /moveto 1 put +OperatorDict /newpath 1 put +OperatorDict /nulldevice 1 put +OperatorDict /pathforall 1 put +OperatorDict /print 1 put +OperatorDict /prompt 1 put +OperatorDict /put 1 put +OperatorDict /putinterval 1 put +OperatorDict /quit 1 put +OperatorDict /rcurveto 1 put +OperatorDict /renderbands 1 put +OperatorDict /repeat 1 put +OperatorDict /resetfile 1 put +OperatorDict /restore 1 put +OperatorDict /reversepath 1 put +OperatorDict /rlineto 1 put +OperatorDict /rmoveto 1 put +OperatorDict /rotate 1 put +OperatorDict /run 1 put +OperatorDict /scale 1 put +OperatorDict /setcachedevice 1 put +OperatorDict /setcachelimit 1 put +OperatorDict /setcacheparams 1 put +OperatorDict /setcharwidth 1 put +OperatorDict /setdash 1 put +OperatorDict /setdefaulttimeouts 1 put +OperatorDict /setdostartpage 1 put +OperatorDict /seteescratch 1 put +OperatorDict /setflat 1 put +OperatorDict /setfont 1 put +OperatorDict /setgray 1 put +OperatorDict /sethsbcolor 1 put +OperatorDict /setidlefonts 1 put +OperatorDict /setjobtimeout 1 put +OperatorDict /setlinecap 1 put +OperatorDict /setlinejoin 1 put +OperatorDict /setlinewidth 1 put +OperatorDict /setmargins 1 put +OperatorDict /setmatrix 1 put +OperatorDict /setmiterlimit 1 put +OperatorDict /setpacking 1 put +OperatorDict /setpagetype 1 put +OperatorDict /setprintname 1 put +OperatorDict /setrgbcolor 1 put +OperatorDict /setsccbatch 1 put +OperatorDict /setsccinteractive 1 put +OperatorDict /setscreen 1 put +OperatorDict /settransfer 1 put +OperatorDict /show 1 put +OperatorDict /showpage 1 put +OperatorDict /start 1 put +OperatorDict /stop 1 put +OperatorDict /store 1 put +OperatorDict /stroke 1 put +OperatorDict /strokepath 1 put +OperatorDict /translate 1 put +OperatorDict /widthshow 1 put +OperatorDict /write 1 put +OperatorDict /writehexstring 1 put +OperatorDict /writestring 1 put + +end def + +% +% Put an object on the stack and call Grabit. Output continues until stack +% is empty. For example, +% +% /letter load Grabit +% +% prints a listing of the letter procedure. +% + +/Grabit { + /saveobj save def + GrabitDict begin + { + count 0 eq {exit} if + count {dup type exec} repeat + (\n) print flush + } loop + end + currentpoint % for hardcopy output + saveobj restore + moveto +} def + diff --git a/sys/src/cmd/postscript/grabit/grabit.rc b/sys/src/cmd/postscript/grabit/grabit.rc new file mode 100755 index 000000000..1f06c2176 --- /dev/null +++ b/sys/src/cmd/postscript/grabit/grabit.rc @@ -0,0 +1,64 @@ +#!/bin/rc +# Print a listing of an object, often a dictionary or an array. Something +# like ==, but the output is often easier to read and closer to PostScript +# that can be sent back through the interpreter. +# + +POSTLIB=/sys/lib/postscript/prologues +PROLOGUE=$POSTLIB/grabit.ps + +COPYFILE= +RECURSIVE=true +OMITNAMES='/Grabit /GrabitDict' + +NONCONFORMING='%!PS' +ENDPROLOG='%%EndProlog' +BEGINSETUP='%%BeginSetup' +ENDSETUP='%%EndSetup' +TRAILER='%%Trailer' + +SETUP=GrabitSetup + +while (! ~ $#* 0 && ~ $1 -*) { + switch ($1) { + case -d; RECURSIVE=false + + case -o; shift; OMITNAMES=$OMITNAMES' '$1 + case -o*; OMITNAMES=$OMITNAMES' '`{echo $1 | sed s/-o//} + + case -C; shift; COPYFILE=$COPYFILE' '$1 + case -C*; COPYFILE=$COPYFILE' '`{echo $1 | sed s/-C//} + + case -L; shift; PROLOGUE=$1 + case -L*; PROLOGUE=`{echo $1 | sed s/-L//} + + case --; + + case -*; echo $0: illegal option $1 >[1=2]; exit 1 + } + shift +done + +echo $NONCONFORMING +cat $PROLOGUE +echo $ENDPROLOG +echo $BEGINSETUP +if (~ $COPYFILE '') COPYFILE=/dev/null +cat $COPYFILE +echo 'GrabitDict begin' +echo '/recursive '$RECURSIVE' def' + +echo mark +for (i in $OMITNAMES) { + switch ($i) { + case /*; echo $i + case ?*; echo /$i + } +} +echo GrabitSetup + +echo end +echo $ENDSETUP + +for (i) echo $i Grabit + diff --git a/sys/src/cmd/postscript/grabit/mkfile b/sys/src/cmd/postscript/grabit/mkfile new file mode 100755 index 000000000..ca2b3c928 --- /dev/null +++ b/sys/src/cmd/postscript/grabit/mkfile @@ -0,0 +1,20 @@ +</$objtype/mkfile + +<../config + +all:V: grabit + +install installall:V: $POSTBIN/grabit $POSTLIB/grabit.ps + +$POSTBIN/grabit: grabit + cp $prereq $target + +$POSTLIB/grabit.ps: grabit.ps + cp $prereq $target + +grabit: grabit.rc + sed 's?^POSTLIB=.*?POSTLIB='$POSTLIB'?' grabit.rc >grabit + chmod 775 grabit + +clean nuke:V: + rm -f grabit diff --git a/sys/src/cmd/postscript/hardcopy/README b/sys/src/cmd/postscript/hardcopy/README new file mode 100755 index 000000000..2ad29065a --- /dev/null +++ b/sys/src/cmd/postscript/hardcopy/README @@ -0,0 +1,11 @@ +Redirect output of the print operator to paper. Particularly useful if +you're trying to extract information from a printer, but you don't have +access to the data the printer returns to the host. + +For example, + + FontDirectory {pop ==} forall + +names all the fonts registered in the FontDirectory dictionary. Simple, +but only if you can read the data returned to the host by the printer. + diff --git a/sys/src/cmd/postscript/hardcopy/hardcopy.ps b/sys/src/cmd/postscript/hardcopy/hardcopy.ps new file mode 100755 index 000000000..65eb24df9 --- /dev/null +++ b/sys/src/cmd/postscript/hardcopy/hardcopy.ps @@ -0,0 +1,196 @@ +% +% Redefiniton of the PostScript file output operators so results go to paper. +% Complicated and slow, but the implementation doesn't place many demands on +% included PostScript. About all that's required is gentle treatment of the +% graphics state between write calls. +% + +/#copies 1 store +/aspectratio 1 def +/font /Courier def +/formsperpage 1 def +/landscape false def +/magnification 1 def +/orientation 0 def +/pointsize 10 def +/rotation 1 def +/xoffset .1 def +/yoffset .1 def + +/roundpage true def +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} def +/min {2 copy gt {exch} if pop} def + +/HardcopySetup { + landscape {/orientation 90 orientation add def} if + font findfont 1 1.1 div scalefont setfont + + pagedimensions + xcenter ycenter translate + orientation rotation mul rotate + width 2 div neg height 2 div translate + xoffset inch yoffset inch neg translate + pointsize 1.1 mul dup scale + magnification dup aspectratio mul scale + height width div 1 min dup scale + 0 -1 translate + 0 0 moveto +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + roundpage currentdict /roundpagebbox known and {roundpagebbox} if + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def +} def + +% +% Unbind the operators in an executable array or packedarray. Leaves the +% unbound array or the original object on the stack. +% + +/Unbind { + 0 index xcheck + 1 index type /arraytype eq + 2 index type /packedarraytype eq or and { + dup length array copy cvx + dup 0 exch { + dup type /operatortype eq { + ( ) cvs cvn cvx + } if + + dup type /dicttype eq { + dup maxlength dict exch { + Unbind + 3 copy put pop pop + } forall + } if + + 0 index xcheck + 1 index type /arraytype eq + 2 index type /packedarraytype eq or and { + Unbind + } if + + 3 copy put pop + 1 add + } forall + pop + } if +} def + +% +% New write operator - don't bind the definition! Expands tabs and backspaces, +% wraps long lines, and starts a new page whenever necessary. The code that +% handles newlines assumes lines are separated by one vertical unit. +% + +/write { + true exch + + %%case '\b': + dup 8#10 eq { + ( ) stringwidth pop neg 0 rmoveto + currentpoint pop 0 lt { + currentpoint exch pop 0 exch moveto + } if + exch pop false exch + } if + + %%case '\t': + dup 8#11 eq { + currentpoint pop ( ) stringwidth pop div round cvi + 8 mod 8 exch sub { + 2 index 8#40 write + } repeat + exch pop false exch + } if + + %%case '\n': + dup 8#12 eq { + currentpoint 0 exch 1 sub moveto pop + + gsave clippath pathbbox pop pop exch pop grestore + currentpoint exch pop 1 sub ge { + 2 index 8#14 write + } if + exch pop false exch + } if + + %%case '\f': + dup 8#14 eq { + gsave showpage grestore + 0 0 moveto + exch pop false exch + } if + + %%case '\r': + dup 8#15 eq { + currentpoint 0 exch moveto pop + exch pop false exch + } if + + %%case EOF: + dup -1 eq { + currentpoint 0 ne exch 0 ne or { + 2 index 8#14 write + } if + exch pop false exch + } if + + %%default: + exch { + dup + gsave clippath pathbbox pop 3 1 roll pop pop grestore + ( ) stringwidth pop currentpoint pop add le { + 2 index 8#12 write + } if + ( ) dup 0 4 -1 roll put show + } if + + pop % the character + pop % and file object +} def + +% +% All the other file output operators call our redefined write operator. +% + +/print { + (%stdout) (w) file exch {1 index exch write} forall + pop +} def + +/writestring { + {1 index exch write} forall + pop +} def + +/writehexstring { + (0123456789ABCDEF) 3 1 roll { + dup + 3 index exch -4 bitshift 16#F and get 2 index exch write + 2 index exch 16#F and get 1 index exch write + } forall + pop pop +} def + +% +% Unbind and redefine the remaining file output procedures. +% + +/= dup load Unbind def +/== dup load Unbind def +/stack dup load Unbind def +/pstack dup load Unbind def + diff --git a/sys/src/cmd/postscript/hardcopy/hardcopy.rc b/sys/src/cmd/postscript/hardcopy/hardcopy.rc new file mode 100755 index 000000000..0077aa716 --- /dev/null +++ b/sys/src/cmd/postscript/hardcopy/hardcopy.rc @@ -0,0 +1,70 @@ +#!/bin/rc +# Generate paper output from the data that a PostScript program normally +# sends back to a host computer using file output operators. +# + +POSTLIB=/sys/lib/postscript/prologues +PROLOGUE=$POSTLIB/hardcopy.ps + +OPTIONS= +MODE=portrait + +NONCONFORMING='%!PS' +ENDPROLOG='%%EndProlog' +BEGINSETUP='%%BeginSetup' +ENDSETUP='%%EndSetup' +TRAILER='%%Trailer' + +SETUP=HardcopySetup +DONE='(%stdout)(w) file -1 write' + +while (! ~ $#* 0 && ~ $1 -*) { + switch ($1) { + case -c; shift; OPTIONS=$OPTIONS' /#copies '$1' store' + case -c*; OPTIONS=$OPTIONS' /#copies `{echo $1 | sed s/-c//}' store' + + case -f; shift; OPTIONS=$OPTIONS' /font '/$1' def' + case -f*; OPTIONS=$OPTIONS' /font '/`{echo $1 | sed s/-f//}' def' + + case -p; shift; MODE=$1 + case -p*; MODE=`{echo $1 | sed s/-p//} + + case -m; shift; OPTIONS=$OPTIONS' /magnification '$1' def' + case -m*; OPTIONS=$OPTIONS' /magnification '`{echo $1 | sed s/-m//}' def' + + case -s; shift; OPTIONS=$OPTIONS' /pointsize '$1' def' + case -s*; OPTIONS=$OPTIONS' /pointsize '`{echo $1 | sed s/-s//}' def' + + case -x; shift; OPTIONS=$OPTIONS' /xoffset '$1' def' + case -x*; OPTIONS=$OPTIONS' /xoffset '`{echo $1 | sed s/-x//}' def' + + case -y; shift; OPTIONS=$OPTIONS' /yoffset '$1' def' + case -y*; OPTIONS=$OPTIONS' /yoffset '`{echo $1 | sed s/-y//}' def' + + case -L; shift; PROLOGUE=$1 + case -L*; PROLOGUE=`{echo $1 | sed s/-L//} + + case --; + + case -*; echo '$0: illegal option $1' >&2; exit 1 + } + shift +} + +switch ($MODE) { + case l*; OPTIONS=$OPTIONS' /landscape true def' + case *; OPTIONS=$OPTIONS' /landscape false def' +} + +echo $NONCONFORMING +cat $PROLOGUE +echo $ENDPROLOG +echo $BEGINSETUP +echo $OPTIONS +echo $SETUP +echo $ENDSETUP + +cat $* + +echo $TRAILER +echo $DONE diff --git a/sys/src/cmd/postscript/hardcopy/mkfile b/sys/src/cmd/postscript/hardcopy/mkfile new file mode 100755 index 000000000..c6131dbac --- /dev/null +++ b/sys/src/cmd/postscript/hardcopy/mkfile @@ -0,0 +1,20 @@ +</$objtype/mkfile + +<../config + +all:V: hardcopy + +installall install:V: $POSTBIN/hardcopy $POSTLIB/hardcopy.ps + +$POSTBIN/hardcopy: hardcopy + cp $prereq $target + +$POSTLIB/hardcopy.ps: hardcopy.ps + cp $prereq $target + +hardcopy: hardcopy.rc + sed 's?^POSTLIB=.*?POSTLIB='$POSTLIB'?' hardcopy.rc >hardcopy + chmod 775 hardcopy + +clean nuke:V: + rm -f hardcopy diff --git a/sys/src/cmd/postscript/mcolor/color.sr b/sys/src/cmd/postscript/mcolor/color.sr new file mode 100755 index 000000000..0a63aad52 --- /dev/null +++ b/sys/src/cmd/postscript/mcolor/color.sr @@ -0,0 +1,45 @@ +.ds Dc black +.ds Cc \*(Dc +.de CL \" Color selection macro +. \" +. \" $1=color (e.g. .CL red) or +. \" $1=textcolor on backgroundcolor (e.g. .CL "red on blue") +. \" $1=red green blue rgb (e.g. .CL ".2 .3 .4 rgb") or +. \" $1=hue saturation brightness hsb (e.g. .CL ".5 .6 .7 hsb") +. \" $2=text +. \" +. \" If no arguments are given the default color (usually black) will be +. \" restored. If $2 is omitted the color selected by $1 remains in effect +. \" until another color is selected. If two arguments are given $2 will be +. \" printed in color $1 and then the default color will be restored. +. \" +. \" The color of the text and the background can be selected by setting $1 +. \" to "textcolor on backgroundcolor" where textcolor and backgroundcolor +. \" can be any of the known colors. For example use .CL "white on black" +. \" for reverse video printing. Changing color in a word can be accomplished +. \" by preceeding the characters with a \X'SetColor:val' command, where val +. \" is the color you wish to use. Named colors are case independent. +. \" +. \" Implementation details are device dependent and are handled in the +. \" appropriate post-processor. Requesting a color that's not available +. \" (eg. not defined in /usr/lib/postscript/color.ps) results in the use +. \" of default colors - black or white on black for reverse video mode. +. \" +. \" All colors may not be supported on every output device, and the direct +. \" specification of a color via an explicit rgb or hsb argument may also +. \" be device dependent. In any case, to be safe on PostScript devices, all +. \" numeric paramenters in the direct rgb or hsb specifications should lie +. \" between 0 and 1 (inclusive). The names of the currently available colors +. \" on PostScript printers are listed in file /usr/lib/postscript/color.ps. +. \" +.mk Ov +.if \\n(.$=0 .ds Cc \\*(Dc +.if \\n(.$=1 .ds Cc \\$1 +.if \\n(.$<2 \\X'SetColor:\\*(Cc' +.if \\n(.$=2 \\X'SetColor:\\$1'\\c +.if \\n(.$=2 'sp |\\n(Ovu +.if \\n(.$=2 \\$2 +.if \\n(.$=2 .mk Ov +.if \\n(.$=2 \\X'SetColor:\\*(Cc'\\c +'sp |\\n(Ovu +.. diff --git a/sys/src/cmd/postscript/mcolor/mcolor.5 b/sys/src/cmd/postscript/mcolor/mcolor.5 new file mode 100755 index 000000000..bf0181fda --- /dev/null +++ b/sys/src/cmd/postscript/mcolor/mcolor.5 @@ -0,0 +1,60 @@ +.ds dP /usr/lib/postscript +.ds dT /usr/lib/tmac +.TH MCOLOR 5 +.SH NAME +.B mcolor +\- color and reverse video macro +.SH SYNOPSIS +\*(mBtroff \-mcolor\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B mcolor +is a macro package for color selection and reverse video printing +on PostScript printers. +The package is compatible with most existing macro packages +and includes the following macro: +.TP 1.25i +.MI .CL "\0color\0text" +Prints +.I text +in +.IR color . +No arguments restores the default color (black). +If +.I text +is omitted the selected +.I color +remains in effect until another +.I color +is selected. +If two arguments are given the +.I text +is printed in +.I color +and then the default color is restored. +.PP +Both the text and background color can be selected. +A +.I color +argument of +.RI `` color1 +.MW on +.IR color2 '' +prints text in +.I color1 +on a background in +.I color2 . +.PP +Named colors must be listed in the +``colordict'' +dictionary in file +.MR \*(dP/color.ps . +.SH FILES +.MW \*(dT/tmac.color +.br +.MW \*(dP/color.ps +.SH SEE ALSO +.BR troff (1), +.BR dpost (1), +.BR mps (5) diff --git a/sys/src/cmd/postscript/mcolor/mcolor.mk b/sys/src/cmd/postscript/mcolor/mcolor.mk new file mode 100755 index 000000000..aacadcfb6 --- /dev/null +++ b/sys/src/cmd/postscript/mcolor/mcolor.mk @@ -0,0 +1,53 @@ +# +# Not installing the man page. +# + +MAKE=/bin/make +MAKEFILE=mcolor.mk + +SYSTEM=V9 +VERSION=3.3.2 + +OWNER=bin +GROUP=bin + +POSTLIB=/usr/lib/postscript +TMACDIR=/usr/lib/tmac + +all : + @cp color.sr tmac.color + +install : all + @if [ ! -d $(TMACDIR) ]; then \ + mkdir $(TMACDIR); \ + chmod 755 $(TMACDIR); \ + chgrp $(GROUP) $(TMACDIR); \ + chown $(OWNER) $(TMACDIR); \ + fi + cp tmac.color $(TMACDIR)/tmac.color + @chmod 644 $(TMACDIR)/tmac.color + @chgrp $(GROUP) $(TMACDIR)/tmac.color + @chown $(OWNER) $(TMACDIR)/tmac.color + +clean : + rm -f tmac.color + +clobber : clean + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + -e "s'^TMACDIR=.*'TMACDIR=$(TMACDIR)'" \ + $(MAKEFILE) >X$(MAKEFILE); \ + mv X$(MAKEFILE) $(MAKEFILE); \ + sed \ + -e "s'^.ds dP.*'.ds dP $(POSTLIB)'" \ + -e "s'^.ds dT.*'.ds dT $(TMACDIR)'" \ + mcolor.5 >Xmcolor.5; \ + mv Xmcolor.5 mcolor.5 + diff --git a/sys/src/cmd/postscript/misc/README b/sys/src/cmd/postscript/misc/README new file mode 100755 index 000000000..d17f15da2 --- /dev/null +++ b/sys/src/cmd/postscript/misc/README @@ -0,0 +1,15 @@ +Miscellaneous programs - all are unsupported. + + ibmfont.c IBM PC to Unix font conversion program + laserbar.[c1] Barcode filter and man page - Jan Wolitzky + lp.model Sample lp interface (not for Unix 4.0) - Maryann Csaszar + macfont.c Macintosh to Unix font conversion program + pscrypt.c Quick implementation of Adobe's encryption/decryption algorithm + setbaud.ps Example of how to change the printer's baudrate + +Use make to compile C programs. For example, + + make macfont + +compiles macfont.c. + diff --git a/sys/src/cmd/postscript/misc/ibmfont.c b/sys/src/cmd/postscript/misc/ibmfont.c new file mode 100755 index 000000000..99e53c346 --- /dev/null +++ b/sys/src/cmd/postscript/misc/ibmfont.c @@ -0,0 +1,293 @@ +/* + * + * Program that converts IBM font files to a format that works on Unix systems. + * Essentially all the information needed came from the Adobe paper "Supporting + * Downloadable PostScript Fonts". To use the program type, + * + * ibmfont font.ibm >font.unix + * + * where font.ibm is the font file, exactly as it came over from an IBM PC, + * and font.unix is equivalent host resident font file usable on Unix systems. + * + */ + +#include <stdio.h> +#include <signal.h> + +#define OFF 0 +#define ON 1 + +#define NON_FATAL 0 +#define FATAL 1 + +#define FALSE 0 +#define TRUE 1 + +char **argv; +int argc; + +char *prog_name; + +int x_stat; +int debug = OFF; +int ignore = OFF; + +FILE *fp_in = stdin; +FILE *fp_out = stdout; + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * IBM PC to Unix font converter. + * + */ + + argc = agc; + argv = agv; + prog_name = argv[0]; + + options(); + arguments(); + exit(x_stat); + +} /* End of main */ + +/*****************************************************************************/ + +options() + +{ + + int ch; + char *names = "DI"; + + extern char *optarg; + extern int optind; + +/* + * + * Command line options. + * + */ + + while ( (ch = getopt(argc, argv, names)) != EOF ) { + switch ( ch ) { + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Everything esle is an input file. No arguments or '-' means stdin. + * + */ + + + if ( argc < 1 ) + conv(); + else + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + conv(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + +} /* End of arguments */ + +/*****************************************************************************/ + +conv() + +{ + + int blocksize; + int blocktype; + int seg; + long ftell(); + +/* + * + * Font files on the IBM PC are stored in a compressed binary format. Individual + * segments in the file are preceeded by a header that looks like, + * + * Byte 1: 128 + * Byte 2: segment type (1=ASCII, 2=TOHEX, or 3=EOF) + * Bytes 3-6: length of the segment + * Bytes 7 ... data + * + */ + + while ( 1 ) { + seg = ftell(fp_in); + if ( getc(fp_in) != 128 ) + error(FATAL, "bad file format"); + blocktype = getc(fp_in); + blocksize = getint(fp_in); + if ( debug == ON ) { + fprintf(stderr, "blocktype = %d, blocksize = %d\n", blocktype, blocksize); + fprintf(stderr, "start=0%o, end=0%o\n", seg, seg+blocksize+6); + fprintf(stderr, "start=%d, end=%d\n", seg, seg+blocksize+6); + } /* End if */ + switch ( blocktype ) { + case 1: + asciitext(blocksize); + break; + + case 2: + hexdata(blocksize); + break; + + case 3: + return; + + default: + error(FATAL, "unknown resource type %d", blocktype); + } /* End switch */ + } /* End while */ + +} /* End of conv */ + +/*****************************************************************************/ + +asciitext(count) + + int count; /* bytes left in the block */ + +{ + + int ch; + int i = 0; + +/* + * + * Handles type 1 (ie. ASCII text) blocks. Changing carriage returns to newlines + * is all I've done. + * + */ + + for ( i = 0; i < count; i++ ) { + if ( (ch = getc(fp_in)) == '\r' ) + ch = '\n'; + putc(ch, fp_out); + } /* End for */ + +} /* End of asciitext */ + +/*****************************************************************************/ + +hexdata(count) + + int count; /* bytes left in the block */ + +{ + + int i; + int n; + +/* + * + * Reads the next count bytes and converts each byte to hex. Also starts a new + * line every 80 hex characters. + * + */ + + for ( i = 0, n = 0; i < count; i++ ) { + fprintf(fp_out, "%.2X", getc(fp_in)); + if ( (++n % 40) == 0 ) + putc('\n', fp_out); + } /* End for */ + +} /* End of hexdata */ + +/*****************************************************************************/ + +getint() + +{ + + int val; + +/* + * + * Reads the next four bytes into an integer and returns the value to the caller. + * First two bytes are probably always 0. + * + */ + + val = getc(fp_in); + val |= (getc(fp_in) << 8); + val |= (getc(fp_in) << 16); + val |= (getc(fp_in) << 24); + + return(val); + +} /* End of getint */ + +/*****************************************************************************/ + +error(kind, mesg, a1, a2, a3) + + int kind; + char *mesg; + unsigned a1, a2, a3; + +{ + +/* + * + * Print mesg and quit if kind is FATAL. + * + */ + + if ( mesg != NULL && *mesg != '\0' ) { + fprintf(stderr, "%s: ", prog_name); + fprintf(stderr, mesg, a1, a2, a3); + putc('\n', stderr); + } /* End if */ + + if ( kind == FATAL && ignore == OFF ) + exit(x_stat | 01); + +} /* End of error */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/misc/laserbar.1 b/sys/src/cmd/postscript/misc/laserbar.1 new file mode 100755 index 000000000..e845fc9bc --- /dev/null +++ b/sys/src/cmd/postscript/misc/laserbar.1 @@ -0,0 +1,41 @@ +.TH LASERBAR 1 +.SH NAME +laserbar \- produce bar codes on a PostScript laser printer +.SH SYNOPSIS +.B laserbar +[\fB-r\fP rotate] [\fB-x\fP xoffset] [\fB-y\fP yoffset] +[\fB-X\fP xscale] [\fB-Y\fP yscale] [\fB-lns\fP] string +.SH DESCRIPTION +.I Laserbar +prints on the standard output the PostScript text that will produce +(on a suitable laser printer) the \s-2CODE-39\s+2 bar code +corresponding to +.I string. +The \fBr\fP option may be used to specify a rotation (in +degrees) of the bar code. +The \fBx\fP, \fBy\fP, \fBX\fP, and \fBY\fP options may be used to specify +an x- or y-axis offset (in inches) or scaling factor, respectively. +(The offset is measured from the lower left corner of the page +to the upper left corner of the bar +code. By default, the bar code produced is one inch high, and is scaled +so that the narrowest elements are each 1/72-inch \- i.e., one point \- wide.) +If the \fBl\fP option is specified, the bar code produced is labeled. +If the \fBn\fP option is specified, the resulting PostScript text +includes a leading \f(CWnewpath\fP command, so that the text may stand +alone or precede any other PostScript commands. +If the \fBs\fP option is specified, the resulting PostScript text includes +a trailing \f(CWshowpage\fP command, so that the text may stand alone +or follow any other PostScript commands. +.P +This manual page (if it appears with a bar code printed on it) was +produced by something like the following sequence: +.IP +.ft CW +laserbar -x 2.5 -y 3 -l -n ABC123xyz > tempfile +.br +troff -man -Tpost laserbar.1 | dpost >> tempfile +.br +prt -dprinter -lpostscript tempfile +.ft P +.SH SEE ALSO +laserbar(3), prt(1), dpost(1), postbgi(1), postprint(1), postdmd(1), posttek(1), etc. diff --git a/sys/src/cmd/postscript/misc/laserbar.c b/sys/src/cmd/postscript/misc/laserbar.c new file mode 100755 index 000000000..d9f586476 --- /dev/null +++ b/sys/src/cmd/postscript/misc/laserbar.c @@ -0,0 +1,166 @@ +/* laserbar -- filter to print barcodes on postscript printer */ + +#define MAIN 1 + +#define LABEL 01 +#define NFLAG 02 +#define SFLAG 04 + +#include <stdio.h> +#include <ctype.h> + +static int code39[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* sp ! " # $ % & ' */ + 0304, 0, 0, 0, 0250, 0052, 0, 0, +/* ( ) * + , - - / */ + 0, 0, 0224, 0212, 0, 0205, 0604, 0242, +/* 0 1 2 3 4 5 6 7 */ + 0064, 0441, 0141, 0540, 0061, 0460, 0160, 0045, +/* 8 9 : ; < = > ? */ + 0444, 0144, 0, 0, 0, 0, 0, 0, +/* @ A B C D E F G */ + 0, 0411, 0111, 0510, 0031, 0430, 0130, 0015, +/* H I J K L M N O */ + 0414, 0114, 0034, 0403, 0103, 0502, 0023, 0422, +/* P Q R S T U V W */ + 0122, 0007, 0406, 0106, 0026, 0601, 0301, 0700, +/* X Y Z [ \ ] ^ _ */ + 0221, 0620, 0320, 0, 0, 0, 0, 0, +/* ` a b c d e f g */ + 0, 0411, 0111, 0510, 0031, 0430, 0130, 0015, +/* h i j k l m n o */ + 0414, 0114, 0034, 0403, 0103, 0502, 0023, 0422, +/* p q r s t u v w */ + 0122, 0007, 0406, 0106, 0026, 0601, 0301, 0700, +/* x y z { | } ~ del */ + 0221, 0620, 0320, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static void barprt(); +void laserbar(); + +#ifdef MAIN + +main(argc, argv) +char **argv; +{ + int c, flags = 0, error = 0; + double rotate = 0, xoffset = 0, yoffset = 0, xscale = 1, yscale = 1; + extern char *optarg; + extern int optind; + extern double atof(); + extern void exit(); + + while ((c = getopt(argc, argv, "r:x:y:X:Y:lns")) != EOF) { + switch(c) { + case 'r': + rotate = atof(optarg); + break; + case 'x': + xoffset = atof(optarg); + break; + case 'y': + yoffset = atof(optarg); + break; + case 'X': + xscale = atof(optarg); + break; + case 'Y': + yscale = atof(optarg); + break; + case 'l': + flags |= LABEL; + break; + case 'n': + flags |= NFLAG; + break; + case 's': + flags |= SFLAG; + break; + case '?': + ++error; + } + } + if ((argc - optind) != 1) + ++error; + if (error) { + (void) fprintf(stderr, +"Usage: %s [-r rotate] [-x xoffset] [-y yoffset] [-X xscale] [-Y yscale] [-lns] string\n", + *argv); + exit(1); + } + laserbar(stdout, argv[optind], rotate, xoffset, yoffset, xscale, yscale, flags); + return 0; +} + +#endif MAIN + +static int right = 0; + +void +laserbar(fp, str, rotate, xoffset, yoffset, xscale, yscale, flags) +FILE *fp; +char *str; +double rotate, xoffset, yoffset, xscale, yscale; +int flags; +{ + xoffset *= 72.; + yoffset *= 72.; + (void) fprintf(fp, "gsave %s\n", (flags & NFLAG) ? "newpath" : ""); + if (xoffset || yoffset) + (void) fprintf(fp, "%f %f moveto\n", xoffset, yoffset); + if (xscale != 1 || yscale != 1) + (void) fprintf(fp, "%f %f scale\n", xscale, yscale); + if (rotate) + (void) fprintf(fp, "%f rotate\n", rotate); + (void) fputs("/Helvetica findfont 16 scalefont setfont\n", fp); + (void) fputs("/w { 0 rmoveto gsave 3 setlinewidth 0 -72 rlineto stroke grestore } def\n", fp); + (void) fputs("/n { 0 rmoveto gsave 1 setlinewidth 0 -72 rlineto stroke grestore } def\n", fp); + (void) fputs("/l { gsave 2 -88 rmoveto show grestore } def\n", fp); + barprt(fp, '*', 0); + while (*str) + barprt(fp, *(str++), (flags & LABEL)); + barprt(fp, '*', 0); + (void) fprintf(fp, "%sgrestore\n", (flags & SFLAG) ? "showpage " : ""); + right = 0; +} + +static void +barprt(fp, c, label) +FILE *fp; +int c, label; +{ + int i, mask, bar, wide; + + if (!(i = code39[c])) + return; + if (islower(c)) + c = toupper(c); + if (label) + (void) fprintf(fp, "(%c) l", c); + else + (void) fputs(" ", fp); + for (bar = 1, mask = 0400; mask; bar = 1 - bar, mask >>= 1) { + wide = mask & i; + if (bar) { + if (wide) + ++right; + (void) fprintf(fp, " %d %s", right, wide ? "w" : "n"); + right = (wide ? 2 : 1); + } + else + right += (wide ? 3 : 1); + } + (void) fputs("\n", fp); + ++right; +} diff --git a/sys/src/cmd/postscript/misc/lp.model b/sys/src/cmd/postscript/misc/lp.model new file mode 100755 index 000000000..966621e39 --- /dev/null +++ b/sys/src/cmd/postscript/misc/lp.model @@ -0,0 +1,66 @@ + +# qmsps800 mac 10/22/86 +# +LPDEST=`basename $0` +QMS_FILE="$1" +DATE="`date +%D`" +TIME="`date +%T`" +owner="$2" +site=`uname` +port="`/usr/bin/lpstat -v$LPDEST | sed -e 's/.*: //'`" +filter_cmd="/usr/lbin/postscript/postio" +filter="$filter_cmd -l $port" +landscape="" formsperpage="" +path=/usr/lbin/postscript +printer=postprint +bannerflag=ON +prev="| $path/postreverse" + +for i in $5 +do + case "$i" in + L2) + formsperpage="-n2" + ;; + land) + landscape="-pland" + ;; + dpost|postprint|posttek|postbgi|postdmd|postio) + printer="$i" + ;; + + postreverse) + prev="" + ;; + nobanner) + bannerflag=OFF + ;; + F*) + QMS_FILE="`expr $i : 'F\(.*\)'`" + ;; + esac +done + +if [ -n "$filter_cmd" -a ! -x "$filter_cmd" ] +then + disable -r"can't execute filter: $filter_cmd" $LPDEST + exit 1 +fi + +shift; shift; shift; shift; shift +files="$*" +cp /usr/spool/lp/model/banner.ps /tmp/ban.$$ +echo "($QMS_FILE) ($LPDEST) ($TIME) ($DATE) ($owner) banner" >> /tmp/ban.$$ +if [ "$printer" = "postio" ] + then + eval $filter $files 2> /dev/null +else + eval $path/$printer $landscape $formsperpage $files $prev | $filter 2> /dev/null + fi +if [ "$bannerflag" = "ON" ] + then + eval $filter /tmp/ban.$$ 2> /dev/null + fi +rm -f /tmp/ban.$$ +exit 0 + diff --git a/sys/src/cmd/postscript/misc/macfont.c b/sys/src/cmd/postscript/misc/macfont.c new file mode 100755 index 000000000..dffbe3d21 --- /dev/null +++ b/sys/src/cmd/postscript/misc/macfont.c @@ -0,0 +1,296 @@ +/* + * + * Program that converts Macintosh font files to a format that works on Unix + * systems. Essentially all the information needed came from the Adobe paper + * "Supporting Downloadable PostScript Fonts". To use the program type, + * + * macfont font.mac >font.unix + * + * where font.mac is the font file, exactly as it came over from a Macintosh, + * and font.unix is equivalent host resident font file usable on Unix systems. + * + */ + +#include <stdio.h> +#include <signal.h> + +#define OFF 0 +#define ON 1 + +#define NON_FATAL 0 +#define FATAL 1 + +#define FALSE 0 +#define TRUE 1 + +char **argv; +int argc; + +char *prog_name; + +int x_stat; +int debug = OFF; +int ignore = OFF; + +FILE *fp_in = stdin; +FILE *fp_out = stdout; + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * Macintosh to Unix font converter. + * + */ + + argc = agc; + argv = agv; + prog_name = argv[0]; + + options(); + arguments(); + exit(x_stat); + +} /* End of main */ + +/*****************************************************************************/ + +options() + +{ + + int ch; + char *names = "DI"; + + extern char *optarg; + extern int optind; + +/* + * + * Command line options. + * + */ + + while ( (ch = getopt(argc, argv, names)) != EOF ) { + switch ( ch ) { + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +arguments() + +{ + + +/* + * + * Everything else is an input file. No arguments or '-' means stdin. + * + */ + + if ( argc < 1 ) + conv(); + else + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + conv(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + +} /* End of arguments */ + +/*****************************************************************************/ + +conv() + +{ + + int blocksize; + int blocktype; + +/* + * + * The first four bytes (in a block) are the block size, the fifth is the block + * type, and the sixth always appears to be NULL. Type 0 blocks are comments and + * are always skipped. Type 1 blocks are ASCII text, type 2 is binary data that + * should be converted to hex, while type 5 blocks represent the end of the font + * file. Commment block lengths appear to be from the first byte, while other + * lengths seem to be measured from block type byte (ie. the fifth byte). Type + * four blocks aren't used, while type 3 blocks mean an end of file indication + * should be sent to the printer. Haven't done anything with type 3 blocks. + * + */ + + while ( 1 ) { + blocksize = getint(fp_in); + blocktype = getc(fp_in); + getc(fp_in); + if ( debug == ON ) + fprintf(stderr, "blocktype = %d, blocksize = %d\n", blocktype, blocksize); + switch ( blocktype ) { + case 0: /* comment - skip blockcount bytes */ + fseek(fp_in, (long) blocksize - 6, 1); + break; + + case 1: + asciitext(blocksize - 2); + break; + + case 2: + hexdata(blocksize - 2); + break; + + case 3: + case 4: + error(FATAL, "resource type %d not implemented", blocktype); + break; + + case 5: + return; + + default: + error(FATAL, "unknown resource type %d", blocktype); + } /* End switch */ + } /* End while */ + +} /* End of conv */ + +/*****************************************************************************/ + +asciitext(count) + + int count; /* bytes left in the block */ + +{ + + int ch; + int i = 0; + +/* + * + * Handles type 1 (ie. ASCII text) blocks. Changing carriage returns to newlines + * is all I've done. + * + */ + + for ( i = 0; i < count; i++ ) { + if ( (ch = getc(fp_in)) == '\r' ) + ch = '\n'; + putc(ch, fp_out); + } /* End for */ + +} /* End of asciitext */ + +/*****************************************************************************/ + +hexdata(count) + + int count; /* bytes left in the block */ + +{ + + int i; + int n; + +/* + * + * Reads the next count bytes and converts each byte to hex. Also starts a new + * line every 80 hex characters. + * + */ + + for ( i = 0, n = 0; i < count; i++ ) { + fprintf(fp_out, "%.2X", getc(fp_in)); + if ( (++n % 40) == 0 ) + putc('\n', fp_out); + } /* End for */ + +} /* End of hexdata */ + +/*****************************************************************************/ + +getint() + +{ + + int val; + int i; + +/* + * + * Reads the next four bytes into an integer and returns the value to the caller. + * First two bytes are probably always 0. + * + */ + + for ( i = 0, val = (getc(fp_in) & 0377); i < 3; i++ ) + val = (val << 8) | (getc(fp_in) & 0377); + + return(val); + +} /* End of getint */ + +/*****************************************************************************/ + +error(kind, mesg, a1, a2, a3) + + + int kind; + char *mesg; + unsigned a1, a2, a3; + +{ + +/* + * + * Print *mesg then quit if kind is FATAL. + * + */ + + if ( mesg != NULL && *mesg != '\0' ) { + fprintf(stderr, "%s: ", prog_name); + fprintf(stderr, mesg, a1, a2, a3); + putc('\n', stderr); + } /* End if */ + + if ( kind == FATAL && ignore == OFF ) + exit(x_stat | 01); + +} /* End of error */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/misc/pscrypt.c b/sys/src/cmd/postscript/misc/pscrypt.c new file mode 100755 index 000000000..316be5887 --- /dev/null +++ b/sys/src/cmd/postscript/misc/pscrypt.c @@ -0,0 +1,333 @@ +/* + * + * Adobe's encryption/decryption algorithm for eexec and show. Runs in + * eexec mode unless told otherwise. Use, + * + * pscrypt file.cypher > file.clear + * + * to decrypt eexec input. Assumes file.cypher is hex with the key as the + * first four bytes, and writes file.clear as binary (omitting the key). + * Use + * + * pscrypt -e12ab34ef file.clear >file.cypher + * + * to encrypt file.clear (for eexec) using 12ab34ef as the key. Input is + * binary and output is hex. The key must be given as a hex number. Use + * -sshow to encrypt or decrypt a CharString or Subr, + * + * pscrypt -sshow file.cypher > file.clear + * + * Use -b or -x to read binary or hex input, and -B or -X to output binary + * or hex. + * + */ + +#include <stdio.h> +#include <ctype.h> + +#define ENCRYPT 0 +#define DECRYPT 1 + +#define NOTSET -1 +#define BINARY 0 +#define HEX 1 +#define LINELENGTH 40 + +#define CHARSTRING 4330 +#define EEXEC 55665 +#define MAGIC1 52845 +#define MAGIC2 22719 + +int argc; +char **argv; + +int mode = DECRYPT; +int input = NOTSET; +int output = NOTSET; +int outoffset = NOTSET; +int inoffset = NOTSET; + +int cryptkey = 0; /* encryption key set with -e */ +int linelength = LINELENGTH; /* only for hex output */ +int lastchar = 0; + +unsigned long seed = EEXEC; +unsigned long key; + +FILE *fp_in = stdin; + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * Implementation of the encryption/decryption used by eexec and show. + * + */ + + argc = agc; + argv = agv; + + options(); + initialize(); + arguments(); + + exit(0); + +} /* End of main */ + +/*****************************************************************************/ + +options() + +{ + + int ch; + char *names = "bde:l:os:xBSX"; + + extern char *optarg; + extern int optind; + +/* + * + * Command line options. + * + */ + + while ( (ch = getopt(argc, argv, names)) != EOF ) + switch ( ch ) { + case 'b': /* binary input */ + input = BINARY; + break; + + case 'd': /* decrypt */ + mode = DECRYPT; + break; + + case 'e': /* encrypt */ + mode = ENCRYPT; + if ( *optarg == '0' && *optarg == 'x' ) + optarg += 2; + sscanf(optarg, "%8x", &cryptkey); + break; + + case 'l': /* line length hex output */ + linelength = atoi(optarg); + break; + + case 'o': /* output all bytes - debugging */ + outoffset = 0; + break; + + case 's': /* seed */ + if ( *optarg == 'e' ) + seed = EEXEC; + else if ( *optarg == 's' ) + seed = CHARSTRING; + else if ( *optarg == '0' && *(optarg+1) == 'x' ) + sscanf(optarg+2, "%x", &seed); + else if ( *optarg == '0' ) + sscanf(optarg, "%o", &seed); + else sscanf(optarg, "%d", &seed); + break; + + case 'x': /* hex input */ + input = HEX; + break; + + case 'B': /* binary output */ + output = BINARY; + break; + + case 'X': /* hex output */ + output = HEX; + break; + + case '?': /* don't understand the option */ + fprintf(stderr, "bad option -%c\n", ch); + exit(1); + break; + + default: /* don't know what to do for ch */ + fprintf(stderr, "missing case for option -%c\n", ch); + exit(1); + break; + } /* End switch */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +initialize() + +{ + +/* + * + * Initialization that has to be done after the options. + * + */ + + key = seed; + + if ( mode == DECRYPT ) { + input = (input == NOTSET) ? HEX : input; + output = (output == NOTSET) ? BINARY : output; + inoffset = (inoffset == NOTSET) ? 0 : inoffset; + outoffset = (outoffset == NOTSET) ? -4 : outoffset; + } else { + input = (input == NOTSET) ? BINARY : input; + output = (output == NOTSET) ? HEX : output; + inoffset = (inoffset == NOTSET) ? 4 : inoffset; + outoffset = (outoffset == NOTSET) ? 0 : outoffset; + } /* End else */ + + if ( linelength <= 0 ) + linelength = LINELENGTH; + +} /* End of initialize */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Everything left is an input file. No arguments or '-' means stdin. + * + */ + + if ( argc < 1 ) + crypt(); + else + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) { + fprintf(stderr, "can't open %s\n", *argv); + exit(1); + } /* End if */ + crypt(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + +} /* End of arguments */ + +/*****************************************************************************/ + +crypt() + +{ + + unsigned int cypher; + unsigned int clear; + +/* + * + * Runs the encryption/decryption algorithm. + * + */ + + while ( lastchar != EOF ) { + cypher = nextbyte(); + clear = ((key >> 8) ^ cypher) & 0xFF; + key = (key + (mode == DECRYPT ? cypher : clear)) * MAGIC1 + MAGIC2; + if ( ++outoffset > 0 && lastchar != EOF ) { + if ( output == HEX ) { + printf("%.2X", clear); + if ( linelength > 0 && (outoffset % linelength) == 0 ) + putchar('\n'); + } else putchar(clear); + } /* End if */ + } /* End while */ + +} /* End of crypt */ + +/*****************************************************************************/ + +nextbyte() + +{ + + int val = EOF; + +/* + * + * Returns the next byte. Uses cryptkey (i.e. what followed -e) while inoffset is + * positive, otherwise reads (hex or binary) from fp_in. + * + */ + + if ( inoffset-- > 0 ) + val = (cryptkey >> (inoffset*8)) & 0xFF; + else if ( input == HEX ) { + if ( (val = nexthexchar()) != EOF ) + val = (val << 4) | nexthexchar(); + } else if ( input == BINARY ) + val = Getc(fp_in); + + return(val); + +} /* End of nextbyte */ + +/*****************************************************************************/ + +nexthexchar() + +{ + + int ch; + +/* + * + * Reads the next hex character. + * + */ + + while ( (ch = Getc(fp_in)) != EOF && ! isxdigit(ch) ) ; + + if ( isdigit(ch) ) + ch -= '0'; + else if ( isupper(ch) ) + ch -= 'A' - 10; + else if ( islower(ch) ) + ch -= 'a' - 10; + + return(ch); + +} /* End of nexthexchar */ + +/*****************************************************************************/ + +Getc(fp) + + FILE *fp; + +{ + +/* + * + * Reads the next byte from *fp, sets lastchar, and returns the character. + * + */ + + return(lastchar = getc(fp)); + +} /* End of Getc */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/misc/setbaud.ps b/sys/src/cmd/postscript/misc/setbaud.ps new file mode 100755 index 000000000..93148d0c4 --- /dev/null +++ b/sys/src/cmd/postscript/misc/setbaud.ps @@ -0,0 +1,9 @@ +% +% Sets baud rate to 9600, options to 0 assuming the password is 0. +% + +serverdict begin + 0 exitserver + statusdict begin + 25 9600 0 setsccbatch + end diff --git a/sys/src/cmd/postscript/mkfile b/sys/src/cmd/postscript/mkfile new file mode 100755 index 000000000..7b9f4b3c0 --- /dev/null +++ b/sys/src/cmd/postscript/mkfile @@ -0,0 +1,50 @@ +</$objtype/mkfile + +<config + +# +# $(TARGETS) is the default list of things built by make. +# +# buildtables + +TARGETS=common\ + cropmarks\ + download\ + grabit\ + hardcopy\ + mpictures\ + postgif\ + postprint\ + postreverse\ + posttek\ + printfont\ + psencoding\ + psfiles\ + g3p9bit\ + p9bitpost\ + tcpostio\ + text2post\ + tr2post + +# UNIX remnants +# trofftable\ +# picpack\ +# postbgi\ +# postdaisy\ +# postdmd\ +# postmd +# postio + +default:V: all + +$TARGETS:V: + cd $target + mk all + +&:VQ: + test -d $POSTBIN || mkdir $POSTBIN + for (i in $TARGETS) @{ + echo ---- Making $target in $i ----; + cd $i; + mk $target + } diff --git a/sys/src/cmd/postscript/mpictures/mkfile b/sys/src/cmd/postscript/mpictures/mkfile new file mode 100755 index 000000000..cc4d48c24 --- /dev/null +++ b/sys/src/cmd/postscript/mpictures/mkfile @@ -0,0 +1,18 @@ +</$objtype/mkfile + +<../config + +TMACDIR=/sys/lib/tmac + +all:V: tmac.pictures + +install installall:V: $TMACDIR/tmac.pictures + +clean nuke:V: + rm -f tmac.pictures + +$TMACDIR/tmac.pictures: tmac.pictures + cp $prereq $target + +tmac.pictures : pictures.sr + cp $prereq $target diff --git a/sys/src/cmd/postscript/mpictures/pictures.sr b/sys/src/cmd/postscript/mpictures/pictures.sr new file mode 100755 index 000000000..6ff4f96e7 --- /dev/null +++ b/sys/src/cmd/postscript/mpictures/pictures.sr @@ -0,0 +1,154 @@ +.de PI \" Picture Include +. \" $1=file(page) $2=height,width,yoff,xoff $3=flags +. \" Height, width, xoff, and yoff are for the frame, flags is for the +. \" picture. Default dimensions are inches. +\\X'PI:\\n(.o:\\n(.i:\\n(.l:\\n(.t:\\$1:\\$2:\\$3:'\\c +.. +.nr FT 0 +.de BP \" Begin a Picture +. \" +. \" $1=file(page) $2=height $3=width $4=position $5=offset $6=flags $7=label +. \" +. \" Height, width, position, and offset are for the frame, flags is for +. \" the picture. The postion flag should be l, c, r, or "". Omitting the +. \" position argument is also allowed for compatibility with the original +. \" version of the macro. In that case offset is taken relative to your +. \" left margin. +.if \\n(FT>1 .EP +. \" Need these when we switch environments. +.nr Ov \\n(.v +.nr Oi \\n(.i +.nr Ol \\n(.l +. \" Remember the arguments - sometimes as both a string and number register. +.nr $2 \\$2i +.nr $3 \\$3i +.nr $4 \\$4i +.ds $4 \\$4 +.nr $5 \\$5i +.ds $5 \\$6 +.ds $6 \\$7 +. \" Accept a few unadvertised position flags. +.if '\\*($4'L' .ds $4 l +.if '\\*($4'C' .ds $4 c +.if '\\*($4'R' .ds $4 r +. \" A null with more than three arguments means l. +.if \\n(.$>3 .if '\\*($4'' .ds $4 l +. \" Default frame dimensions if missing, zero, or null. +.if !\\n($2>0 .nr $2 3.0i +.if !\\n($3>0 .nr $3 \\n(.lu-\\n(.iu-\\n($4u +.if !\\n($3>0 .nr $3 \\n($2u +. \" Figure out the offset that will be used the rest of the way. +.if '\\*($4'l' .nr $4 \\n($5u +.if '\\*($4'c' .nr $4 (\\n(.lu-\\n(.iu-\\n($3u)/2u+\\n($5u +.if '\\*($4'r' .nr $4 \\n(.lu-\\n(.iu-\\n($3u+\\n($5u +. \" If we haven't recognized the position flag assume it wasn't given and +. \" treat argument four as an offset from the left. +.if !'\\*($4'l' .if !'\\*($4'c' .if !'\\*($4'r' .ds $5 \\$5 +.if !'\\*($4'l' .if !'\\*($4'c' .if !'\\*($4'r' .ds $6 \\$6 +. \" Set increments for line length and indent. +.nr Ii \\n($3u+\\n($4u+.1i +.nr Il \\n(.lu-\\n(.iu-\\n($4u+.1i +. \" Set the frame type to one of: +. \" 0 - frame is as wide as a line of text - skip over it. +. \" 1 - fits in left or right margins +. \" 2 - fill with text on the right +. \" 3 - on the left +. \" 4 - or on both sides of the frame +. \" 5 - only set in EP if FT was 4 and now filling on the right. +. \" Assume the frame is as wide as a line of text, then check dimensions +. \" to see what's really true. The order of these tests is important! +.nr FT 0 +.if \\n($4u>1.0i .nr FT 3 +.if \\n($4u+\\n(.iu>=\\n(.lu .nr FT 1 +.if \\n($3u+\\n($4u+\\n(.iu+1.0i<\\n(.lu .nr FT 2 +.if \\n($3u+\\n($4u<=0 .nr FT 1 +.if \\n(FT=2 .if \\n($4u>1.0i .nr FT 4 +. \" Ask for some vertical space - labeled pictures need a little extra, +. \" margin pictures a little less. +.if \\n(FT=1 .if '\\*($6'' .ne \\n($2u +.if \\n(FT=1 .if !'\\*($6'' .ne \\n($2u+2v +.if !\\n(FT=1 .if '\\*($6'' .ne \\n($2u+3v +.if !\\n(FT=1 .if !'\\*($6'' .ne \\n($2u+5v +. \" Save our place, draw the picture, label it, and return. Need precise +. \" control of when \X'...' is put out - thus the new environment. +.mk Oh +.ev 1 +.in \\n(Oiu +.ll \\n(Olu +.vs \\n(Ovu +.if \\n(FT=1 .sp -1v +.if \\n(FT=1 .PI \\$1 \\n($2u,\\n($3u,\\n(.vu,\\n($4u t\\*($5 +.if !\\n(FT=1 .PI \\$1 \\n($2u,\\n($3u,\\n(.vu,\\n($4u \\*($5 +.in +.ll +.vs +.ev +.lt \\n($3u +.tl \(ts\(ts\\h'\\n($4u+\\n(.iu'\\v'\\n($2u+1.5v'\\*($6\\v'-\\n($2u-1.5v'\\h'-\\n($4u-\\n(.iu'\(ts\(ts +.lt +'sp |\\n(Ohu +. \" Figure out what to do with the text that follows. +.if !'\\*($6'' .nr $2 +2v +.if \\n(FT=0 .sp \\n($2u+2v +.if \\n(FT=1 .nr FT 0 +.if \\n(FT=2 'in +\\n(Iiu +.if \\n(FT>2 .ll -\\n(Ilu +.if \\n(FT>1 .di BB +.if \\n(FT>1 .dt \\n($2u+2v+1u EP +. \" Clean things up. +.rr $2 +.rr $3 +.rr $4 +.rm $4 +.rr $5 +.rm $5 +.rm $6 +.rr Oh +.rr Oi +.rr Ol +.rr Ov +.if \\n(FT=0 .EP +.. +.de EP \" End the Picture - Normally called from a trap, although it can be used +. \" on its own to mark the end of a picture. +.nr Ot 0 +.if \\n(.tu<\\n(.pu .nr Ot \\n(.tu +.if \\n(Ot>0 .if \\n(FT=4 .nr FT 3 +.if \\n(FT<2 .nr Ot 0 +.if \\n(Ot>0 .br +.if \\n(FT=5 .nr Ot 0 +.if \\n(FT>1 \{\ +. ev 1 +. eo +. br +. di +. nf +. in 0 +. BB +. in +. fi +. ec +. ev +. rm BB\} +.if \\n(FT=5 \{\ +. nr FT 2 +' sp |\\n(Nhu+1v\} +.if \\n(FT=4 \{\ +. mk Nh +. nr Nh -1v +. nr FT 5 +' sp -\\n(dnu+1v +' in +\\n(Iiu +. ll +\\n(Ilu +. di BB +. dt \\n(dnu-2v+1u EP\} +.if \\n(FT=2 'in -\\n(Iiu +.if \\n(FT=3 .ll +\\n(Ilu +.if \\n(FT<4 .nr FT 0 +.if \\n(Ot>0 .sp \\n(Otu +.rr Ot +.if \\n(FT=0 \{\ +. rr Nh +. rr Ii +. rr Il\} +.. diff --git a/sys/src/cmd/postscript/p9bitpost/mkfile b/sys/src/cmd/postscript/p9bitpost/mkfile new file mode 100755 index 000000000..f99668432 --- /dev/null +++ b/sys/src/cmd/postscript/p9bitpost/mkfile @@ -0,0 +1,17 @@ +</$objtype/mkfile + + +<../config + +COMMONDIR=../common + +TARG=p9bitpost +OFILES=pslib.$O\ + p9bitpost.$O\ + +BIN=$POSTBIN + +LIB=/$objtype/lib/libmemdraw.a +< /sys/src/cmd/mkone + +CFLAGS=-w -I$COMMONDIR diff --git a/sys/src/cmd/postscript/p9bitpost/p9bitpost.c b/sys/src/cmd/postscript/p9bitpost/p9bitpost.c new file mode 100755 index 000000000..2816c5139 --- /dev/null +++ b/sys/src/cmd/postscript/p9bitpost/p9bitpost.c @@ -0,0 +1,105 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include "pslib.h" + +#define HDLEN 60 + +int dpi = -1; +int debug = 0; +int landscape = 0; +char *file = "<stdin>"; + +int paperlength = 11*72; +int paperwidth = 612; /* 8.5*72 */ + +void +error(char *s) +{ + fprint(2, "p9bitpost: can't %s file %s: %r\n", s, file); + exits("error"); +} + +void +main(int argc, char *argv[]) { + int i, fd = 0; + double xmag = 1.0, ymag = 1.0; + char *optstr, *Patch; + Memimage *memimage; + + Patch = nil; + for (i=1; i<argc; i++) { + if (*argv[i] != '-') break; + switch(argv[i][1]) { + case 'b': + if (argv[i][2] == '\0') + dpi = atoi(argv[++i]); + else + dpi = atoi(&(argv[i][2])); + break; + case 'd': + debug = 1; + break; + case 'm': + if (argv[i][2] == '\0') + optstr = argv[++i]; + else + optstr = &(argv[i][2]); + if ((optstr=strtok(optstr, " ,")) != 0) + xmag = ymag = atof(optstr); + if ((optstr=strtok(0, " ,")) != 0) + ymag = atof(optstr); + break; + case 'L': + landscape = 1; + break; + case 'P': + if (argv[i][2] == '\0') + Patch = argv[++i]; + else + Patch = &(argv[i][2]); + break; + case 'p': + optstr = argv[++i]; + if(optstr == nil) + goto Usage; + paperlength = 72*atof(optstr); + optstr = argv[++i]; + if(optstr == nil) + goto Usage; + paperwidth = 72*atof(optstr); + if(paperlength < 72 || paperwidth < 72) + goto Usage; + break; + default: + Usage: + fprint(2, "usage: %s [-b dpi] [-m magnification] [-L] [-P postscript_patch_string] [-p paperlength paperwidth (in inches)] inputfile\n", argv[0]); + exits("usage"); + } + } + + if (i < argc) { + file = argv[i]; + fd = open(file, OREAD); + if (fd < 0) + error("open"); + } + + memimageinit(); + memimage = readmemimage(fd); + if(memimage == nil) + error("alloc memory for"); + + psinit(0, 0); + if(xmag != 1.0) + psopt("xmagnification", &xmag); + if(ymag != 1.0) + psopt("ymagnification", &ymag); + if(landscape) + psopt("landscape", &landscape); + if(Patch) + psopt("Patch", &Patch); + image2psfile(1, memimage, dpi); + exits(""); +} diff --git a/sys/src/cmd/postscript/p9bitpost/pslib.c b/sys/src/cmd/postscript/p9bitpost/pslib.c new file mode 100755 index 000000000..afe2e7646 --- /dev/null +++ b/sys/src/cmd/postscript/p9bitpost/pslib.c @@ -0,0 +1,813 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <bio.h> +#include "pslib.h" +/* implement PsLib; +/* +/* include "sys.m"; +/* sys: Sys; +/* +/* include "draw.m"; +/* draw : Draw; +/* Image, Display,Rect,Point : import draw; +/* +/* include "bufio.m"; +/* bufmod : Bufio; +/* +/* include "tk.m"; +/* tk: Tk; +/* Toplevel: import tk; +/* +/* Iobuf : import bufmod; +/* +/* include "string.m"; +/* str : String; +/* +/* include "daytime.m"; +/* time : Daytime; +/* +/* include "pslib.m"; +/* +/* ASCII,RUNE,IMAGE : con iota; +/* +*/ +struct iteminfo { + int itype; + int offset; /* offset from the start of line. */ + int width; /* width.... */ + int ascent; /* ascent of the item */ + int font; /* font */ + int line; /* line its on */ + char *buf; +}; + +struct lineinfo { + int xorg; + int yorg; + int width; + int height; + int ascent; +}; + + +/* font_arr := array[256] of {* => (-1,"")}; +/* remap := array[20] of (string,string); +/* +/* PXPI : con 100; +/* PTPI : con 100; +/* +*/ +char *noinit = "pslib not properly initialized"; +/* +*/ +static int boxes; +static int debug; +static int totitems; +static int totlines; +static int curfont; +static char *def_font; +static int def_font_type; +static int curfonttype; +static int pagestart; +static int started; + +static int bps; +static int width; +static int height; +static int iwidth; +static int iheight; +static int xstart; +static int ystart; +static double xmagnification = 1.0, ymagnification = 1.0; +static int rotation = 0; +static int landscape = 0; +static char *Patch = nil; + +/* ctxt : ref Draw->Context; +/* t : ref Toplevel; +*/ +char* +psinit(int box, int deb) { /* d: ref Toplevel, */ +/* t=d; */ + debug = deb; + totlines=0; + totitems=0; + pagestart=0; + boxes=box; /* #box; */ + curfont=0; +/* e := loadfonts(); +/* if (e != "") +/* return e; +*/ + started=1; + return ""; +} + +/* stats() : (int,int,int) +/* { +/* return (totitems,totlines,curfont); +/* } +/* +/* loadfonts() : string +/* { +/* input : string; +/* iob:=bufmod->open("/fonts/psrename",bufmod->OREAD); +/* if (iob==nil) +/* return sys->sprint("can't open /fonts/psrename: %r"); +/* i:=0; +/* while((input=iob.gets('\n'))!=nil){ +/* (tkfont,psfont):=str->splitl(input," "); +/* psfont=psfont[1:len psfont -1]; +/* remap[i]=(tkfont,psfont); +/* i++; +/* } +/* return ""; +/* } +/* +*/ +static char *username; + +int +preamble(Biobuf *ioutb, Rectangle bb) { + + if (!started) return 1; + username = getuser(); + if(bb.max.x == 0 && bb.max.y == 0) { + bb.max.x = 612; + bb.max.y = 792; + } + Bprint(ioutb, "%%!PS-Adobe-3.0\n"); + Bprint(ioutb, "%%%%Creator: PsLib 1.0 (%s)\n",username); + Bprint(ioutb, "%%%%CreationDate: %s", ctime(time(nil))); + Bprint(ioutb, "%%%%Pages: (atend) \n"); + Bprint(ioutb, "%%%%BoundingBox: %d %d %d %d\n", bb.min.x, bb.min.y, bb.max.x, bb.max.y); + Bprint(ioutb, "%%%%EndComments\n"); + Bprint(ioutb, "%%%%BeginProlog\n"); + Bprint(ioutb, "/doimage {\n"); + Bprint(ioutb, "/grey exch def\n"); + Bprint(ioutb, "/bps exch def\n"); + Bprint(ioutb, "/width exch def\n"); + Bprint(ioutb, "/height exch def\n"); + Bprint(ioutb, "/xstart exch def\n"); + Bprint(ioutb, "/ystart exch def\n"); + Bprint(ioutb, "/iwidth exch def\n"); + Bprint(ioutb, "/ascent exch def\n"); + Bprint(ioutb, "/iheight exch def\n"); + Bprint(ioutb, "gsave\n"); + if(boxes) + Bprint(ioutb, "xstart ystart iwidth iheight rectstroke\n"); +/* # if bps==8, use inferno colormap; else (bps < 8) it's grayscale or true color */ + Bprint(ioutb, "bps 8 eq grey false eq and {\n"); + Bprint(ioutb, " [/Indexed /DeviceRGB 255 <\n"); + Bprint(ioutb, " ffffff ffffaa ffff55 ffff00 ffaaff ffaaaa ffaa55 ffaa00 ff55ff ff55aa ff5555 ff5500\n"); + Bprint(ioutb, " ff00ff ff00aa ff0055 ff0000 ee0000 eeeeee eeee9e eeee4f eeee00 ee9eee ee9e9e ee9e4f\n"); + Bprint(ioutb, " ee9e00 ee4fee ee4f9e ee4f4f ee4f00 ee00ee ee009e ee004f dd0049 dd0000 dddddd dddd93\n"); + Bprint(ioutb, " dddd49 dddd00 dd93dd dd9393 dd9349 dd9300 dd49dd dd4993 dd4949 dd4900 dd00dd dd0093\n"); + Bprint(ioutb, " cc0088 cc0044 cc0000 cccccc cccc88 cccc44 cccc00 cc88cc cc8888 cc8844 cc8800 cc44cc\n"); + Bprint(ioutb, " cc4488 cc4444 cc4400 cc00cc aaffaa aaff55 aaff00 aaaaff bbbbbb bbbb5d bbbb00 aa55ff\n"); + Bprint(ioutb, " bb5dbb bb5d5d bb5d00 aa00ff bb00bb bb005d bb0000 aaffff 9eeeee 9eee9e 9eee4f 9eee00\n"); + Bprint(ioutb, " 9e9eee aaaaaa aaaa55 aaaa00 9e4fee aa55aa aa5555 aa5500 9e00ee aa00aa aa0055 aa0000\n"); + Bprint(ioutb, " 990000 93dddd 93dd93 93dd49 93dd00 9393dd 999999 99994c 999900 9349dd 994c99 994c4c\n"); + Bprint(ioutb, " 994c00 9300dd 990099 99004c 880044 880000 88cccc 88cc88 88cc44 88cc00 8888cc 888888\n"); + Bprint(ioutb, " 888844 888800 8844cc 884488 884444 884400 8800cc 880088 55ff55 55ff00 55aaff 5dbbbb\n"); + Bprint(ioutb, " 5dbb5d 5dbb00 5555ff 5d5dbb 777777 777700 5500ff 5d00bb 770077 770000 55ffff 55ffaa\n"); + Bprint(ioutb, " 4fee9e 4fee4f 4fee00 4f9eee 55aaaa 55aa55 55aa00 4f4fee 5555aa 666666 666600 4f00ee\n"); + Bprint(ioutb, " 5500aa 660066 660000 4feeee 49dddd 49dd93 49dd49 49dd00 4993dd 4c9999 4c994c 4c9900\n"); + Bprint(ioutb, " 4949dd 4c4c99 555555 555500 4900dd 4c0099 550055 550000 440000 44cccc 44cc88 44cc44\n"); + Bprint(ioutb, " 44cc00 4488cc 448888 448844 448800 4444cc 444488 444444 444400 4400cc 440088 440044\n"); + Bprint(ioutb, " 00ff00 00aaff 00bbbb 00bb5d 00bb00 0055ff 005dbb 007777 007700 0000ff 0000bb 000077\n"); + Bprint(ioutb, " 333333 00ffff 00ffaa 00ff55 00ee4f 00ee00 009eee 00aaaa 00aa55 00aa00 004fee 0055aa\n"); + Bprint(ioutb, " 006666 006600 0000ee 0000aa 000066 222222 00eeee 00ee9e 00dd93 00dd49 00dd00 0093dd\n"); + Bprint(ioutb, " 009999 00994c 009900 0049dd 004c99 005555 005500 0000dd 000099 000055 111111 00dddd\n"); + Bprint(ioutb, " 00cccc 00cc88 00cc44 00cc00 0088cc 008888 008844 008800 0044cc 004488 004444 004400\n"); + Bprint(ioutb, " 0000cc 000088 000044 000000>\n"); + Bprint(ioutb, " ] setcolorspace\n"); + Bprint(ioutb, " /decodemat [0 255] def\n"); + Bprint(ioutb, "}\n"); +/* # else, bps != 8 */ + Bprint(ioutb, "{\n"); +/* is it greyscale or is it 24-bit color? */ + Bprint(ioutb, " grey true eq {\n"); + Bprint(ioutb, " [/DeviceGray] setcolorspace\n"); + Bprint(ioutb, " /decodemat [1 0] def\n"); + Bprint(ioutb, " }\n"); + Bprint(ioutb, " {\n"); +/* must be color */ + Bprint(ioutb, " [/DeviceRGB] setcolorspace\n"); + Bprint(ioutb, " /bps 8 def\n"); + Bprint(ioutb, " /decodemat [1 0 1 0 1 0] def\n"); + Bprint(ioutb, " }\n"); + Bprint(ioutb, " ifelse\n"); + Bprint(ioutb, "}\n"); + Bprint(ioutb, "ifelse\n"); + Bprint(ioutb, "/xmagnification %g def\n", xmagnification); + Bprint(ioutb, "/ymagnification %g def\n", ymagnification); + Bprint(ioutb, "/rotation %d def\n", rotation); + Bprint(ioutb, "xstart ystart translate rotation rotate\n"); + Bprint(ioutb, "iwidth xmagnification mul iheight ymagnification mul scale\n"); + Bprint(ioutb, "<<\n"); + Bprint(ioutb, " /ImageType 1\n"); + Bprint(ioutb, " /Width width \n"); + Bprint(ioutb, " /Height height \n"); + Bprint(ioutb, " /BitsPerComponent bps %% bits/sample\n"); + Bprint(ioutb, " /Decode decodemat %% Brazil/Inferno cmap or DeviceGray value\n"); + Bprint(ioutb, " /ImageMatrix [width 0 0 height neg 0 height]\n"); + Bprint(ioutb, " /DataSource currentfile /ASCII85Decode filter\n"); + Bprint(ioutb, ">> \n"); + Bprint(ioutb, "image\n"); + Bprint(ioutb, "grestore\n"); + Bprint(ioutb, "} def\n"); + Bprint(ioutb, "%%%%EndProlog\n"); + if (Patch != nil) + Bprint(ioutb, "%s\n", Patch); + return 0; +} + +int +trailer(Biobuf *ioutb ,int pages) { + if(!started) + return 1; + Bprint(ioutb, "%%%%Trailer\n%%%%Pages: %d\n%%%%EOF\n", pages); + return 0; +} + +void +printnewpage(int pagenum, int end, Biobuf *ioutb) +{ + if (!started) return; + if (end){ +/* # bounding box */ + if (boxes){ + Bprint(ioutb, "18 18 moveto 594 18 lineto 594 774 lineto 18 774 lineto closepath stroke\n"); + } + Bprint(ioutb, "showpage\n%%%%EndPage %d %d\n", pagenum, pagenum); + } else + Bprint(ioutb, "%%%%Page: %d %d\n", pagenum, pagenum); +} + +/* int +/* printimage(FILE *ioutb, struct lineinfo line, struct iteminfo imag) { +/* int RM; +/* +/* RM=612-18; +/* class:=tk->cmd(t,"winfo class "+imag.buf); +/* #sys->print("Looking for [%s] of type [%s]\n",imag.buf,class); +/* if (line.xorg+imag.offset+imag.width>RM) +/* imag.width=RM-line.xorg-imag.offset; +/* case class { +/* "button" or "menubutton" => +/* # try to get the text out and print it.... +/* ioutb.puts(sys->sprint("%d %d moveto\n",line.xorg+imag.offset, +/* line.yorg)); +/* msg:=tk->cmd(t,sys->sprint("%s cget -text",imag.buf)); +/* ft:=tk->cmd(t,sys->sprint("%s cget -font",imag.buf)); +/* sys->print("font is [%s]\n",ft); +/* ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n", +/* line.xorg+imag.offset,line.yorg,imag.width, +/* line.height)); +/* return (class,msg); +/* "label" => +/* (im,im2,err) := tk->imageget(t,imag.buf); +/* if (im!=nil){ +/* bps := 1<<im.ldepth; +/* ioutb.puts(sys->sprint("%d %d %d %d %d %d %d %d doimage\n", +/* im.r.dy(),line.ascent,im.r.dx(),line.yorg, +/* line.xorg+imag.offset,im.r.dy(), im.r.dx(), bps)); +/* imagebits(ioutb,im); +/* } +/* return (class,""); +/* "entry" => +/* ioutb.puts(sys->sprint("%d %d moveto\n",line.xorg+imag.offset, +/* line.yorg)); +/* ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n", +/* line.xorg+imag.offset,line.yorg,imag.width, +/* line.height)); +/* return (class,""); +/* * => +/* sys->print("Unhandled class [%s]\n",class); +/* return (class,"Error"); +/* +/* } +/* return ("",""); +/* } +/* +/* printline(ioutb: ref Iobuf,line : lineinfo,items : array of iteminfo) +/* { +/* xstart:=line.xorg; +/* wid:=xstart; +/* # items +/* if (len items == 0) return; +/* for(j:=0;j<len items;j++){ +/* msg:=""; +/* class:=""; +/* if (items[j].itype==IMAGE) +/* (class,msg)=printimage(ioutb,line,items[j]); +/* if (items[j].itype!=IMAGE || class=="button"|| class=="menubutton"){ +/* setfont(ioutb,items[j].font); +/* if (msg!=""){ +/* # position the text in the center of the label +/* # moveto curpoint +/* # (msg) stringwidth pop xstart sub 2 div +/* ioutb.puts(sys->sprint("%d %d moveto\n",xstart+items[j].offset, +/* line.yorg+line.height-line.ascent)); +/* ioutb.puts(sys->sprint("(%s) dup stringwidth pop 2 div", +/* msg)); +/* ioutb.puts(" 0 rmoveto show\n"); +/* } +/* else { +/* ioutb.puts(sys->sprint("%d %d moveto\n", +/* xstart+items[j].offset,line.yorg+line.height +/* -line.ascent)); +/* ioutb.puts(sys->sprint("(%s) show\n",items[j].buf)); +/* } +/* } +/* wid=xstart+items[j].offset+items[j].width; +/* } +/* if (boxes) +/* ioutb.puts(sys->sprint("%d %d %d %d rectstroke\n",line.xorg,line.yorg, +/* wid,line.height)); +/* } +/* +/* setfont(ioutb: ref Iobuf,font : int){ +/* ftype : int; +/* fname : string; +/* if ((curfonttype&font)!=curfonttype){ +/* for(f:=0;f<curfont;f++){ +/* (ftype,fname)=font_arr[f]; +/* if ((ftype&font)==ftype) +/* break; +/* } +/* if (f==curfont){ +/* fname=def_font; +/* ftype=def_font_type; +/* } +/* ioutb.puts(sys->sprint("%s setfont\n",fname)); +/* curfonttype=ftype; +/* } +/* } +/* +/* parseTkline(ioutb: ref Iobuf,input : string) : string +/* { +/* if (!started) return noinit; +/* thisline : lineinfo; +/* PS:=792-18-18; # page size in points +/* TM:=792-18; # top margin in points +/* LM:=18; # left margin 1/4 in. in +/* BM:=18; # bottom margin 1/4 in. in +/* x : int; +/* (x,input)=str->toint(input,10); +/* thisline.xorg=(x*PTPI)/PXPI; +/* (x,input)=str->toint(input,10); +/* thisline.yorg=(x*PTPI)/PXPI; +/* (x,input)=str->toint(input,10); +/* thisline.width=(x*PTPI)/PXPI; +/* (x,input)=str->toint(input,10); +/* thisline.height=(x*PTPI)/PXPI; +/* (x,input)=str->toint(input,10); +/* thisline.ascent=(x*PTPI)/PXPI; +/* (x,input)=str->toint(input,10); +/* # thisline.numitems=x; +/* if (thisline.width==0 || thisline.height==0) +/* return ""; +/* if (thisline.yorg+thisline.height-pagestart>PS){ +/* pagestart=thisline.yorg; +/* return "newpage"; +/* # must resend this line.... +/* } +/* thisline.yorg=TM-thisline.yorg-thisline.height+pagestart; +/* thisline.xorg+=LM; +/* (items, err) :=getline(totlines,input); +/* if(err != nil) +/* return err; +/* totitems+=len items; +/* totlines++; +/* printline(ioutb,thisline,items); +/* return ""; +/* } +/* +/* +/* getfonts(input: string) : string +/* { +/* if (!started) return "Error"; +/* tkfont,psfont : string; +/* j : int; +/* retval := ""; +/* if (input[0]=='%') +/* return ""; +/* # get a line of the form +/* # 5::/fonts/lucida/moo.16.font +/* # translate it to... +/* # 32 f32.16 +/* # where 32==1<<5 and f32.16 is a postscript function that loads the +/* # appropriate postscript font (from remap) +/* # and writes it to fonts.... +/* (bits,font):=str->toint(input,10); +/* if (bits!=-1) +/* bits=1<<bits; +/* else{ +/* bits=1; +/* def_font_type=bits; +/* curfonttype=def_font_type; +/* } +/* font=font[2:]; +/* for(i:=0;i<len remap;i++){ +/* (tkfont,psfont)=remap[i]; +/* if (tkfont==font) +/* break; +/* } +/* if (i==len remap) +/* psfont="Times-Roman"; +/* (font,nil)=str->splitr(font,"."); +/* (nil,font)=str->splitr(font[0:len font-1],"."); +/* (fsize,nil):=str->toint(font,10); +/* fsize=(PTPI*3*fsize)/(2*PXPI); +/* enc_font:="f"+string bits+"."+string fsize; +/* ps_func:="/"+enc_font+" /"+psfont+" findfont "+string fsize+ +/* " scalefont def\n"; +/* sy_font:="sy"+string fsize; +/* xtra_func:="/"+sy_font+" /Symbol findfont "+string fsize+ +/* " scalefont def\n"; +/* for(i=0;i<len font_arr;i++){ +/* (j,font)=font_arr[i]; +/* if (j==-1) break; +/* } +/* if (j==len font_arr) +/* return "Error"; +/* font_arr[i]=(bits,enc_font); +/* if (bits==1) +/* def_font=enc_font; +/* curfont++; +/* retval+= ps_func; +/* retval+= xtra_func; +/* return retval; +/* } +/* +/* deffont() : string +/* { +/* return def_font; +/* } +/* +/* getline(k : int, input : string) : (array of iteminfo, string) +/* { +/* lineval,args : string; +/* j, nb : int; +/* lw:=0; +/* wid:=0; +/* flags:=0; +/* item_arr := array[32] of {* => iteminfo(-1,-1,-1,-1,-1,-1,"")}; +/* curitem:=0; +/* while(input!=nil){ +/* (nil,input)=str->splitl(input,"["); +/* if (input==nil) +/* break; +/* com:=input[1]; +/* input=input[2:]; +/* case com { +/* 'A' => +/* nb=0; +/* # get the width of the item +/* (wid,input)=str->toint(input,10); +/* wid=(wid*PTPI)/PXPI; +/* if (input[0]!='{') +/* return (nil, sys->sprint( +/* "line %d item %d Bad Syntax : '{' expected", +/* k,curitem)); +/* # get the args. +/* (args,input)=str->splitl(input,"}"); +/* # get the flags. +/* # assume there is only one int flag.. +/* (flags,args)=str->toint(args[1:],16); +/* if (args!=nil && debug){ +/* sys->print("line %d item %d extra flags=%s\n", +/* k,curitem,args); +/* } +/* if (flags<1024) flags=1; +/* item_arr[curitem].font=flags; +/* item_arr[curitem].offset=lw; +/* item_arr[curitem].width=wid; +/* lw+=wid; +/* for(j=1;j<len input;j++){ +/* if ((input[j]==')')||(input[j]=='(')) +/* lineval[len lineval]='\\'; +/* if (input[j]=='[') +/* nb++; +/* if (input[j]==']') +/* if (nb==0) +/* break; +/* else +/* nb--; +/* lineval[len lineval]=input[j]; +/* } +/* if (j<len input) +/* input=input[j:]; +/* item_arr[curitem].buf=lineval; +/* item_arr[curitem].line=k; +/* item_arr[curitem].itype=ASCII; +/* curitem++; +/* lineval=""; +/* 'R' => +/* nb=0; +/* # get the width of the item +/* (wid,input)=str->toint(input,10); +/* wid=(wid*PTPI)/PXPI; +/* if (input[0]!='{') +/* return (nil, "Bad Syntax : '{' expected"); +/* # get the args. +/* (args,input)=str->splitl(input,"}"); +/* # get the flags. +/* # assume there is only one int flag.. +/* (flags,args)=str->toint(args[1:],16); +/* if (args!=nil && debug){ +/* sys->print("line %d item %d Bad Syntax args=%s", +/* k,curitem,args); +/* } +/* item_arr[curitem].font=flags; +/* item_arr[curitem].offset=lw; +/* item_arr[curitem].width=wid; +/* lw+=wid; +/* for(j=1;j<len input;j++){ +/* if (input[j]=='[') +/* nb++; +/* if (input[j]==']') +/* if (nb==0) +/* break; +/* else +/* nb--; +/* case input[j] { +/* 8226 => # bullet +/* lineval+="\\267 "; +/* 169 => # copyright +/* lineval+="\\251 "; +/* curitem++; +/* * => +/* lineval[len lineval]=input[j]; +/* } +/* } +/* if (j>len input) +/* input=input[j:]; +/* item_arr[curitem].buf=lineval; +/* item_arr[curitem].line=k; +/* item_arr[curitem].itype=RUNE; +/* curitem++; +/* lineval=""; +/* 'N' or 'C'=> +/* # next item +/* for(j=0;j<len input;j++) +/* if (input[j]==']') +/* break; +/* if (j>len input) +/* input=input[j:]; +/* 'T' => +/* (wid,input)=str->toint(input,10); +/* wid=(wid*PTPI)/PXPI; +/* item_arr[curitem].offset=lw; +/* item_arr[curitem].width=wid; +/* lw+=wid; +/* lineval[len lineval]='\t'; +/* # next item +/* for(j=0;j<len input;j++) +/* if (input[j]==']') +/* break; +/* if (j>len input) +/* input=input[j:]; +/* item_arr[curitem].buf=lineval; +/* item_arr[curitem].line=k; +/* item_arr[curitem].itype=ASCII; +/* curitem++; +/* lineval=""; +/* 'W' => +/* (wid,input)=str->toint(input,10); +/* wid=(wid*PTPI)/PXPI; +/* item_arr[curitem].offset=lw; +/* item_arr[curitem].width=wid; +/* item_arr[curitem].itype=IMAGE; +/* lw+=wid; +/* # next item +/* for(j=1;j<len input;j++){ +/* if (input[j]==']') +/* break; +/* lineval[len lineval]=input[j]; +/* } +/* item_arr[curitem].buf=lineval; +/* if (j>len input) +/* input=input[j:]; +/* curitem++; +/* lineval=""; +/* * => +/* # next item +/* for(j=0;j<len input;j++) +/* if (input[j]==']') +/* break; +/* if (j>len input) +/* input=input[j:]; +/* +/* } +/* } +/* return (item_arr[0:curitem], ""); +/* } +*/ + +void +cmap2ascii85(uchar *b, uchar *c) { + int i; + unsigned long i1; + +/* fprintf(stderr, "addr=0x%x %x %x %x %x\n", b, b[0], b[1], b[2], b[3]); */ + b--; /* one-index b */ + c--; /* one-index c */ + i1 = (b[1]<<24)+(b[2]<<16)+(b[3]<<8)+b[4]; + if(i1 == 0){ + c[1] = 'z'; + c[2] = '\0'; + return; + } + for(i=0; i<=4; i++){ + c[5-i] = '!' + (i1 % 85); + i1 /= 85; + } + c[6] = '\0'; +} + +static uchar *arr = nil; +ulong onesbits = ~0; +void +imagebits(Biobuf *ioutb, Memimage *im) +{ + int spb; + int bitoff; + int j, n, n4, i, bpl, nrest; + int lsf; + uchar c85[6], *data, *src, *dst; + Memimage *tmp; + Rectangle r; + + tmp = nil; + if (debug) + fprint(2, "imagebits, r=%d %d %d %d, depth=%d\n", + im->r.min.x, im->r.min.y, im->r.max.x, im->r.max.y, im->depth); + width = Dx(im->r); + height = Dy(im->r); + bps = im->depth; /* # bits per sample */ + bitoff = 0; /* # bit offset of beginning sample within first byte */ + if (bps < 8) { + spb = 8 / bps; + bitoff = (im->r.min.x % spb) * bps; + } + if (bitoff != 0) { +/* # Postscript image wants beginning of line at beginning of byte */ + r = im->r; + r.min.x -= bitoff/im->depth; + r.max.x -= bitoff/im->depth; + tmp = allocmemimage(r, im->chan); + if(tmp == nil){ + fprint(2, "p9bitpost: allocmemimage failed: %r\n"); + exits("alloc"); + } + memimagedraw(tmp, r, im, im->r.min, nil, ZP, S); + im = tmp; + } + lsf = 0; + /* compact data to remove word-boundary padding */ + bpl = bytesperline(im->r, im->depth); + n = bpl*Dy(im->r); + data = malloc(n); + if(data == nil){ + fprint(2, "p9bitpost: malloc failed: %r\n"); + exits("malloc"); + } + for(i=0; i<Dy(im->r); i++){ + /* memmove(data+bpl*i, byteaddr(im, Pt(im->r.min.x, im->r.min.y+i)), bpl); with inversion */ + dst = data+bpl*i; + src = byteaddr(im, Pt(im->r.min.x, im->r.min.y+i)); + for(j=0; j<bpl; j++) + *dst++ = 255 - *src++; + } + n4 = (n / 4) * 4; + for (i = 0; i < n4; i += 4){ + cmap2ascii85(data+i, c85); + lsf += strlen((char *)c85); + Bprint(ioutb, "%s", c85); + if (lsf > 74) { + Bprint(ioutb, "\n"); + lsf = 0; + } + } + nrest = n - n4; + if (nrest != 0) { + uchar foo[4]; + + for (i=0; i<nrest; i++) + foo[i] = data[n4+i]; + for (i=nrest; i<4; i++) + foo[i] = '\0'; + cmap2ascii85(foo, c85); + if (strcmp((char *)c85, "z") == 0 ) + strcpy((char *)c85, "!!!!!"); + Bprint(ioutb, "%.*s", nrest+1, c85); + } + Bprint(ioutb, "\n~>"); + Bprint(ioutb, "\n"); + freememimage(tmp); +} + +int +image2psfile(int fd, Memimage *im, int dpi) { + Rectangle r; + Rectangle bbox; + int e; + int xmargin = 36; + int ymargin = 36; + double paperaspectratio; + double imageaspectratio; + Biobuf ioutb; + Memimage *tmp; + + if(im->depth >= 8 && im->chan != CMAP8 && im->chan != GREY8){ + /* + * the postscript libraries can only handle [1248]-bit grey, 8-bit cmap, + * and 24-bit color, so convert. + */ + tmp = allocmemimage(im->r, strtochan("b8g8r8")); + if(tmp == nil) + return 1; + memimagedraw(tmp, tmp->r, im, im->r.min, nil, ZP, S); + freememimage(im); + im = tmp; + } + + Binit(&ioutb, fd, OWRITE); + r = im->r; + width = Dx(r); + height = Dy(r); + imageaspectratio = (double) width / (double) height; + if (landscape) { + paperaspectratio = ((double)paperlength - (ymargin * 2)) / ((double)paperwidth - (xmargin * 2)); + if (dpi > 0) { + iwidth = width * 72 / dpi; + iheight = height * 72 / dpi; + } else if (imageaspectratio > paperaspectratio) { + iwidth = paperlength - (ymargin * 2); + iheight = iwidth / imageaspectratio; + } else { + iheight = paperwidth - (xmargin * 2); + iwidth = iheight * imageaspectratio; + } + xstart = paperwidth - xmargin - (iheight * ymagnification); + ystart = paperlength - ymargin; + rotation = -90; + } else { + paperaspectratio = ((double)paperwidth - (xmargin * 2)) / ((double)paperlength - (ymargin * 2)); + if (dpi > 0) { + iwidth = width * 72 / dpi; + iheight = height * 72 / dpi; + } else if (imageaspectratio > paperaspectratio) { + iwidth = paperwidth - (xmargin * 2); + iheight = iwidth / imageaspectratio; + } else { + iheight = paperlength - (ymargin * 2); + iwidth = iheight * imageaspectratio; + } + xstart = xmargin; + ystart = paperlength - ymargin - (iheight * ymagnification); + rotation = 0; + } + bbox = Rect(xstart,ystart,xstart+iwidth,ystart+iheight); + e = preamble(&ioutb, bbox); + if(e != 0) + return e; + Bprint(&ioutb, "%%%%Page: 1\n%%%%BeginPageSetup\n"); + Bprint(&ioutb, "/pgsave save def\n"); + Bprint(&ioutb, "%%%%EndPageSetup\n"); + bps = im->depth; + Bprint(&ioutb, "%d 0 %d %d %d %d %d %d %s doimage\n", iheight, iwidth, ystart, xstart, height, width, bps, im->flags&Fgrey ? "true" : "false"); + imagebits(&ioutb, im); + Bprint(&ioutb, "pgsave restore\nshowpage\n"); + e = trailer(&ioutb, 1); + if(e != 0) + return e; + Bterm(&ioutb); + return 0; +} + +/* set local variables by string and pointer to its value + * the variables are: + * int magnification + * int landscape + * char *Patch + */ +void +psopt(char *s, void *val) +{ + if(s == nil) + return; + if(strcmp("xmagnification", s) == 0) + xmagnification = *((double *)val); + if(strcmp("ymagnification", s) == 0) + ymagnification = *((double *)val); + if(strcmp("landscape", s) == 0) + landscape = *((int *)val); + if(strcmp("Patch", s) == 0) + Patch = *((char **)val); +} diff --git a/sys/src/cmd/postscript/p9bitpost/pslib.h b/sys/src/cmd/postscript/p9bitpost/pslib.h new file mode 100755 index 000000000..85a7db0ae --- /dev/null +++ b/sys/src/cmd/postscript/p9bitpost/pslib.h @@ -0,0 +1,6 @@ +char *psinit(int, int); /* second arg is debug flag; returns "" on success */ +int image2psfile(int, Memimage*, int); +void psopt(char *, void *); + +int paperlength; +int paperwidth; diff --git a/sys/src/cmd/postscript/picpack/mkfile b/sys/src/cmd/postscript/picpack/mkfile new file mode 100755 index 000000000..4c713bb60 --- /dev/null +++ b/sys/src/cmd/postscript/picpack/mkfile @@ -0,0 +1,57 @@ +BUILTINS= +</$objtype/mkfile +MAKE=mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/sys/lib/postscript/bin + +COMMONDIR=../common + +CC=pcc +LD=pcc + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B +LDFLAGS= + +all :V: $O.out + +install :V: $POSTBIN/$objtype/picpack $MAN1DIR/picpack.1 + +installall :V: + for(objtype in $CPUS) { \ + $MAKE 'MAKE=$MAKE' \ + 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \ + 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \ + 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \ + 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \ + 'ROUNDPAGE=$ROUNDPAGE' \ + 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \ + install \ + } + +clean :V: + rm -f *.$O + +clobber :V: clean + rm -f $O.out + +$POSTBIN/$objtype/picpack : $O.out + cp $prereq $target + +$MAN1DIR/picpack.1 : picpack.1 + cp $prereq $target + +$O.out : picpack.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/tempnam.$O $COMMONDIR/getopt.$O + $LD $LDFLAGS $prereq + +%.$O: %.c + $CC $CFLAGS $stem.c + +picpack.$O : picpack.c $COMMONDIR/ext.h $COMMONDIR/gen.h $COMMONDIR/path.h + +common :V: + cd $COMMONDIR; $MAKE diff --git a/sys/src/cmd/postscript/picpack/picpack.1 b/sys/src/cmd/postscript/picpack/picpack.1 new file mode 100755 index 000000000..ee5a428fa --- /dev/null +++ b/sys/src/cmd/postscript/picpack/picpack.1 @@ -0,0 +1,123 @@ +.TH PICPACK 1 +.SH NAME +.B picpack +\- PostScript picture packing preprocessor +.SH SYNOPSIS +\*(mBpicpack\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B picpack +copies +.I files +to stdout, expanding picture inclusion requests +(marked by the +.MW .BP +or +.MW .PI +macros) into an in-line +format that can be passed through +.B troff +and handled by +.BR dpost . +If no +.I files +are specified +or if +.OP \- +is one of the input +.I files +standard input is read. +The following +.I options +are understood: +.TP 0.75i +.OP \-k list +.I list +is a comma- or space-separated string of words used to locate +picture inclusion requests. +The start of every line in the input +.I files +is compared with each word in +.I list . +If there is a match, the second string on the line is +taken as the pathname of a picture file that is added +to the output file. +The default +.I list +is +.RM `` ".BP .PI ''. +.TP +.OP \-q +Suppress ``missing picture file'' error messages. +.PP +.B picpack +is a trivial preprocessor that, in a sense, duplicates some of the +picture inclusion capabilities already available in +.BR dpost . +.B picpack +should not be used if your formatting command line includes +a call to +.BR dpost . +Its only purpose is to combine picture files with text in a single +file that can be passed through +.B troff +and unpacked, at some later time, by +.BR dpost . +The original picture inclusion mechanism, with files are pulled in by +.BR dpost , +is the preferred approach. +.SH EXAMPLES +A typical application might be in a distributed printing environment +where everything up to +.B troff +is run by the user and everything after +.B troff +is handled by a spooling daemon (perhaps +.BR lp ). +In that case the command line would be, +.EX +pic \f2file\fP | tbl | eqn | picpack | troff -mm -Tpost | lp +.EE +A poor example, although one that should still work, would be, +.EX +pic \f2file\fP | tbl | eqn | picpack | troff -mm -Tpost | dpost >\f2file\fP.ps +.EE +In this case picture inclusion requests could (and should) be handled by +.BR dpost . +Running +.B picpack +is not needed or even recommended. +It should be dropped from any pipeline that includes a call to +.BR dpost . +.SH DIAGNOSTICS +A 0 exit status is returned if +.I files +were successfully processed. +.SH WARNINGS +.PP +Combining pictures and text using the capabilities available in +.B dpost +is the recommended approach and is always guaranteed to be more +efficient than +.BR picpack . +Running +.B picpack +and +.B dpost +in the same pipeline makes little sense. +.PP +Using +.B picpack +will likely result in files that can no longer be reliably passed +through other important +.B troff +postprocessors like +.BR proof . +At present +.B picpack +is only guaranteed to work with +.BR dpost . +.SH SEE ALSO +.BR dpost (1), +.BR troff (1) diff --git a/sys/src/cmd/postscript/picpack/picpack.c b/sys/src/cmd/postscript/picpack/picpack.c new file mode 100755 index 000000000..7d96bc02b --- /dev/null +++ b/sys/src/cmd/postscript/picpack/picpack.c @@ -0,0 +1,441 @@ +/* + * + * picpack - picture packing pre-processor + * + * A trivial troff pre-processor that copies files to stdout, expanding picture + * requests into an in-line format that's passed transparently through troff and + * handled by dpost. The program is an attempt to address requirements, expressed + * by several organizations, of being able to store a document as a single file + * (usually troff input) that can then be sent through dpost and ultimately to + * a PostScript printer. + * + * The program looks for strings listed in the keys[] array at the start of each + * line. When a picture request (as listed in keys[]) is found the second string + * on the line is taken to be a picture file pathname that's added (in transparent + * mode) to the output file. In addition each in-line picture file is preceeded by + * device control command (again passed through in transparent mode) that looks + * like, + * + * x X InlinePicture filename bytes + * + * where bytes is the size of the picture file (which begins on the next line) + * and filename is the pathname of the picture file. dpost uses both arguments to + * manage in-line pictures (in a big temp file). To handle pictures in diversions + * picpack reads each input file twice. The first pass looks for picture inclusion + * requests and copies each picture file transparently to the output file, while + * second pass just copies the input file to the output file. Things could still + * break, but the two pass method should handle most jobs. + * + * The recognized in-line picture requests are saved in keys[] and by default only + * expand .BP and .PI macro calls. The -k option changes the recognized strings, + * and may be needed if you've built your own picture inclusion macros on top of + * .BP or .PI or decided to list each picture file at the start of your input file + * using a dummy macro. For example you could require every in-line picture be + * named by a dummy macro (say .iP), then the command line, + * + * picpack -k.iP file > file.pack + * + * hits on lines that begin with .iP (rather than .BP or .PI), and the only files + * pulled in would be ones named as the second argument to the new .iP macro. The + * -k option accepts a space or comma separated list of up to 10 different key + * strings. picpack imposes no contraints on key strings, other than not allowing + * spaces or commas. A key string can begin with \" and in that case it would be + * troff comment. + * + * Although the program will help some users, there are obvious disadvantages. + * Perhaps the most important is that troff output files (with in-line pictures + * included) don't fit the device independent language accepted by important post + * processors like proof, and that means you won't be able to reliably preview a + * packed file on your 5620 or whatever. Another potential problem is that picture + * files can be large. Packing everything together in a single file at an early + * stage has a better chance of exceeding your system's ulimit. + * + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +#include "gen.h" /* general purpose definitions */ +#include "ext.h" /* external variable definitions */ +#include "path.h" /* just for TEMPDIR definition */ + +char *keys[11] = {".BP", ".PI", NULL}; +int quiet = FALSE; + +FILE *fp_in = stdin; /* input */ +FILE *fp_out = stdout; /* and output files */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A picture packing pre-processor that copies input files to stdout, expanding + * picture requests (as listed in keys[]) to an in-line format that can be passed + * through troff (using transparent mode) and handled later by dpost. + * + */ + + argc = agc; /* global so everyone can use them */ + argv = agv; + + prog_name = argv[0]; /* just for error messages */ + + options(); /* command line options */ + arguments(); /* translate all the input files */ + done(); /* clean things up */ + + exit(x_stat); /* everything probably went OK */ + +} /* End of main */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* name returned by getopt() */ + + extern char *optarg; /* option argument set by getopt() */ + extern int optind; + +/* + * + * Handles the command line options. + * + */ + + while ( (ch = getopt(argc, argv, "k:qDI")) != EOF ) { + switch ( ch ) { + case 'k': /* new expansion key strings */ + newkeys(optarg); + break; + + case 'q': /* disables "missing picture" messages */ + quiet = TRUE; + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't know the option */ + error(FATAL, ""); + break; + + default: + error(FATAL, "missing case for option %c", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-options args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +newkeys(list) + + char *list; /* comma or space separated key strings */ + +{ + + char *p; /* next key string from *list */ + int i; /* goes in keys[i] */ + int n; /* last key string slot in keys[] */ + +/* + * + * Separates *list into space or comma separated strings and adds each to the + * keys[] array. The strings in keys[] are used to locate the picture inclusion + * requests that are translated to the in-line format. The keys array must end + * with a NULL pointer and by default only expands .BP and .PI macro calls. + * + */ + + n = (sizeof(keys) / sizeof(char *)) - 1; + + for ( i = 0, p = strtok(list, " ,"); p != NULL; i++, p = strtok(NULL, " ,") ) + if ( i >= n ) + error(FATAL, "too many key strings"); + else keys[i] = p; + + keys[i] = NULL; + +} /* End of newkeys */ + +/*****************************************************************************/ + +arguments() + +{ + + FILE *copystdin(); + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we process stdin, after copying it to a temporary file. + * + */ + + if ( argc < 1 ) { + fp_in = copystdin(); + picpack(); + } else + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = copystdin(); + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + picpack(); + fclose(fp_in); + argc--; + argv++; + } /* End while */ + +} /* End of arguments */ + +/*****************************************************************************/ + +FILE *copystdin() + +{ + + char *tfile; /* temporary file name */ + int fd_out; /* and its file descriptor */ + FILE *fp; /* return value - the new input file */ + +/* + * + * Copies stdin to a temp file, unlinks the file, and returns the file pointer + * for the new temporary file to the caller. Needed because we read each input + * file twice in an attempt to handle pictures in diversions. + * + */ + + if ( (tfile = tempnam(TEMPDIR, "post")) == NULL ) + error(FATAL, "can't generate temp file name"); + + if ( (fd_out = creat(tfile, 0660)) == -1 ) + error(FATAL, "can't create %s", tfile); + + copyfile(fileno(stdin), fd_out); + close(fd_out); + + if ( (fp = fopen(tfile, "r")) == NULL ) + error(FATAL, "can't open %s", tfile); + + unlink(tfile); + return(fp); + +} /* End of copystdin */ + +/*****************************************************************************/ + +copyfile(fd_in, fd_out) + + int fd_in; /* input */ + int fd_out; /* and output files */ + +{ + + char buf[512]; /* internal buffer for reads and writes */ + int count; /* number of bytes put in buf[] */ + +/* + * + * Copies file fd_in to fd_out. Handles the second pass for each input file and + * also used to copy stdin to a temporary file. + * + */ + + while ( (count = read(fd_in, buf, sizeof(buf))) > 0 ) + if ( write(fd_out, buf, count) != count ) + error(FATAL, "write error"); + +} /* End of copyfile */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files - unlink the temporary file that was used + * to record the in-line picture file pathnames. + * + */ + + if ( temp_file != NULL ) + unlink(temp_file); + +} /* End of done */ + +/*****************************************************************************/ + +picpack() + +{ + + char line[512]; /* next input line */ + char name[100]; /* picture file names - from BP or PI */ + int i; /* for looking through keys[] */ + +/* + * + * Handles the two passes over the next input file. First pass compares the start + * of each line in *fp_in with the key strings saved in the keys[] array. If a + * match is found inline() is called to copy the picture file (ie. the file named + * as the second string in line[]) to stdout, provided the file hasn't previously + * been copied. The second pass goes back to the start of fp_in and copies it all + * to the output file. + * + */ + + while ( fgets(line, sizeof(line), fp_in) != NULL ) { + for ( i = 0; keys[i] != NULL; i++ ) + if ( strncmp(line, keys[i], strlen(keys[i])) == 0 ) { + if ( sscanf(line, "%*s %s", name) == 1 ) { + strtok(name, "("); + if ( gotpicfile(name) == FALSE ) + inline(name); + } /* End if */ + } /* End if */ + } /* End while */ + + fflush(fp_out); /* second pass - copy fp_in to fp_out */ + fseek(fp_in, 0L, 0); + copyfile(fileno(fp_in), fileno(fp_out)); + +} /* End of picpack */ + +/*****************************************************************************/ + +inline(name) + + char *name; /* name of the in-line picture file */ + +{ + + long size; /* size in bytes - from fstat */ + FILE *fp; /* for reading *name */ + int ch; /* next character from picture file */ + int lastch = '\n'; /* so we know when to put out \! */ + + struct stat sbuf; /* for the picture file size */ + +/* + * + * Copies the picture file *name to the output file in an in-line format that can + * be passed through troff and recovered later by dpost. Transparent mode is used + * so each line starts with \! and all \ characters must be escaped. The in-line + * picture sequence begins with an "x X InlinePicture" device control command that + * names the picture file and gives its size (in bytes). + * + */ + + if ( (fp = fopen(name, "r")) != NULL ) { + fstat(fileno(fp), &sbuf); + if ( (size = sbuf.st_size) > 0 ) { + fprintf(fp_out, "\\!x X InlinePicture %s %ld\n", name, size); + while ( (ch = getc(fp)) != EOF ) { + if ( lastch == '\n' ) + fprintf(fp_out, "\\!"); + if ( ch == '\\' ) + putc('\\', fp_out); + putc(lastch = ch, fp_out); + } /* End while */ + if ( lastch != '\n' ) + putc('\n', fp_out); + } /* End if */ + fclose(fp); + addpicfile(name); + } else if ( quiet == FALSE ) + error(NON_FATAL, "can't read picture file %s", name); + +} /* End of inline */ + +/*****************************************************************************/ + +gotpicfile(name) + + char *name; + +{ + + char buf[100]; + FILE *fp_pic; + +/* + * + * Checks the list of previously added picture files in *temp_file and returns + * FALSE if it's a new file and TRUE otherwise. Probably should open the temp + * file once for update and leave it open, rather than opening and closing it + * every time. + * + */ + + if ( temp_file != NULL ) + if ( (fp_pic = fopen(temp_file, "r")) != NULL ) { + while ( fscanf(fp_pic, "%s", buf) != EOF ) + if ( strcmp(buf, name) == 0 ) { + fclose(fp_pic); + return(TRUE); + } /* End if */ + fclose(fp_pic); + } /* End if */ + + return(FALSE); + +} /* End of gotpicfile */ + +/*****************************************************************************/ + +addpicfile(name) + + char *name; + +{ + + FILE *fp_pic; + +/* + * + * Adds string *name to the list of in-line picture files that's maintained in + * *temp_file. Should undoubtedly open the file once for update and use fseek() + * to move around in the file! + * + */ + + if ( temp_file == NULL ) + if ( (temp_file = tempnam(TEMPDIR, "picpac")) == NULL ) + return; + + if ( (fp_pic = fopen(temp_file, "a")) != NULL ) { + fprintf(fp_pic, "%s\n", name); + fclose(fp_pic); + } /* End if */ + +} /* End of addpicfile */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/picpack/picpack.mk b/sys/src/cmd/postscript/picpack/picpack.mk new file mode 100755 index 000000000..e79febae7 --- /dev/null +++ b/sys/src/cmd/postscript/picpack/picpack.mk @@ -0,0 +1,75 @@ +MAKE=/bin/make +MAKEFILE=picpack.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +HFILES=$(COMMONDIR)/ext.h\ + $(COMMONDIR)/gen.h\ + $(COMMONDIR)/path.h + +OFILES=picpack.o\ + $(COMMONDIR)/glob.o\ + $(COMMONDIR)/misc.o\ + $(COMMONDIR)/tempnam.o + +all : picpack + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + cp picpack $(POSTBIN)/picpack + @chmod 755 $(POSTBIN)/picpack + @chgrp $(GROUP) $(POSTBIN)/picpack + @chown $(OWNER) $(POSTBIN)/picpack + cp picpack.1 $(MAN1DIR)/picpack.1 + @chmod 644 $(MAN1DIR)/picpack.1 + @chgrp $(GROUP) $(MAN1DIR)/picpack.1 + @chown $(OWNER) $(MAN1DIR)/picpack.1 + +clean : + rm -f *.o + +clobber : clean + rm -f picpack + +picpack : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o picpack $(OFILES) + +picpack.o : $(HFILES) + +$(COMMONDIR)/glob.o\ +$(COMMONDIR)/misc.o\ +$(COMMONDIR)/tempnam.o : + @cd $(COMMONDIR); $(MAKE) -f common.mk SYSTEM=$(SYSTEM) `basename $@` + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE) + diff --git a/sys/src/cmd/postscript/postbgi/README b/sys/src/cmd/postscript/postbgi/README new file mode 100755 index 000000000..de815330e --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/README @@ -0,0 +1,21 @@ + +BGI (Basic Graphical Instructions) to PostScript translator. Probably +not useful outside the Computer Centers. Added code to tie lines to +device space coordinates. Helps eliminate variations in line widths +noticeable when users selected a non-zero linewidth with the -w option. + +Much that was omitted from early versions of the program has been +implemented. What's in place will handle most STARE (black and white) +and PRISM (color) BGI jobs. PRISM jobs often fill regions with color, +and need require device specific tuning to get things just right. An +easy solution is add "-P/prism true def" option to the postbgi command +line when you translate PRISM jobs. + +A typical command line for STARE jobs would be, + + postbgi file >file.ps + +while for PRISM jobs use, + + postbgi -P"/prism true def" file >file.ps + diff --git a/sys/src/cmd/postscript/postbgi/mkfile b/sys/src/cmd/postscript/postbgi/mkfile new file mode 100755 index 000000000..5722ae6ca --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/mkfile @@ -0,0 +1,61 @@ +BUILTINS= +</$objtype/mkfile +MAKE=mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/rc/bin/postscript/ +POSTLIB=$ROOT/sys/lib/postscript/prologues + +COMMONDIR=../common + +CC=pcc +LD=pcc + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B +LDFLAGS= + +all :V: $O.out + +install :V: $POSTBIN/$objtype/postbgi $POSTLIB/postbgi.ps $MAN1DIR/postbgi.1 + +installall :V: + for(objtype in $CPUS) { \ + $MAKE 'MAKE=$MAKE' \ + 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \ + 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \ + 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \ + 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \ + 'ROUNDPAGE=$ROUNDPAGE' \ + 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \ + install \ + } + +clean :V: + rm -f *.$O + +clobber :V: clean + rm -f $O.out + +$POSTBIN/$objtype/postbgi : $O.out + cp $prereq $target + +$POSTLIB/postbgi.ps : postbgi.ps + cp $prereq $target + +$MAN1DIR/postbgi.1 : postbgi.1 + cp $prereq $target + +$O.out : postbgi.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/request.$O $COMMONDIR/getopt.$O + $LD $LDFLAGS $prereq + +%.$O: %.c + $CC $CFLAGS $stem.c + +postbgi.$O : $COMMONDIR/comments.h $COMMONDIR/gen.h $COMMONDIR/path.h $COMMONDIR/ext.h postbgi.h + +common :V: + cd $COMMONDIR; $MAKE diff --git a/sys/src/cmd/postscript/postbgi/postbgi.1 b/sys/src/cmd/postscript/postbgi/postbgi.1 new file mode 100755 index 000000000..971e14a0c --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.1 @@ -0,0 +1,243 @@ +.ds dQ /usr/lib/postscript +.TH POSTBGI 1 "DWB 3.2" +.SH NAME +.B postbgi +\- PostScript translator for +.SM BGI +(Basic Graphical Instructions) files +.SH SYNOPSIS +\*(mBpostbgi\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B postbgi +translates +.SM BGI +(Basic Graphical Instructions) +.I files +into PostScript and writes the results on the +standard output. +If no +.I files +are specified, or if +.OP \- +is one of the input +.IR files , +the standard input is read. +The following +.I options +are understood: +.TP 0.75i +.OP \-c num +Print +.I num +copies of each page. +By default only one copy is printed. +.TP +.OP \-f name +Print text using font +.IR name . +Any PostScript font can be used, +although the best results will only be +obtained with constant width fonts. +The default font is Courier. +.TP +.OP \-m num +Magnify each logical page by the factor +.IR num . +Pages are scaled uniformly about the origin, +which by default is located at the center of +each page. +The default magnification is 1.0. +.TP +.OP \-n num +Print +.I num +logical pages on each piece of paper, +where +.I num +can be any positive integer. +By default +.I num +is set to 1. +.TP +.OP \-o list +Print pages whose numbers are given in the comma-separated +.IR list . +The list contains single numbers +.I N +and ranges +.IR N1\-\|N2 . +A missing +.I N1 +means the lowest numbered page, a missing +.I N2 +means the highest. +.TP +.OP \-p mode +Print +.I files +in either \*(mBportrait\fP or \*(mBlandscape\fP +.IR mode . +Only the first character of +.I mode +is significant. +The default +.I mode +is \*(mBportrait\fP. +.TP +.OP \-w num +Set the line width used for graphics to +.I num +points, where a point is approximately 1/72 +of an inch. +By default +.I num +is set to 0 points, which forces lines to be +one pixel wide. +.TP +.OP \-x num +Translate the origin +.I num +inches along the positive x axis. +The default +coordinate system has the origin fixed at the +center of the page, with positive +x to the right and positive y up the page. +Positive +.I num +moves everything right. +The default offset is 0 inches. +.TP +.OP \-y num +Translate the origin +.I num +inches along the positive y axis. +Positive +.I num +moves everything up the page. +The default offset is 0 inches. +.TP +.OP \-E name +Set the character encoding for text fonts to +.IR name . +Requesting +.I name +means include file +.MI \*(dQ name .enc \f1. +A nonexistent encoding file is silently ignored. +The default selects file +.MR \*(dQ/Default.enc . +.TP +.OP \-L file +Use +.I file +as the PostScript prologue. +.br +The default is +.MR \*(dQ/postbgi.ps . +.PP +Three options allow insertion of arbitrary PostScript +at controlled points in the translation process: +.TP 0.75i +.OP \-C file +Copy +.I file +to the output file; +.I file +must contain legitimate PostScript. +.TP +.OP \-P string +Include +.I string +in the output file; +.I string +must be legitimate PostScript. +.TP +.OP \-R action +Requests special +.I action +(e.g., +.MR manualfeed ) +on a per page or global basis. +The +.I action +string can be given as +.IR request , +.IM request : page\f1\|, +or +.IM request : page : file\f1\|. +If +.I page +is omitted or given as 0, the request +applies to all pages. +If +.I file +is omitted, the request +lookup is done in +.MR \*(dQ/ps.requests . +.PP +.B postbgi +can handle +.SM STARE +(black and white) and +.SM PRISM +(color) +.SM BGI +jobs. +By default plots are rigidly scaled to fill the page, which produces +the good results for most +.SM STARE +jobs. +.SM PRISM +jobs typically fill regions with colors, and often require device +specific tuning to produce acceptable results. +Adding the +.MW \-P"/prism\ true\ def" +option is strongly recommended when +.B postbgi +is translating +.SM PRISM +jobs. +.br +.ne 7v +.SH EXAMPLES +For most +.SM STARE +jobs, +.EX +postbgi \f2file +.EE +gives good results, while +.EX +postbgi \-P"/prism true def" \f2file +.EE +is recommended when translating +.SM PRISM +jobs. +.SH DIAGNOSTICS +A 0 exit status is returned if +.I files +were successfully processed. +.SH BUGS +The default line width is too small for write-white +print engines, like the one used by the PS-2400. +Several +.SM BGI +opcodes have not been implemented. +.SH FILES +.MW \*(dQ/postbgi.ps +.br +.MW \*(dQ/forms.ps +.br +.MW \*(dQ/ps.requests +.SH SEE ALSO +.BR dpost (1), +.BR postdaisy (1), +.BR postdmd (1), +.BR postio (1), +.BR postmd (1), +.BR postprint (1), +.BR postreverse (1), +.BR posttek (1), +.BR psencoding (1) diff --git a/sys/src/cmd/postscript/postbgi/postbgi.c b/sys/src/cmd/postscript/postbgi/postbgi.c new file mode 100755 index 000000000..c6047d75b --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.c @@ -0,0 +1,1523 @@ +/* + * + * postbgi - BGI (Basic Graphical Instructions) to PostScript translator. + * + * A simple program that translates BGI files into PostScript. Probably only + * useful in Computer Centers that support STARE or PRISM plotters. Most of the + * code was borrowed from the corresponding program that was written for printers + * that understand Impress. + * + * Extending the original program to handle PRISM jobs was not trivial. Graphics + * packages that support PRISM occasionally use BGI commands that I ignored in the + * STARE implementation. Subroutines, color requests, patterns (for filling), and + * filled trapeziods were the most important omissions. All are now implemented, + * and at present only repeats, filled slices, and raster rectangles are missing. + * + * Pattern filling results were not always predictable or even good, unless the + * halftone screen definitions were changed and scaling was adjusted so one pixel + * in user space mapped into an integral number of device space pixels. Doing that + * makes the resulting PostScript output device dependent, but was often necessary. + * I've added two booleans to the PostScript prologue (fixscreen and scaletodevice) + * that control what's done. By default both are false (check postbgi.ps) but can + * be set to true on the command line using the -P option or by hand by changing + * the definitions in the prologue. A command line that would set fixscreen and + * scaletodevice true would look like, + * + * postbgi -P"/fixscreen true" -P"/scaletodevice true" file >file.ps + * + * Several other approaches are available if you want to have your spooler handle + * STARE and PRISM jobs differently. A boolean called prism is defined in the + * prologue (postbgi.ps) and if it's set to true PostScript procedure setup will + * set fixscreen and scaletodevice to true before anything important is done. That + * means the following command line, + * + * postbgi -P"/prism true" file >file.ps + * + * accomplishes the same things as the last example. Two different prologue files, + * one for STARE jobs and the other for PRISM, could be used and the spooler could + * point postbgi to the appropriate one using the -L option. In that case the only + * important difference in the two prologues would be the definition of prism. The + * prologue used for PRISM jobs would have prism set to true, while the STARE + * prologue would have it set to false. + * + * Also included is code that ties lines to device space coordinates. What you get + * is a consistent line thickness, but placement of lines won't be exact. It's a + * trade-off that should be right for most jobs. Everything is implemented in the + * prologue (postbgi.ps) and nothing will be done if the linewidth is zero or if + * the boolean fixlinewidth (again in postbgi.ps) is false. Once again the -P + * option can be used to set fixlinewidth to whatever you choose. + * + * BGI supports color mixing but PostScript doesn't. BGI files that expect to mix + * colors won't print properly. PostScript's fill operator overlays whatever has + * already been put down. Implementing color mixing would have been a terribly + * difficult job - not worth the effort! + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how the program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects + * to find the current page number on the stack. + * + * v + * + * dx1 dy1 ... dxn dyn x y v - + * + * Draws the vector described by the numbers on the stack. The top two + * numbers are the coordinates of the starting point. The rest of the + * numbers are relative displacements from the preceeding point. + * + * pp + * + * x1 y1 ... xn yn string pp - + * + * Prints string, which is always a single character, at the points + * represented by the rest of the numbers on the stack. + * + * R + * + * n deltax deltay x y R - + * + * Creates a rectangular path with its lower left corner at (x, y) and + * sides of length deltax and deltay. The resulting path is stroked if + * n is 0 and filled otherwise. + * + * T + * + * dx3 dy3 dx2 dy2 dx1 dy1 x y T - + * + * Fills a trapezoid starting at (x, y) and having relative displacements + * given by the (dx, dy) pairs. + * + * t + * + * angle x y string t - + * + * Prints string starting at (x, y) using an orientation of angle degrees. + * The PostScript procedure can handle any angle, but BGI files will only + * request 0 or 90 degrees. Text printed at any other orientation will be + * vector generated. + * + * p + * + * x y p - + * + * Called to mark the point (x, y). It fills a small circle, that right + * now has a constant radius. This stuff could probably be much more + * efficient? + * + * l + * + * array l - + * + * Sets the line drawing mode according to the description given in + * array. The arrays that describe the different line styles are declared + * in STYLES (file posttek.h), although it would be better to have them + * defined in the prologue. + * + * c + * + * red green blue c - + * + * Sets the current PostScript RGB color using setrgbcolor. Also used for + * selecting appropriate patterns as colors. + * + * f + * + * bgisize f - + * + * Changes the size of the font that's used to print text. bgisize is a + * grid separation in a 5 by 7 array in which characters are assumed to + * be built. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * The default line width is zero, which forces lines to be one pixel wide. That + * works well for 'write to black' engines but won't be right for 'write to white' + * engines. The line width can be changed using the -w option, or you can change + * the initialization of linewidth in the prologue. Code in the prologue supports + * the generation of uniform width lines when linewidth is non-zero and boolean + * fixlinewidth is true. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#include <signal.h> +#include <math.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ +#include "postbgi.h" /* a few definitions just used here */ + +char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI"; + +char *prologue = POSTBGI; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +char *styles[] = STYLES; /* descriptions of line styles */ + +int hpos = 0; /* current horizontal */ +int vpos = 0; /* and vertical position */ + +int bgisize = BGISIZE; /* just the character grid spacing */ +int linespace; /* distance between lines of text */ + +int bgimode; /* character or graph mode */ + +int in_subr = FALSE; /* currently defining a subroutine */ +int in_global = FALSE; /* to save space with subroutine defs */ +int subr_id = 0; /* defining this subroutine */ +int shpos = 0; /* starting horizontal */ +int svpos = 0; /* and vertical positions - subroutines */ +Disp displacement[64]; /* dx and dy after a subroutine call */ + +Fontmap fontmap[] = FONTMAP; /* for translating font names */ +char *fontname = "Courier"; /* use this PostScript font */ + +int page = 0; /* page we're working on */ +int printed = 0; /* printed this many pages */ + +FILE *fp_in = stdin; /* read from this file */ +FILE *fp_out = NULL; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A program that converts BGI (Basic Graphical Instructions) files generated by + * packages like GRAFPAC and DISSPLA into PostScript. It does an adequate job but + * is far from perfect. A few things still haven't been implemented (eg. repeats + * and raster rectangles), but what's here should be good enough for most of our + * STARE and PRISM jobs. Color mixing (in PRISM jobs) won't work on PostScript + * printers, and there's no chance I'll implement it! + * + */ + + argc = agc; /* global so everyone can use them */ + argv = agv; + + prog_name = argv[0]; /* just for error messages */ + + init_signals(); /* set up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* everything probably went OK */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Make sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* option name - from getopt() */ + +/* + * + * Reads and processes the command line options. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s def\n", optarg); + break; + + case 'f': /* new font */ + fontname = get_font(optarg); + fprintf(stdout, "/font /%s def\n", fontname); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'w': /* line width */ + fprintf(stdout, "/linewidth %s def\n", optarg); + break; + + case 'x': /* shift horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* Postscript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't know the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +char *get_font(name) + + char *name; /* name the user asked for */ + +{ + + int i; /* for looking through fontmap[] */ + +/* + * + * Called from options() to map a user's font name into a legal PostScript name. + * If the lookup fails *name is returned to the caller. That should let you choose + * any PostScript font. + * + */ + + for ( i = 0; fontmap[i].name != NULL; i++ ) + if ( strcmp(name, fontmap[i].name) == 0 ) + return(fontmap[i].val); + + return(name); + +} /* End of get_font */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line options are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + if ( argc < 1 ) + conv(); + else + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + conv(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with the last input file, so mark the end of the pages, make sure the + * last page is printed, and restore the initial environment. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct, provided it's not NULL. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +conv() + +{ + + int ch; /* next input character */ + +/* + * + * Controls the conversion of BGI files into PostScript. Not everything has been + * implemented, but what's been done should be good enough for our purposes. + * + */ + + redirect(-1); /* get ready for the first page */ + bgimode = 0; + formfeed(); + + while ( (ch = get_char()) != EOF ) { + switch ( ch ) { + case BRCHAR: /* rotated character mode */ + bgimode = ch; + text(90); + break; + + case BCHAR: /* graphical character mode */ + bgimode = ch; + text(0); + break; + + case BGRAPH: /* graphical master mode */ + bgimode = ch; + break; + + case BSUB: /* subroutine definition */ + subr_def(); + break; + + case BRET: /* end of subroutine */ + subr_end(); + break; + + case BCALL: /* subroutine call */ + subr_call(); + break; + + case BEND: /* end display - page */ + formfeed(); + break; + + case BERASE: /* erase - shouldn't be used */ + error(FATAL, "BGI erase opcode obsolete"); + break; + + case BREP: /* repeat */ + error(FATAL, "Repeat not implemented"); + repeat(); + break; + + case BSETX: /* new x coordinate */ + hgoto(get_int(0)); + break; + + case BSETY: /* new y coordinate */ + vgoto(get_int(0)); + break; + + case BSETXY: /* new x and y coordinates */ + hgoto(get_int(0)); + vgoto(get_int(0)); + break; + + case BINTEN: /* mark the current point */ + fprintf(fp_out, "%d %d p\n", hpos, vpos); + break; + + case BVISX: /* visible x */ + vector(X_COORD, VISIBLE); + break; + + case BINVISX: /* invisible x */ + vector(X_COORD, INVISIBLE); + break; + + case BVISY: /* visible y */ + vector(Y_COORD, VISIBLE); + break; + + case BINVISY: /* invisible y */ + vector(Y_COORD, INVISIBLE); + break; + + case BVEC: /* arbitrary vector */ + vector(LONGVECTOR, VISIBLE); + break; + + case BSVEC: /* short vector */ + vector(SHORTVECTOR, VISIBLE); + break; + + case BRECT: /* draw rectangle */ + rectangle(OUTLINE); + break; + + case BPOINT1: /* point plot 1 */ + case BPOINT: /* point plot 2 */ + point_plot(ch, get_char()); + break; + + case BLINE: /* line plot */ + line_plot(); + break; + + case BLTY: /* line type */ + fprintf(fp_out, "%s l\n", styles[get_data()]); + break; + + case BARC: /* circular arc */ + arc(OUTLINE); + break; + + case BFARC: /* filled circle */ + arc(FILL); + break; + + case BFRECT: /* filled rectangle */ + rectangle(FILL); + break; + + case BRASRECT: /* raster rectangle */ + error(FATAL, "Raster Rectangle not implemented"); + break; + + case BCOL: /* select color */ + set_color(get_data()); + break; + + case BFTRAPH: /* filled trapezoid */ + trapezoid(); + break; + + case BPAT: /* pattern for area filling */ + pattern(); + break; + + case BCSZ: /* change BGI character 'size' */ + setsize(get_data()); + break; + + case BNOISE: /* from bad file format */ + break; + + default: /* don't recognize the code */ + error(FATAL, "bad BGI command %d (0%o)", ch, ch); + break; + } /* End switch */ + + if ( debug == ON ) + fprintf(stderr, "\n"); + } /* End while */ + + formfeed(); /* in case BEND was missing */ + +} /* End of conv */ + +/*****************************************************************************/ + +hgoto(n) + + int n; /* new horizontal position */ + +{ + +/* + * + * Sets the current BGI horizontal position to n. + * + */ + + hpos = n; + +} /* End of hgoto */ + +/*****************************************************************************/ + +vgoto(n) + + int n; /* move to this vertical position */ + +{ + +/* + * + * Sets the absolute vertical position to n. + * + */ + + vpos = n; + +} /* End of vgoto */ + +/*****************************************************************************/ + +setsize(n) + + int n; /* BGI size - just a grid separation */ + +{ + +/* + * + * Called when we're supposed to change the BGI character size to n. The BGI + * size is the grid separation in a 5 by 7 array in which characters are assumed + * to be built. + * + */ + + bgisize = n; + linespace = LINESPACE(bgisize); + + fprintf(fp_out, "%d f\n", bgisize); + + if ( debug == ON ) + fprintf(stderr, "BGI size = %d\n", n); + +} /* End of setsize */ + +/*****************************************************************************/ + +repeat() + +{ + + int count; /* repeat this many times */ + int ch; /* next input character */ + +/* + * + * Haven't implemented repeats, although it wouldn't be difficult. Apparently it's + * not used by any graphics packages that generate BGI. + * + */ + + count = get_int(); /* get the repeat count */ + + while ( (ch = get_char()) != EOF && ch != BENDR ) ; + +} /* End of repeat */ + +/*****************************************************************************/ + +text(angle) + + int angle; /* either 0 or 90 degrees */ + +{ + + int ch; /* next character from file *fp_in */ + +/* + * + * Called from conv() after we've entered one of the graphical character modes. + * Characters are read from the input file and printed until the next mode change + * opcode is found (or until EOF). angle will be 90 for rotated character mode + * and 0 otherwise. + * + * + */ + + fprintf(fp_out, "%d %d %d(", angle, hpos, vpos); + + while ( (ch = get_char()) != EOF ) { + if ( ch == BGRAPH || ch == BCHAR || ch == BRCHAR ) { + ungetc(ch, fp_in); + position--; + break; + } /* End if */ + + switch ( ch ) { + case '\012': + vgoto(vpos - linespace); + + case '\015': + hgoto(0); + fprintf(fp_out, ")t\n%d %d %d(", angle, hpos, vpos); + break; + + case '(': + case ')': + case '\\': + putc('\\', fp_out); + + default: + if ( isascii(ch) && isprint(ch) ) + putc(ch, fp_out); + else fprintf(fp_out, "\\%.3o", ch & 0377); + break; + } /* End switch */ + } /* End while */ + + fprintf(fp_out, ") t\n"); + +} /* End of text */ + +/*****************************************************************************/ + +formfeed() + +{ + + int ch; /* repeat count for this page */ + +/* + * + * Does whatever is needed to print the last page and get ready for the next one. + * It's called, from conv(), after a BEND code is processed. I'm ignoring the + * copy count that's expected to follow each page. + * + */ + + if ( bgimode == BGRAPH && (ch = get_char()) != EOF && ! (ch & MSB) ) { + ungetc(ch, fp_in); + position--; + } /* End if */ + + if ( fp_out == stdout ) /* count the last page */ + printed++; + + fprintf(fp_out, "cleartomark\n"); + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + + while ( (ch = get_char()) == 0 ) ; /* skip any NULL characters */ + ungetc(ch, fp_in); + position--; + + if ( ungetc(getc(fp_in), fp_in) == EOF ) + redirect(-1); + else redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d pagesetup\n", printed+1); + + setsize(bgisize); + hpos = vpos = 0; + +} /* End of formfeed */ + +/*****************************************************************************/ + +subr_def() + +{ + +/* + * + * Starts a subroutine definition. All subroutines are defined as PostScript + * procedures that begin with the character S and end with the subroutine's id + * (a number between 0 and 63 - I guess). The primary, and perhaps only use of + * subroutines is in special color plots produced by several graphics libraries, + * and even there it's not all that common. I've also chosen not to worry about + * nested subroutine definitions - that would certainly be overkill! + * + * All subroutines set up their own (translated) coordinate system, do their work + * in that system, and restore things when they exit. To make everything work + * properly we save the current point (in shpos and svpos), set our position to + * (0, 0), and restore things at the end of the subroutine definition. That means + * hpos and vpos measure the relative displacement after a subroutine returns, and + * we save those values in the displacement[] array. The displacements are used + * (in subr_call()) to properly adjust our position after each subroutine call, + * and all subroutines are called with the current x and y coordinates on top of + * the stack. + * + */ + + if ( in_subr == TRUE ) /* a nested subroutine definition?? */ + error(FATAL, "can't handle nested subroutine definitions"); + + if ( (subr_id = get_data()) == EOF ) + error(FATAL, "missing subroutine identifier"); + + if ( in_global == FALSE ) { /* just used to reduce file size some */ + fprintf(fp_out, "cleartomark\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s", BEGINGLOBAL); + in_global = TRUE; + } /* End if */ + + fprintf(fp_out, "/S%d {\n", subr_id); + fprintf(fp_out, "gsave translate\n"); + + shpos = hpos; /* save our current position */ + svpos = vpos; + + hgoto(0); /* start at the origin */ + vgoto(0); + + in_subr = TRUE; /* in a subroutine definition */ + +} /* End of subr_def */ + +/*****************************************************************************/ + +subr_end() + +{ + + int ch; /* for looking at next opcode */ + +/* + * + * Handles stuff needed at the end of each subroutine. Want to remember the change + * in horizontal and vertical positions for each subroutine so we can adjust our + * position after each call - just in case. The current position was set to (0, 0) + * before we started the subroutine definition, so when we get here hpos and vpos + * are the relative displacements after the subroutine is called. They're saved in + * the displacement[] array and used to adjust the current position when we return + * from a subroutine. + * + */ + + if ( in_subr == FALSE ) /* not in a subroutine definition?? */ + error(FATAL, "subroutine end without corresponding start"); + + fprintf(fp_out, "grestore\n"); + fprintf(fp_out, "} def\n"); + + if ( in_global == TRUE && (ch = get_char()) != BSUB ) { + fprintf(fp_out, "%s", ENDGLOBAL); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + in_global = FALSE; + } /* End if */ + + ungetc(ch, fp_in); /* put back the next opcode */ + + displacement[subr_id].dx = hpos; + displacement[subr_id].dy = vpos; + + hgoto(shpos); /* back to where we started */ + vgoto(svpos); + + in_subr = FALSE; /* done with the definition */ + +} /* End of subr_end */ + +/*****************************************************************************/ + +subr_call() + +{ + + int ch; /* next byte from *fp_in */ + int id; /* subroutine id if ch wasn't an opcode */ + +/* + * + * Handles subroutine calls. Everything that follows the BCALL opcode (up to the + * next opcode) is taken as a subroutine identifier - thus the loop that generates + * the subroutine calls. + * + */ + + while ( (ch = get_char()) != EOF && (ch & MSB) ) { + id = ch & DMASK; + fprintf(fp_out, "%d %d S%d\n", hpos, vpos, id); + + hgoto(hpos + displacement[id].dx); /* adjust our position */ + vgoto(vpos + displacement[id].dy); + } /* End while */ + + ungetc(ch, fp_in); + +} /* End of subr_call */ + +/*****************************************************************************/ + +vector(var, mode) + + int var; /* coordinate that varies next? */ + int mode; /* VISIBLE or INVISIBLE vectors */ + +{ + + int ch; /* next character from *fp_in */ + int x, y; /* line drawn to this point */ + int count = 0; /* number of points so far */ + +/* + * + * Handles plotting of all types of BGI vectors. If it's a manhattan vector var + * specifies which coordinate will be changed by the next number in the input + * file. + * + */ + + x = hpos; /* set up the first point */ + y = vpos; + + while ( (ch = get_char()) != EOF && ch & MSB ) { + if ( var == X_COORD ) /* next length is change in x */ + x += get_int(ch); + else if ( var == Y_COORD ) /* it's the change in y */ + y += get_int(ch); + else if ( var == LONGVECTOR ) { /* long vector */ + x += get_int(ch); + y += get_int(0); + } else { /* must be a short vector */ + x += ((ch & MSBMAG) * ((ch & SGNB) ? -1 : 1)); + y += (((ch = get_data()) & MSBMAG) * ((ch & SGNB) ? -1 : 1)); + } /* End else */ + + if ( mode == VISIBLE ) { /* draw the line segment */ + fprintf(fp_out, "%d %d\n", hpos - x, vpos - y); + count++; + } /* End if */ + + hgoto(x); /* adjust the current BGI position */ + vgoto(y); + + if ( var == X_COORD ) /* vertical length comes next */ + var = Y_COORD; + else if ( var == Y_COORD ) /* change horizontal next */ + var = X_COORD; + } /* End while */ + + if ( count > 0 ) + fprintf(fp_out, "%d %d v\n", hpos, vpos); + + ungetc(ch, fp_in); /* it wasn't part of the vector */ + position--; + +} /* End of vector */ + +/*****************************************************************************/ + +rectangle(mode) + + int mode; /* FILL or OUTLINE the rectangle */ + +{ + + int deltax; /* displacement for horizontal side */ + int deltay; /* same but for vertical sides */ + +/* + * + * Draws a rectangle and either outlines or fills it, depending on the value of + * mode. Would be clearer, and perhaps better, if {stroke} or {fill} were put on + * the stack instead of 0 or 1. R could then define the path and just do an exec + * to fill or stroke it. + * + */ + + deltax = get_int(0); /* get the height and width */ + deltay = get_int(0); + + if ( mode == OUTLINE ) + fprintf(fp_out, "0 %d %d %d %d R\n", deltax, deltay, hpos, vpos); + else fprintf(fp_out, "1 %d %d %d %d R\n", deltax, deltay, hpos, vpos); + +} /* End of rectangle */ + +/*****************************************************************************/ + +trapezoid() + +{ + + int kind; /* which sides are parallel */ + int d[6]; /* true displacements - depends on kind */ + +/* + * + * Handles filled trapeziods. A data byte of 0101 following the opcode means the + * horizontal sides are parallel, 0102 means the vertical sides are parallel. + * Filling is handled by eofill so we don't need to get things in the right order. + * + */ + + kind = get_data(); + + d[0] = get_int(0); + d[1] = 0; + d[2] = get_int(0); + d[3] = get_int(0); + d[4] = get_int(0); + d[5] = 0; + + if ( kind == 2 ) { /* parallel sides are vertical */ + d[1] = d[0]; + d[0] = 0; + d[5] = d[4]; + d[4] = 0; + } /* End if */ + + fprintf(fp_out, "%d %d %d %d %d %d %d %d T\n", d[4], d[5], d[2], d[3], d[0], d[1], hpos, vpos); + +} /* End of trapezoid */ + +/*****************************************************************************/ + +point_plot(mode, ch) + + int mode; /* plotting mode BPOINT or BPOINT1 */ + int ch; /* will be placed at the points */ + +{ + + int c; /* next character from input file */ + int x, y; /* ch gets put here next */ + int deltax; /* x increment for BPOINT1 mode */ + +/* + * + * The two point plot modes are used to place a character at selected points. The + * difference in the two modes, namely BPOINT and BPOINT1, is the way we get the + * coordinates of the next point. In BPOINT1 the two bytes immediately following + * ch select a constant horizontal change, while both coordinates are given for + * all points in BPOINT mode. + * + */ + + if ( mode == BPOINT1 ) { /* first integer is change in x */ + deltax = get_int(0); + x = hpos - deltax; + } /* End if */ + + while ( (c = get_char()) != EOF && (c & MSB) ) { + if ( mode == BPOINT1 ) { /* only read y coordinate */ + y = get_int(c); + x += deltax; + } else { /* get new x and y from input file */ + x = get_int(c); + y = get_int(0); + } /* End else */ + + hgoto(x); /* adjust BGI position */ + vgoto(y); + + fprintf(fp_out, "%d %d\n", hpos, vpos); + } /* End while */ + + putc('(', fp_out); + + switch ( ch ) { + case '(': + case ')': + case '\\': + putc('\\', fp_out); + + default: + putc(ch, fp_out); + } /* End switch */ + + fprintf(fp_out, ")pp\n"); + + ungetc(c, fp_in); /* it wasn't part of the point plot */ + position--; + +} /* End of point_plot */ + +/*****************************************************************************/ + +line_plot() + +{ + + int c; /* next input character from fp_in */ + int deltax; /* change in x coordinate */ + int x0, y0; /* starting point for next segment */ + int x1, y1; /* endpoint of the line */ + int count = 0; /* number of points so far */ + +/* + * + * Essentially the same format as BPOINT1, except that in this case we connect + * pairs of points by line segments. + * + */ + + deltax = get_int(0); /* again the change in x is first */ + + x1 = hpos; /* so it works first time through */ + y1 = get_int(0); + + while ( (c = get_char()) != EOF && (c & MSB) ) { + x0 = x1; /* line starts here */ + y0 = y1; + + x1 += deltax; /* and ends at this point */ + y1 = get_int(c); + + fprintf(fp_out, "%d %d\n", -deltax, y0 - y1); + count++; + } /* End while */ + + hgoto(x1); /* adjust current BGI position */ + vgoto(y1); + + if ( count > 0 ) + fprintf(fp_out, "%d %d v\n", hpos, vpos); + + ungetc(c, fp_in); /* wasn't part of the line */ + position--; + +} /* End of line_plot */ + +/*****************************************************************************/ + +arc(mode) + + int mode; /* FILL or OUTLINE the path */ + +{ + + int dx1, dy1; /* displacements for first point */ + int dx2, dy2; /* same for the second point */ + int radius; /* of the arc */ + int angle1, angle2; /* starting and ending angles */ + +/* + * + * Called whenever we need to draw an arc. I'm ignoring filled slices for now. + * + */ + + dx1 = get_int(0); /* displacements relative to center */ + dy1 = get_int(0); + dx2 = get_int(0); + dy2 = get_int(0); + + radius = get_int(0); /* and the radius */ + + if ( radius == 0 ) /* nothing to do */ + return; + + angle1 = (atan2((double) dy1, (double) dx1) * 360) / (2 * PI) + .5; + angle2 = (atan2((double) dy2, (double) dx2) * 360) / (2 * PI) + .5; + + fprintf(fp_out, "%d %d %d %d %d arcn stroke\n", hpos, vpos, radius, angle1, angle2); + +} /* End of arc */ + +/*****************************************************************************/ + +pattern() + +{ + + double red = 0; /* color components */ + double green = 0; + double blue = 0; + int kind; /* corse or fine pattern */ + int val; /* next color data byte */ + int i; /* loop index */ + +/* + * + * Handles patterns by setting the current color based of the values assigned to + * the next four data bytes. BGI supports two kinds of patterns (fine or coarse) + * but I'm handling each in the same way - for now. In a fine pattern the four + * data bytes assign a color to four individual pixels (upperleft first) while + * in a coarse pattern the four colors are assigned to groups of four pixels, + * for a total of 16. Again the first color goes to the group in the upper left + * corner. The byte immediately following the BPAT opcode selects fine (040) or + * coarse (041) patterns. The PostScript RGB color is assigned by averaging the + * RED, GREEN, and BLUE components assigned to the four pixels (or groups of + * pixels). Acceptable results, but there's no distinction between fine and + * coarse patterns. + * + */ + + if ( (kind = get_char()) == EOF ) + error(FATAL, "bad pattern command"); + + for ( i = 0; i < 4; i++ ) { + val = get_data(); + red += get_color(val, RED); + green += get_color(val, GREEN); + blue += get_color(val, BLUE); + } /* End for */ + + fprintf(fp_out, "%g %g %g c\n", red/4, green/4, blue/4); + +} /* End of pattern */ + +/*****************************************************************************/ + +get_color(val, component) + + int val; /* color data byte */ + int component; /* RED, GREEN, or BLUE component */ + +{ + + + int primary; /* color mixing mode - bits 2 to 4 */ + int plane; /* primary color plane - bits 5 to 7 */ + unsigned rgbcolor; /* PostScript expects an RGB triple */ + +/* + * + * Picks the requested color component (RED, GREEN, or BLUE) from val and returns + * the result to the caller. BGI works with Cyan, Yellow, and Magenta so the one's + * complement stuff (following the exclusive or'ing) recovers the RED, BLUE, and + * GREEN components that PostScript's setrgbcolor operator needs. The PostScript + * interpreter in the ColorScript 100 has a setcmycolor operator, but it's not + * generally available so I've decided to stick with setrgbcolor. + * + */ + + primary = (val >> 3) & 07; + plane = val & 07; + rgbcolor = (~(primary ^ plane)) & 07; + + if ( debug == ON ) + fprintf(stderr, "val = %o, primary = %o, plane = %o, rgbcolor = %o\n", + val, primary, plane, rgbcolor); + + switch ( component ) { + case RED: + return(rgbcolor>>2); + + case GREEN: + return(rgbcolor&01); + + case BLUE: + return((rgbcolor>>1)&01); + + default: + error(FATAL, "unknown color component"); + return(0); + } /* End switch */ + +} /* End of get_color */ + +/*****************************************************************************/ + +set_color(val) + + int val; /* color data byte */ + +{ + +/* + * + * Arranges to have the color set to the value requested in the BGI data byte val. + * + */ + + fprintf(fp_out, "%d %d %d c\n", get_color(val, RED), get_color(val, GREEN), get_color(val, BLUE)); + +} /* End of set_color */ + +/*****************************************************************************/ + +get_int(highbyte) + + int highbyte; /* already read this byte */ + +{ + + int lowbyte; /* this and highbyte make the int */ + +/* + * + * Figures out the value on the integer (sign magnitude form) that's next in the + * input file. If highbyte is nonzero we'll use it and the next byte to build the + * integer, otherwise two bytes are read from fp_in. + * + */ + + + if ( highbyte == 0 ) /* need to read the first byte */ + highbyte = get_data(); + + lowbyte = get_data(); /* always need the second byte */ + + return(highbyte & SGNB ? -MAG(highbyte, lowbyte) : MAG(highbyte, lowbyte)); + +} /* End of get_int */ + +/*****************************************************************************/ + +get_data() + +{ + + int val; /* data value returned to caller */ + +/* + * + * Called when we expect to find a single data character in the input file. The + * data bit is turned off and the resulting value is returned to the caller. + * + */ + + if ( (val = get_char()) == EOF || ! (val & MSB) ) + error(FATAL, "missing data value"); + + return(val & DMASK); + +} /* End of get_data */ + +/*****************************************************************************/ + +get_char() + +{ + + int ch; /* character we just read */ + +/* + * + * Reads the next character from file *fp_in and returns the value to the caller. + * This routine isn't really needed, but we may want to deal directly with some + * screwball file formats so I thought it would probably be a good idea to isolate + * all the input in one routine that could be easily changed. + * + */ + + if ( (ch = getc(fp_in)) != EOF ) { + position++; + ch &= CHMASK; + } /* End if */ + + if ( debug == ON ) + fprintf(stderr, "%o ", ch); + + return(ch); + +} /* End of get_char */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postbgi/postbgi.h b/sys/src/cmd/postscript/postbgi/postbgi.h new file mode 100755 index 000000000..41e3003c1 --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.h @@ -0,0 +1,203 @@ +/* + * + * BGI opcodes. + * + */ + +#define BRCHAR 033 /* rotated character mode */ +#define BCHAR 034 /* graphical character mode */ +#define BGRAPH 035 /* graphical master mode */ + +#define BSUB 042 /* subroutine definition */ +#define BRET 043 /* end of subroutine */ +#define BCALL 044 /* subroutine call */ + +#define BEND 045 /* end page */ +#define BERASE 046 /* erase - obsolete */ +#define BREP 047 /* repeat */ +#define BENDR 050 /* end repeat */ + +#define BSETX 051 /* set horizontal position */ +#define BSETY 052 /* set vertical position */ +#define BSETXY 053 /* set horizontal and vertical positions */ +#define BINTEN 054 /* intensify - mark current pixel */ + +#define BVISX 055 /* manhattan vector - change x first */ +#define BINVISX 056 /* same as BVISX but nothing drawn */ +#define BVISY 057 /* manhattan vector - change y first */ +#define BINVISY 060 /* same as BVISY but nothing drawn */ + +#define BVEC 061 /* arbitrary long vector */ +#define BSVEC 062 /* arbitrary short vector */ +#define BRECT 063 /* outline rectangle */ +#define BPOINT1 064 /* point plot - mode 1 */ +#define BPOINT 065 /* point plot - mode 2 */ +#define BLINE 066 /* line plot */ + +#define BCSZ 067 /* set character size */ +#define BLTY 070 /* select line type */ +#define BARC 071 /* draw circular arc */ +#define BFARC 072 /* filled circular arc */ +#define BFRECT 073 /* filled rectangle */ +#define BRASRECT 074 /* raster rectangle */ +#define BCOL 075 /* select color */ +#define BFTRAPH 076 /* filled trapezoid */ +#define BPAT 077 /* pattern are for filling - no info */ + +#define BNOISE 0 /* from bad file format */ + +/* + * + * Character size is controlled by the spacing of dots in a 5x7 dot matrix, which + * by default is set to BGISIZE. + * + */ + +#define BGISIZE 2 /* default character grid spacing */ + +/* + * + * Definitions used to decode the bytes read from a BGI file. + * + */ + +#define CHMASK 0177 /* characters only use 7 bits */ +#define DMASK 077 /* data values use lower 6 bits */ +#define MSB 0100 /* used to check for data or opcode */ +#define SGNB 040 /* sign bit for integers */ +#define MSBMAG 037 /* mag of most sig byte in a BGI int */ + +/* + * + * Descriptions of BGI vectors and what's done when they're drawn. + * + */ + +#define X_COORD 0 /* change x next in manhattan vector */ +#define Y_COORD 1 /* same but y change comes next */ +#define LONGVECTOR 2 /* arbitrary long vector */ +#define SHORTVECTOR 3 /* components given in 6 bits */ + +#define VISIBLE 0 /* really draw the vector */ +#define INVISIBLE 1 /* just move the current position */ + +/* + * + * What's done with a closed path. + * + */ + +#define OUTLINE 0 /* outline the defined path */ +#define FILL 1 /* fill it in */ + +/* + * + * BGI line style definitions. They're used as an index into the STYLES array, + * which really belongs in the prologue. + * + */ + +#define SOLID 0 +#define DOTTED 1 +#define SHORTDASH 2 +#define DASH 3 +#define LONGDASH 4 +#define DOTDASH 5 +#define THREEDOT 6 + +#define STYLES \ + \ + { \ + "[]", \ + "[.5 2]", \ + "[2 4]", \ + "[4 4]", \ + "[8 4]", \ + "[.5 2 4 2]", \ + "[.5 2 .5 2 .5 2 4 2]" \ + } + +/* + * + * Three constants used to choose which component (RED, GREEN, or BLUE) we're + * interested in. BGI colors are specified as a single data byte and pulling a + * particular component out of the BGI color byte is handled by procedure + * get_color(). + * + */ + +#define RED 0 +#define GREEN 1 +#define BLUE 2 + +/* + * + * An array of type Disp is used to save the horizontal and vertical displacements + * that result after a subroutine has been called. Needed so we can properly adjust + * our horizontal and vertical positions after a subroutine call. Entries are made + * immediately after a subroutine is defined and used after the call. Subroutine + * names are integers that range from 0 to 63 (assigned in the BG file) and the + * name is used as an index into the Disp array when we save or retrieve the + * displacement. + * + */ + +typedef struct { + int dx; /* horizontal and */ + int dy; /* vertical displacements */ +} Disp; + +/* + * + * An array of type Fontmap helps convert font names requested by users into + * legitimate PostScript names. The array is initialized using FONTMAP, which must + * end with and entry that has NULL defined as its name field. + * + */ + +typedef struct { + char *name; /* user's font name */ + char *val; /* corresponding PostScript name */ +} Fontmap; + +#define FONTMAP \ + \ + { \ + "R", "Courier", \ + "I", "Courier-Oblique", \ + "B", "Courier-Bold", \ + "CO", "Courier", \ + "CI", "Courier-Oblique", \ + "CB", "Courier-Bold", \ + "CW", "Courier", \ + "PO", "Courier", \ + "courier", "Courier", \ + "cour", "Courier", \ + "co", "Courier", \ + NULL, NULL \ + } + +/* + * + * Two macros that are useful in processing BGI files: + * + * MAG(A, B) - Takes bytes A and B which have been read from a BGI file + * and returns the magnitude of the integer represented by + * the two bytes. + * + * LINESPACE(A) - Takes BGI size A and returns the number of address units + * that can be used for a reasonable interline spacing. + * + */ + +#define MAG(A, B) (((A & MSBMAG) << 6) | (B & DMASK)) +#define LINESPACE(A) (8 * A) + +/* + * + * Some of the non-integer valued functions in postdmd.c. + * + */ + +char *get_font(); + diff --git a/sys/src/cmd/postscript/postbgi/postbgi.mk b/sys/src/cmd/postscript/postbgi/postbgi.mk new file mode 100755 index 000000000..24ad6b27d --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.mk @@ -0,0 +1,93 @@ +MAKE=/bin/make +MAKEFILE=postbgi.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +HFILES=postbgi.h\ + $(COMMONDIR)/comments.h\ + $(COMMONDIR)/ext.h\ + $(COMMONDIR)/gen.h\ + $(COMMONDIR)/path.h + +OFILES=postbgi.o\ + $(COMMONDIR)/glob.o\ + $(COMMONDIR)/misc.o\ + $(COMMONDIR)/request.o + +all : postbgi + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + @if [ ! -d "$(POSTLIB)" ]; then \ + mkdir $(POSTLIB); \ + chmod 755 $(POSTLIB); \ + chgrp $(GROUP) $(POSTLIB); \ + chown $(OWNER) $(POSTLIB); \ + fi + cp postbgi $(POSTBIN)/postbgi + @chmod 755 $(POSTBIN)/postbgi + @chgrp $(GROUP) $(POSTBIN)/postbgi + @chown $(OWNER) $(POSTBIN)/postbgi + cp postbgi.ps $(POSTLIB)/postbgi.ps + @chmod 644 $(POSTLIB)/postbgi.ps + @chgrp $(GROUP) $(POSTLIB)/postbgi.ps + @chown $(OWNER) $(POSTLIB)/postbgi.ps + cp postbgi.1 $(MAN1DIR)/postbgi.1 + @chmod 644 $(MAN1DIR)/postbgi.1 + @chgrp $(GROUP) $(MAN1DIR)/postbgi.1 + @chown $(OWNER) $(MAN1DIR)/postbgi.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postbgi + +postbgi : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postbgi $(OFILES) -lm + +postbgi.o : $(HFILES) + +$(COMMONDIR)/glob.o\ +$(COMMONDIR)/misc.o\ +$(COMMONDIR)/request.o : + @cd $(COMMONDIR); $(MAKE) -f common.mk `basename $@` + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + postbgi.1 >XXX.1; \ + mv XXX.1 postbgi.1 + diff --git a/sys/src/cmd/postscript/postbgi/postbgi.ps b/sys/src/cmd/postscript/postbgi/postbgi.ps new file mode 100755 index 000000000..1fa486f2a --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.ps @@ -0,0 +1,135 @@ +% +% Version 3.3.2 prologue for BGI files - STARE or PRISM. +% + +/#copies 1 store +/aspectratio 1 def +/fixlinewidth true def +/fixscreen false def +/font /Courier def +/formsperpage 1 def +/landscape false def +/linewidth 0 def +/magnification 1 def +/margin 0 def +/orientation 0 def +/prism false def +/resolution 128 def +/rotation 1 def +/scaletodevice false def +/screenheight 1280 def +/screenwidth 1024 def +/xoffset 0 def +/yoffset 0 def + +/devres 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt def + +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/kshow {kshow} bind def % so later references don't bind +/show {show} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + prism {/fixscreen true def /scaletodevice true def} if + prism linewidth 0 eq and {/linewidth .3 def} if + fixscreen {devres 4 div orientation currentscreen 3 1 roll pop pop setscreen} if + + pagedimensions + /scaling + scaletodevice + {devres resolution div truncate 72 mul devres div dup} + {height margin sub screenheight div width margin sub screenwidth div} + ifelse + min def + xcenter ycenter translate + orientation rotation mul rotate + xoffset inch yoffset inch translate + magnification dup aspectratio mul scale + scaling scaling scale + screenwidth 2 div neg screenheight 2 div neg translate + + tietodevicespace + linewidth scaling div setlinewidth + 1 setlinecap + newpath +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def} bind def + +/tietodevicespace { + fixlinewidth linewidth 0 gt and linewidth 1 lt and { + /moveto { + 2 copy /Y exch def /X exch def + transform round exch round exch itransform + moveto + } bind def + /lineto { + 2 copy /Y exch def /X exch def + transform round exch round exch itransform + lineto + } bind def + /rlineto {Y add exch X add exch lineto} bind def + /v V 0 get bind def + } if +} def + +/V [{moveto counttomark 2 idiv {rlineto} repeat stroke}] def +/v V 0 get bind def +/p {linewidth 2 div 0 360 arc fill} bind def +/pp {/ch exch def counttomark 2 idiv {moveto xc yc rmoveto ch show} repeat} bind def + +/l {{scaling div} forall counttomark array astore 0 setdash} bind def +/c {setrgbcolor} bind def + +/T {newpath moveto rlineto rlineto rlineto closepath eofill} bind def + +/R { + newpath moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath + 0 eq {stroke} {eofill} ifelse +} bind def + +/f { + dup dup + /charwidth exch 6 mul def + /xc exch -2.5 mul def + /yc exch -3.5 mul def + font findfont charwidth .6 div scalefont setfont +} bind def + +/t { + /str exch def + gsave + translate rotate + xc yc moveto + currentpoint + { + pop pop + exch charwidth add exch + moveto currentpoint + } str kshow + pop pop + grestore +} bind def + +/done {/lastpage where {pop lastpage} if} def diff --git a/sys/src/cmd/postscript/postdaisy/Opostdaisy.c b/sys/src/cmd/postscript/postdaisy/Opostdaisy.c new file mode 100755 index 000000000..a440fd604 --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/Opostdaisy.c @@ -0,0 +1,1222 @@ +/* + * + * postdaisy - PostScript translator for Diablo 1640 files. + * + * A program that translates Diablo 1640 files into PostScript. Absolutely nothing + * is guaranteed. Quite a few things haven't been implemented, and what's been + * done isn't well tested. Most of the documentation used to write this program + * was taken from the 'Diablo Emulator' section of a recent Imagen manual. + * + * Some of document comments that are generated may not be right. Most of the test + * files I used produced a trailing blank page. I've put a check in formfeed() that + * won't print the last page if it doesn't contain any text, but PAGES comments may + * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or + * bold printing have been turned on by escape commands. + * + * The brute force approach used to implement horizontal and vertical tabs leaves + * much to be desired, and may not work for very small initial hmi and vmi values. + * At the very least I should have used malloc() to get space for the two tabstop + * arrays after hmi and vmi are known! + * + * Reverse printing mode hasn't been tested at all, but what's here should be + * close even though it's not efficient. + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how this program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects to + * find the current page number on the stack. + * + * t + * + * mark str1 x1 str2 x2 ... strn xn y hmi t mark + * + * Handles all the text on the stack. Characters in the strings are + * printed using hmi as the character advance, and all strings are at + * vertical position y. Each string is begins at the horizontal position + * that preceeds it. + * + * f + * + * font f - + * + * Use font f, where f is the full PostScript font name. Only used when + * we switch to auto underline (Courier-Italic) or bold (Courier-Bold) + * printing. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <fcntl.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ +#include "postdaisy.h" /* a few special definitions */ + +char *optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI"; + +char *prologue = POSTDAISY; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +char htabstops[COLUMNS]; /* horizontal */ +char vtabstops[ROWS]; /* and vertical tabs */ + +int res = RES; /* input file resolution - sort of */ + +int hmi = HMI; /* horizontal motion index - 1/120 inch */ +int vmi = VMI; /* vertical motion index - 1/48 inch */ +int ohmi = HMI; /* original hmi */ +int ovmi = VMI; /* and vmi - for tabs and char size */ + +int hpos = 0; /* current horizontal */ +int vpos = 0; /* and vertical position */ + +int lastx = -1; /* printer's last horizontal */ +int lasty = -1; /* and vertical position */ +int lasthmi = -1; /* hmi for current text strings */ + +int lastc = -1; /* last printed character */ +int prevx = -1; /* at this position */ + +int leftmargin = LEFTMARGIN; /* page margins */ +int rightmargin = RIGHTMARGIN; +int topmargin = TOPMARGIN; +int bottommargin = BOTTOMMARGIN; + +int stringcount = 0; /* number of strings on the stack */ +int stringstart = 1; /* column where current one starts */ +int advance = 1; /* -1 if in backward print mode */ + +int lfiscr = OFF; /* line feed implies carriage return */ +int crislf = OFF; /* carriage return implies line feed */ + +int linespp = 0; /* lines per page if it's positive */ +int markedpage = FALSE; /* helps prevent trailing blank page */ +int page = 0; /* page we're working on */ +int printed = 0; /* printed this many pages */ + +Fontmap fontmap[] = FONTMAP; /* for translating font names */ +char *fontname = "Courier"; /* use this PostScript font */ +int shadowprint = OFF; /* automatic bold printing if ON */ + +FILE *fp_in; /* read from this file */ +FILE *fp_out = stdout; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that translates Diablo 1640 files into PostScript. Nothing + * is guaranteed - the program not well tested and doesn't implement everything. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* really just for error messages */ + + init_signals(); /* sets up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* handle the command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + + int interrupt(); /* signal handler */ + +/* + * + * Makes sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + if ( DOROUND ) + cat(ROUNDPAGE); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + int n; /* for CR and LF modes */ + +/* + * + * Reads and processes the command line options. Added the -P option so arbitrary + * PostScript code can be passed through. Expect it could be useful for changing + * definitions in the prologue for which options have not been defined. + * + * Although any PostScript font can be used, things will only work for constant + * width fonts. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'f': /* use this PostScript font */ + fontname = get_font(optarg); + fprintf(stdout, "/font /%s def\n", fontname); + break; + + case 'h': /* default character spacing */ + ohmi = hmi = atoi(optarg) * HSCALE; + fprintf(stdout, "/hmi %s def\n", optarg); + break; + + case 'l': /* lines per page */ + linespp = atoi(optarg); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'r': /* set CR and LF modes */ + n = atoi(optarg); + if ( n & 01 ) + lfiscr = ON; + else lfiscr = OFF; + if ( n & 02 ) + crislf = ON; + else crislf = OFF; + break; + + case 's': /* point size */ + fprintf(stdout, "/pointsize %s def\n", optarg); + break; + + case 'v': /* default line spacing */ + ovmi = vmi = atoi(optarg) * VSCALE; + break; + + case 'x': /* shift things horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +char *get_font(name) + + char *name; /* name the user asked for */ + +{ + + int i; /* for looking through fontmap[] */ + +/* + * + * Called from options() to map a user's font name into a legal PostScript name. + * If the lookup fails *name is returned to the caller. That should let you choose + * any PostScript font, although things will only work well for constant width + * fonts. + * + */ + + for ( i = 0; fontmap[i].name != NULL; i++ ) + if ( strcmp(name, fontmap[i].name) == 0 ) + return(fontmap[i].val); + + return(name); + +} /* End of get_font */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + fp_in = stdin; + + if ( argc < 1 ) + text(); + else { /* at least one argument is left */ + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + text(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files, so mark the end of the pages, make sure the + * last page is printed, and restore the initial environment. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct provided it's not NULL. Accounting + * is requested using the -A or -J options. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +text() + +{ + + int ch; /* next input character */ + +/* + * + * Translates the next input file into PostScript. The redirect(-1) call forces + * the initial output to go to /dev/null - so the stuff formfeed() does at the + * end of each page doesn't go to stdout. + * + */ + + redirect(-1); /* get ready for the first page */ + formfeed(); /* force PAGE comment etc. */ + inittabs(); + + while ( (ch = getc(fp_in)) != EOF ) + switch ( ch ) { + case '\010': /* backspace */ + backspace(); + break; + + case '\011': /* horizontal tab */ + htab(); + break; + + case '\012': /* new line */ + linefeed(); + break; + + case '\013': /* vertical tab */ + vtab(); + break; + + case '\014': /* form feed */ + formfeed(); + break; + + case '\015': /* carriage return */ + carriage(); + break; + + case '\016': /* extended character set - SO */ + break; + + case '\017': /* extended character set - SI */ + break; + + case '\031': /* next char from supplementary set */ + break; + + case '\033': /* 2 or 3 byte escape sequence */ + escape(); + break; + + default: + if ( isascii(ch) && isprint(ch) ) + oput(ch); + break; + } /* End switch */ + + formfeed(); /* next file starts on a new page? */ + +} /* End of text */ + +/*****************************************************************************/ + +inittabs() + +{ + + int i; /* loop index */ + +/* + * + * Initializes the horizontal and vertical tab arrays. The way tabs are handled is + * quite inefficient and may not work for all initial hmi or vmi values. + * + */ + + for ( i = 0; i < COLUMNS; i++ ) + htabstops[i] = ((i % 8) == 0) ? ON : OFF; + + for ( i = 0; i < ROWS; i++ ) + vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF; + +} /* End of inittabs */ + +/*****************************************************************************/ + +cleartabs() + +{ + + int i; /* loop index */ + +/* + * + * Clears all horizontal and vertical tab stops. + * + */ + + for ( i = 0; i < ROWS; i++ ) + htabstops[i] = OFF; + + for ( i = 0; i < COLUMNS; i++ ) + vtabstops[i] = OFF; + +} /* End of cleartabs */ + +/*****************************************************************************/ + +formfeed() + +{ + +/* + * + * Called whenever we've finished with the last page and want to get ready for the + * next one. Also used at the beginning and end of each input file, so we have to + * be careful about what's done. I've added a simple test before the showpage that + * should eliminate the extra blank page that was put out at the end of many jobs, + * but the PAGES comments may be wrong. + * + */ + + if ( fp_out == stdout ) /* count the last page */ + printed++; + + endline(); /* print the last line */ + + fprintf(fp_out, "cleartomark\n"); + if ( feof(fp_in) == 0 || markedpage == TRUE ) + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + + if ( ungetc(getc(fp_in), fp_in) == EOF ) + redirect(-1); + else redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d pagesetup\n", printed+1); + + vgoto(topmargin); + hgoto(leftmargin); + + markedpage = FALSE; + +} /* End of formfeed */ + +/*****************************************************************************/ + +linefeed() + +{ + + int line = 0; /* current line - based on ovmi */ + +/* + * + * Adjust our current vertical position. If we've passed the bottom of the page + * or exceeded the number of lines per page, print it and go to the upper left + * corner of the next page. This routine is also called from carriage() if crislf + * is ON. + * + */ + + vmot(vmi); + + if ( lfiscr == ON ) + hgoto(leftmargin); + + if ( linespp > 0 ) /* means something so see where we are */ + line = vpos / ovmi + 1; + + if ( vpos > bottommargin || line > linespp ) + formfeed(); + +} /* End of linefeed */ + +/*****************************************************************************/ + +carriage() + +{ + +/* + * + * Handles carriage return character. If crislf is ON we'll generate a line feed + * every time we get a carriage return character. + * + */ + + if ( shadowprint == ON ) /* back to normal mode */ + changefont(fontname); + + advance = 1; + shadowprint = OFF; + + hgoto(leftmargin); + + if ( crislf == ON ) + linefeed(); + +} /* End of carriage */ + +/*****************************************************************************/ + +htab() + +{ + + int col; /* 'column' we'll be at next */ + int i; /* loop index */ + +/* + * + * Tries to figure out where the next tab stop is. Wasn't positive about this + * one, since hmi can change. I'll assume columns are determined by the original + * value of hmi. That fixes them on the page, which seems to make more sense than + * letting them float all over the place. + * + */ + + endline(); + + col = hpos/ohmi + 1; + for ( i = col; i < ROWS; i++ ) + if ( htabstops[i] == ON ) { + col = i; + break; + } /* End if */ + + hgoto(col * ohmi); + lastx = hpos; + +} /* End of htab */ + +/*****************************************************************************/ + +vtab() + +{ + + int line; /* line we'll be at next */ + int i; /* loop index */ + +/* + * + * Looks for the next vertical tab stop in the vtabstops[] array and moves to that + * line. If we don't find a tab we'll just move down one line - shouldn't happen. + * + */ + + endline(); + + line = vpos/ovmi + 1; + for ( i = line; i < COLUMNS; i++ ) + if ( vtabstops[i] == ON ) { + line = i; + break; + } /* End if */ + + vgoto(line * ovmi); + +} /* End of vtab */ + +/*****************************************************************************/ + +backspace() + +{ + +/* + * + * Moves backwards a distance equal to the current value of hmi, but don't go + * past the left margin. + * + */ + + endline(); + + if ( hpos - leftmargin >= hmi ) + hmot(-hmi); + else hgoto(leftmargin); /* maybe just ignore the backspace?? */ + + lastx = hpos; + +} /* End of backspace */ + +/*****************************************************************************/ + +escape() + +{ + + int ch; /* control character */ + +/* + * + * Handles special codes that are expected to follow an escape character. The + * initial escape character is followed by one or two bytes. + * + */ + + switch ( ch = getc(fp_in) ) { + case 'T': /* top margin */ + topmargin = vpos; + break; + + case 'L': /* bottom margin */ + bottommargin = vpos; + break; + + case 'C': /* clear top and bottom margins */ + bottommargin = BOTTOMMARGIN; + topmargin = TOPMARGIN; + break; + + case '9': /* left margin */ + leftmargin = hpos; + break; + + case '0': /* right margin */ + rightmargin = hpos; + break; + + case '1': /* set horizontal tab */ + htabstops[hpos/ohmi] = ON; + break; + + case '8': /* clear horizontal tab at hpos */ + htabstops[hpos/ohmi] = OFF; + break; + + case '-': /* set vertical tab */ + vtabstops[vpos/ovmi] = ON; + break; + + case '2': /* clear all tabs */ + cleartabs(); + break; + + case '\014': /* set lines per page */ + linespp = getc(fp_in); + break; + + case '\037': /* set hmi to next byte minus 1 */ + hmi = HSCALE * (getc(fp_in) - 1); + break; + + case 'S': /* reset hmi to default */ + hmi = ohmi; + break; + + case '\011': /* move to column given by next byte */ + hgoto((getc(fp_in)-1) * ohmi); + break; + + case '?': /* do carriage return after line feed */ + lfiscr = ON; + break; + + case '!': /* don't generate carriage return */ + lfiscr = OFF; + break; + + case '5': /* forward print mode */ + advance = 1; + break; + + case '6': /* backward print mode */ + advance = -1; + break; + + case '\036': /* set vmi to next byte minus 1 */ + vmi = VSCALE * (getc(fp_in) - 1); + break; + + case '\013': /* move to line given by next byte */ + vgoto((getc(fp_in)-1) * ovmi); + break; + + case 'U': /* positive half line feed */ + vmot(vmi/2); + break; + + case 'D': /* negative half line feed */ + vmot(-vmi/2); + break; + + case '\012': /* negative line feed */ + vmot(-vmi); + break; + + case '\015': /* clear all margins */ + bottommargin = BOTTOMMARGIN; + topmargin = TOPMARGIN; + leftmargin = BOTTOMMARGIN; + rightmargin = RIGHTMARGIN; + break; + + case 'E': /* auto underscore - use italic font */ + changefont("/Courier-Oblique"); + break; + + case 'R': /* disable auto underscore */ + changefont(fontname); + break; + + case 'O': /* bold/shadow printing */ + case 'W': + changefont("/Courier-Bold"); + shadowprint = ON; + break; + + case '&': /* disable bold printing */ + changefont(fontname); + shadowprint = OFF; + break; + + case '/': /* ignored 2 byte escapes */ + case '\\': + case '<': + case '>': + case '%': + case '=': + case '.': + case '4': + case 'A': + case 'B': + case 'M': + case 'N': + case 'P': + case 'Q': + case 'X': + case '\010': + break; + + case ',': /* ignored 3 byte escapes */ + case '\016': + case '\021': + getc(fp_in); + break; + + case '3': /* graphics mode - should quit! */ + case '7': + case 'G': + case 'V': + case 'Y': + case 'Z': + error(FATAL, "graphics mode is not implemented"); + break; + + default: + error(FATAL, "missing case for escape o%o\n", ch); + break; + } /* End switch */ + +} /* End of escape */ + +/*****************************************************************************/ + +vmot(n) + + int n; /* move this far vertically */ + +{ + +/* + * + * Move vertically n units from where we are. + * + */ + + vpos += n; + +} /* End of vmot */ + +/*****************************************************************************/ + +vgoto(n) + + int n; /* new vertical position */ + +{ + +/* + * + * Moves to absolute vertical position n. + * + */ + + vpos = n; + +} /* End of vgoto */ + +/*****************************************************************************/ + +hmot(n) + + int n; /* move this horizontally */ + +{ + +/* + * + * Moves horizontally n units from our current position. + * + */ + + hpos += n * advance; + + if ( hpos < leftmargin ) + hpos = leftmargin; + +} /* End of hmot */ + +/*****************************************************************************/ + +hgoto(n) + + int n; /* go to this horizontal position */ + +{ + +/* + * + * Moves to absolute horizontal position n. + * + */ + + hpos = n; + +} /* End of hgoto */ + +/*****************************************************************************/ + +changefont(name) + + char *name; + +{ + +/* + * + * Changes the current font. Used to get in and out of auto underscore and bold + * printing. + * + */ + + endline(); + fprintf(fp_out, "%s f\n", name); + +} /* End of changefont */ + +/*****************************************************************************/ + +startline() + +{ + +/* + * + * Called whenever we want to be certain we're ready to start pushing characters + * into an open string on the stack. If stringcount is positive we've already + * started, so there's nothing to do. The first string starts in column 1. + * + */ + + if ( stringcount < 1 ) { + putc('(', fp_out); + stringstart = lastx = hpos; + lasty = vpos; + lasthmi = hmi; + lastc = -1; + prevx = -1; + stringcount = 1; + } /* End if */ + +} /* End of startline */ + +/*****************************************************************************/ + +endline() + +{ + +/* + * + * Generates a call to the PostScript procedure that processes the text on the + * the stack - provided stringcount is positive. + * + */ + + if ( stringcount > 0 ) + fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi); + + stringcount = 0; + +} /* End of endline */ + +/*****************************************************************************/ + +endstring() + +{ + +/* + * + * Takes the string we've been working on and adds it to the output file. Called + * when we need to adjust our horizontal position before starting a new string. + * Also called from endline() when we're done with the current line. + * + */ + + if ( stringcount > 0 ) { + fprintf(fp_out, ")%d(", stringstart); + lastx = stringstart = hpos; + stringcount++; + } /* End if */ + +} /* End of endstring */ + +/*****************************************************************************/ + +oput(ch) + + int ch; /* next output character */ + +{ + +/* + * + * Responsible for adding all printing characters from the input file to the + * open string on top of the stack. The only other characters that end up in + * that string are the quotes required for special characters. Reverse printing + * mode hasn't been tested but it should be close. hpos and lastx should disagree + * each time (except after startline() does something), and that should force a + * call to endstring() for every character. + * + */ + + if ( stringcount > 100 ) /* don't put too much on the stack */ + endline(); + + if ( vpos != lasty ) + endline(); + + if ( advance == -1 ) /* for reverse printing - move first */ + hmot(hmi); + + startline(); + + if ( lastc != ch || hpos != prevx ) { + if ( lastx != hpos ) + endstring(); + + if ( ch == '\\' || ch == '(' || ch == ')' ) + putc('\\', fp_out); + putc(ch, fp_out); + + lastc = ch; + prevx = hpos; + lastx += lasthmi; + } /* End if */ + + if ( advance != -1 ) + hmot(hmi); + + markedpage = TRUE; + +} /* End of oput */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postdaisy/README b/sys/src/cmd/postscript/postdaisy/README new file mode 100755 index 000000000..53c0485cc --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/README @@ -0,0 +1,4 @@ + +Diablo 630 to PostScript translator. Not terribly useful, and much has +been omitted. + diff --git a/sys/src/cmd/postscript/postdaisy/mkfile b/sys/src/cmd/postscript/postdaisy/mkfile new file mode 100755 index 000000000..e596ef0a6 --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/mkfile @@ -0,0 +1,62 @@ +BUILTINS= +</$objtype/mkfile +MAKE=mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/rc/bin/postscript/ +POSTLIB=$ROOT/sys/lib/postscript/prologues + +COMMONDIR=../common + +CC=pcc +LD=pcc + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B +LDFLAGS= + +all :V: $O.out + +install :V: $POSTBIN/$objtype/postdaisy $POSTLIB/postdaisy.ps $MAN1DIR/postdaisy.1 + +installall :V: + for(objtype in $CPUS) { \ + $MAKE 'MAKE=$MAKE' \ + 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \ + 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \ + 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \ + 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \ + 'ROUNDPAGE=$ROUNDPAGE' \ + 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \ + install \ + } + +clean :V: + rm -f *.$O + +clobber :V: clean + rm -f $O.out + +$POSTBIN/$objtype/postdaisy : $O.out + cp $prereq $target + +$POSTLIB/postdaisy.ps : postdaisy.ps + cp $prereq $target + +$MAN1DIR/postdaisy.1 : postdaisy.1 + cp $prereq $target + +$O.out : postdaisy.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/request.$O $COMMONDIR/getopt.$O + $LD $LDFLAGS $prereq + +%.$O: %.c + $CC $CFLAGS $stem.c + +postdaisy.$O : postdaisy.c postdaisy.h $COMMONDIR/comments.h $COMMONDIR/ext.h $COMMONDIR/gen.h $COMMONDIR/path.h + + +common :V: + cd $COMMONDIR; $MAKE diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.1 b/sys/src/cmd/postscript/postdaisy/postdaisy.1 new file mode 100755 index 000000000..a8716aa2e --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/postdaisy.1 @@ -0,0 +1,217 @@ +.ds dQ /usr/lib/postscript +.TH POSTDAISY 1 "DWB 3.2" +.SH NAME +.B postdaisy +\- PostScript translator for Diablo 630 files +.SH SYNOPSIS +\*(mBpostdaisy\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B postdaisy +translates Diablo 630 daisy-wheel +.I files +into PostScript and writes the results on the +standard output. +If no +.I files +are specified, or if +.OP \- +is one of the input +.IR files , +the standard input is read. +The following +.I options +are understood: +.TP 0.75i +.OP \-c num +Print +.I num +copies of each page. +By default only one copy is printed. +.TP +.OP \-f name +Print +.I files +using font +.IR name . +Any PostScript font can be used, +although the best results will only be +obtained with constant width fonts. +The default font is Courier. +.TP +.OP \-h num +Set the initial horizontal motion index to +.IR num . +Determines the character advance and the default +point size, unless the +.OP \-s +option is used. +The default is 12. +.TP +.OP \-m num +Magnify each logical page by the factor +.IR num . +Pages are scaled uniformly about the origin, +which is located near the upper left corner of +each page. +The default magnification is 1.0. +.TP +.OP \-n num +Print +.I num +logical pages on each piece of paper, +where +.I num +can be any positive integer. +By default +.I num +is set to 1. +.TP +.OP \-o list +Print pages whose numbers are given in the comma-separated +.IR list . +The list contains single numbers +.I N +and ranges +.IR N1\-\|N2 . +A missing +.I N1 +means the lowest numbered page, a missing +.I N2 +means the highest. +.TP +.OP \-p mode +Print +.I files +in either \*(mBportrait\fP or \*(mBlandscape\fP +.IR mode . +Only the first character of +.I mode +is significant. +The default +.I mode +is \*(mBportrait\fP. +.TP +.OP \-r num +Selects carriage return and line feed behavior. +If +.I num +is 1 a line feed generates a carriage return. +If +.I num +is 2 a carriage return generates a line feed. +Setting +.I num +to 3 enables both modes. +.TP +.OP \-s num +Use point size +.I num +instead of the default value set by the +initial horizontal motion index. +.TP +.OP \-v num +Set the initial vertical motion index to +.IR num . +The default is 8. +.TP +.OP \-x num +Translate the origin +.I num +inches along the positive x axis. +The default +coordinate system has the origin fixed near the +upper left corner of the page, with positive +x to the right and positive y down the page. +Positive +.I num +moves everything right. +The default offset is 0.25 inches. +.TP +.OP \-y num +Translate the origin +.I num +inches along the positive y axis. +Positive +.I num +moves text down the page. +The default offset is 0.25 inches. +.TP +.OP \-E name +Set the character encoding for text fonts to +.IR name . +Requesting +.I name +means include file +.MI \*(dQ/ name .enc \f1. +A nonexistent encoding file is silently ignored. +The default selects file +.MR \*(dQ/Default.enc . +.TP +.OP \-L file +Use +.I file +as the PostScript prologue. +.br +The default is +.MR \*(dQ/postdaisy.ps . +.PP +Three options allow insertion of arbitrary PostScript +at controlled points in the translation process: +.TP 0.75i +.OP \-C file +Copy +.I file +to the output file; +.I file +must contain legitimate PostScript. +.TP +.OP \-P string +Include +.I string +in output file; +.I string +must be legitimate PostScript. +.TP +.OP \-R action +Requests special +.I action +(e.g., +.MR manualfeed ) +on a per page or global basis. +The +.I action +string can be given as +.IR request , +.IM request : page\f1\|, +or +.IM request : page : file\f1\|. +If +.I page +is omitted or given as 0, the request +applies to all pages. +If +.I file +is omitted, the request +lookup is done in +.MR \*(dQ/ps.requests . +.SH DIAGNOSTICS +A 0 exit status is returned if +.I files +were successfully processed. +.SH FILES +.MW \*(dQ/postdaisy.ps +.br +.MW \*(dQ/forms.ps +.br +.MW \*(dQ/ps.requests +.SH SEE ALSO +.BR dpost (1), +.BR postdmd (1), +.BR postio (1), +.BR postmd (1), +.BR postprint (1), +.BR postreverse (1), +.BR posttek (1), +.BR psencoding (1) diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.c b/sys/src/cmd/postscript/postdaisy/postdaisy.c new file mode 100755 index 000000000..8588cf9af --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/postdaisy.c @@ -0,0 +1,1225 @@ +/* + * + * postdaisy - PostScript translator for Diablo 1640 files. + * + * A program that translates Diablo 1640 files into PostScript. Absolutely nothing + * is guaranteed. Quite a few things haven't been implemented, and what's been + * done isn't well tested. Most of the documentation used to write this program + * was taken from the 'Diablo Emulator' section of a recent Imagen manual. + * + * Some of document comments that are generated may not be right. Most of the test + * files I used produced a trailing blank page. I've put a check in formfeed() that + * won't print the last page if it doesn't contain any text, but PAGES comments may + * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or + * bold printing have been turned on by escape commands. + * + * The brute force approach used to implement horizontal and vertical tabs leaves + * much to be desired, and may not work for very small initial hmi and vmi values. + * At the very least I should have used malloc() to get space for the two tabstop + * arrays after hmi and vmi are known! + * + * Reverse printing mode hasn't been tested at all, but what's here should be + * close even though it's not efficient. + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how this program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects to + * find the current page number on the stack. + * + * t + * + * mark str1 x1 str2 x2 ... strn xn y hmi t mark + * + * Handles all the text on the stack. Characters in the strings are + * printed using hmi as the character advance, and all strings are at + * vertical position y. Each string is begins at the horizontal position + * that preceeds it. + * + * f + * + * font f - + * + * Use font f, where f is the full PostScript font name. Only used when + * we switch to auto underline (Courier-Italic) or bold (Courier-Bold) + * printing. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif +#include <sys/types.h> +#include <fcntl.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ +#include "postdaisy.h" /* a few special definitions */ + +char *optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI"; + +char *prologue = POSTDAISY; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +char htabstops[COLUMNS]; /* horizontal */ +char vtabstops[ROWS]; /* and vertical tabs */ + +int res = RES; /* input file resolution - sort of */ + +int hmi = HMI; /* horizontal motion index - 1/120 inch */ +int vmi = VMI; /* vertical motion index - 1/48 inch */ +int ohmi = HMI; /* original hmi */ +int ovmi = VMI; /* and vmi - for tabs and char size */ + +int hpos = 0; /* current horizontal */ +int vpos = 0; /* and vertical position */ + +int lastx = -1; /* printer's last horizontal */ +int lasty = -1; /* and vertical position */ +int lasthmi = -1; /* hmi for current text strings */ + +int lastc = -1; /* last printed character */ +int prevx = -1; /* at this position */ + +int leftmargin = LEFTMARGIN; /* page margins */ +int rightmargin = RIGHTMARGIN; +int topmargin = TOPMARGIN; +int bottommargin = BOTTOMMARGIN; + +int stringcount = 0; /* number of strings on the stack */ +int stringstart = 1; /* column where current one starts */ +int advance = 1; /* -1 if in backward print mode */ + +int lfiscr = OFF; /* line feed implies carriage return */ +int crislf = OFF; /* carriage return implies line feed */ + +int linespp = 0; /* lines per page if it's positive */ +int markedpage = FALSE; /* helps prevent trailing blank page */ +int page = 0; /* page we're working on */ +int printed = 0; /* printed this many pages */ + +Fontmap fontmap[] = FONTMAP; /* for translating font names */ +char *fontname = "Courier"; /* use this PostScript font */ +int shadowprint = OFF; /* automatic bold printing if ON */ + +FILE *fp_in; /* read from this file */ +FILE *fp_out = stdout; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that translates Diablo 1640 files into PostScript. Nothing + * is guaranteed - the program not well tested and doesn't implement everything. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* really just for error messages */ + + init_signals(); /* sets up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* handle the command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Makes sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + if ( DOROUND ) + cat(ROUNDPAGE); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + int n; /* for CR and LF modes */ + +/* + * + * Reads and processes the command line options. Added the -P option so arbitrary + * PostScript code can be passed through. Expect it could be useful for changing + * definitions in the prologue for which options have not been defined. + * + * Although any PostScript font can be used, things will only work for constant + * width fonts. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'f': /* use this PostScript font */ + fontname = get_font(optarg); + fprintf(stdout, "/font /%s def\n", fontname); + break; + + case 'h': /* default character spacing */ + ohmi = hmi = atoi(optarg) * HSCALE; + fprintf(stdout, "/hmi %s def\n", optarg); + break; + + case 'l': /* lines per page */ + linespp = atoi(optarg); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'r': /* set CR and LF modes */ + n = atoi(optarg); + if ( n & 01 ) + lfiscr = ON; + else lfiscr = OFF; + if ( n & 02 ) + crislf = ON; + else crislf = OFF; + break; + + case 's': /* point size */ + fprintf(stdout, "/pointsize %s def\n", optarg); + break; + + case 'v': /* default line spacing */ + ovmi = vmi = atoi(optarg) * VSCALE; + break; + + case 'x': /* shift things horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +char *get_font(name) + + char *name; /* name the user asked for */ + +{ + + int i; /* for looking through fontmap[] */ + +/* + * + * Called from options() to map a user's font name into a legal PostScript name. + * If the lookup fails *name is returned to the caller. That should let you choose + * any PostScript font, although things will only work well for constant width + * fonts. + * + */ + + for ( i = 0; fontmap[i].name != NULL; i++ ) + if ( strcmp(name, fontmap[i].name) == 0 ) + return(fontmap[i].val); + + return(name); + +} /* End of get_font */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + fp_in = stdin; + + if ( argc < 1 ) + text(); + else { /* at least one argument is left */ + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + text(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files, so mark the end of the pages, make sure the + * last page is printed, and restore the initial environment. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct provided it's not NULL. Accounting + * is requested using the -A or -J options. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +text() + +{ + + int ch; /* next input character */ + +/* + * + * Translates the next input file into PostScript. The redirect(-1) call forces + * the initial output to go to /dev/null - so the stuff formfeed() does at the + * end of each page doesn't go to stdout. + * + */ + + redirect(-1); /* get ready for the first page */ + formfeed(); /* force PAGE comment etc. */ + inittabs(); + + while ( (ch = getc(fp_in)) != EOF ) + switch ( ch ) { + case '\010': /* backspace */ + backspace(); + break; + + case '\011': /* horizontal tab */ + htab(); + break; + + case '\012': /* new line */ + linefeed(); + break; + + case '\013': /* vertical tab */ + vtab(); + break; + + case '\014': /* form feed */ + formfeed(); + break; + + case '\015': /* carriage return */ + carriage(); + break; + + case '\016': /* extended character set - SO */ + break; + + case '\017': /* extended character set - SI */ + break; + + case '\031': /* next char from supplementary set */ + break; + + case '\033': /* 2 or 3 byte escape sequence */ + escape(); + break; + + default: + oput(ch); + break; + } /* End switch */ + + formfeed(); /* next file starts on a new page? */ + +} /* End of text */ + +/*****************************************************************************/ + +inittabs() + +{ + + int i; /* loop index */ + +/* + * + * Initializes the horizontal and vertical tab arrays. The way tabs are handled is + * quite inefficient and may not work for all initial hmi or vmi values. + * + */ + + for ( i = 0; i < COLUMNS; i++ ) + htabstops[i] = ((i % 8) == 0) ? ON : OFF; + + for ( i = 0; i < ROWS; i++ ) + vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF; + +} /* End of inittabs */ + +/*****************************************************************************/ + +cleartabs() + +{ + + int i; /* loop index */ + +/* + * + * Clears all horizontal and vertical tab stops. + * + */ + + for ( i = 0; i < ROWS; i++ ) + htabstops[i] = OFF; + + for ( i = 0; i < COLUMNS; i++ ) + vtabstops[i] = OFF; + +} /* End of cleartabs */ + +/*****************************************************************************/ + +formfeed() + +{ + +/* + * + * Called whenever we've finished with the last page and want to get ready for the + * next one. Also used at the beginning and end of each input file, so we have to + * be careful about what's done. I've added a simple test before the showpage that + * should eliminate the extra blank page that was put out at the end of many jobs, + * but the PAGES comments may be wrong. + * + */ + + if ( fp_out == stdout ) /* count the last page */ + printed++; + + endline(); /* print the last line */ + + fprintf(fp_out, "cleartomark\n"); + if ( feof(fp_in) == 0 || markedpage == TRUE ) + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + + if ( ungetc(getc(fp_in), fp_in) == EOF ) + redirect(-1); + else redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d pagesetup\n", printed+1); + + vgoto(topmargin); + hgoto(leftmargin); + + markedpage = FALSE; + +} /* End of formfeed */ + +/*****************************************************************************/ + +linefeed() + +{ + + int line = 0; /* current line - based on ovmi */ + +/* + * + * Adjust our current vertical position. If we've passed the bottom of the page + * or exceeded the number of lines per page, print it and go to the upper left + * corner of the next page. This routine is also called from carriage() if crislf + * is ON. + * + */ + + vmot(vmi); + + if ( lfiscr == ON ) + hgoto(leftmargin); + + if ( linespp > 0 ) /* means something so see where we are */ + line = vpos / ovmi + 1; + + if ( vpos > bottommargin || line > linespp ) + formfeed(); + +} /* End of linefeed */ + +/*****************************************************************************/ + +carriage() + +{ + +/* + * + * Handles carriage return character. If crislf is ON we'll generate a line feed + * every time we get a carriage return character. + * + */ + + if ( shadowprint == ON ) /* back to normal mode */ + changefont(fontname); + + advance = 1; + shadowprint = OFF; + + hgoto(leftmargin); + + if ( crislf == ON ) + linefeed(); + +} /* End of carriage */ + +/*****************************************************************************/ + +htab() + +{ + + int col; /* 'column' we'll be at next */ + int i; /* loop index */ + +/* + * + * Tries to figure out where the next tab stop is. Wasn't positive about this + * one, since hmi can change. I'll assume columns are determined by the original + * value of hmi. That fixes them on the page, which seems to make more sense than + * letting them float all over the place. + * + */ + + endline(); + + col = hpos/ohmi + 1; + for ( i = col; i < ROWS; i++ ) + if ( htabstops[i] == ON ) { + col = i; + break; + } /* End if */ + + hgoto(col * ohmi); + lastx = hpos; + +} /* End of htab */ + +/*****************************************************************************/ + +vtab() + +{ + + int line; /* line we'll be at next */ + int i; /* loop index */ + +/* + * + * Looks for the next vertical tab stop in the vtabstops[] array and moves to that + * line. If we don't find a tab we'll just move down one line - shouldn't happen. + * + */ + + endline(); + + line = vpos/ovmi + 1; + for ( i = line; i < COLUMNS; i++ ) + if ( vtabstops[i] == ON ) { + line = i; + break; + } /* End if */ + + vgoto(line * ovmi); + +} /* End of vtab */ + +/*****************************************************************************/ + +backspace() + +{ + +/* + * + * Moves backwards a distance equal to the current value of hmi, but don't go + * past the left margin. + * + */ + + endline(); + + if ( hpos - leftmargin >= hmi ) + hmot(-hmi); + else hgoto(leftmargin); /* maybe just ignore the backspace?? */ + + lastx = hpos; + +} /* End of backspace */ + +/*****************************************************************************/ + +escape() + +{ + + int ch; /* control character */ + +/* + * + * Handles special codes that are expected to follow an escape character. The + * initial escape character is followed by one or two bytes. + * + */ + + switch ( ch = getc(fp_in) ) { + case 'T': /* top margin */ + topmargin = vpos; + break; + + case 'L': /* bottom margin */ + bottommargin = vpos; + break; + + case 'C': /* clear top and bottom margins */ + bottommargin = BOTTOMMARGIN; + topmargin = TOPMARGIN; + break; + + case '9': /* left margin */ + leftmargin = hpos; + break; + + case '0': /* right margin */ + rightmargin = hpos; + break; + + case '1': /* set horizontal tab */ + htabstops[hpos/ohmi] = ON; + break; + + case '8': /* clear horizontal tab at hpos */ + htabstops[hpos/ohmi] = OFF; + break; + + case '-': /* set vertical tab */ + vtabstops[vpos/ovmi] = ON; + break; + + case '2': /* clear all tabs */ + cleartabs(); + break; + + case '\014': /* set lines per page */ + linespp = getc(fp_in); + break; + + case '\037': /* set hmi to next byte minus 1 */ + hmi = HSCALE * (getc(fp_in) - 1); + break; + + case 'S': /* reset hmi to default */ + hmi = ohmi; + break; + + case '\011': /* move to column given by next byte */ + hgoto((getc(fp_in)-1) * ohmi); + break; + + case '?': /* do carriage return after line feed */ + lfiscr = ON; + break; + + case '!': /* don't generate carriage return */ + lfiscr = OFF; + break; + + case '5': /* forward print mode */ + advance = 1; + break; + + case '6': /* backward print mode */ + advance = -1; + break; + + case '\036': /* set vmi to next byte minus 1 */ + vmi = VSCALE * (getc(fp_in) - 1); + break; + + case '\013': /* move to line given by next byte */ + vgoto((getc(fp_in)-1) * ovmi); + break; + + case 'U': /* positive half line feed */ + vmot(vmi/2); + break; + + case 'D': /* negative half line feed */ + vmot(-vmi/2); + break; + + case '\012': /* negative line feed */ + vmot(-vmi); + break; + + case '\015': /* clear all margins */ + bottommargin = BOTTOMMARGIN; + topmargin = TOPMARGIN; + leftmargin = BOTTOMMARGIN; + rightmargin = RIGHTMARGIN; + break; + + case 'E': /* auto underscore - use italic font */ + changefont("/Courier-Oblique"); + break; + + case 'R': /* disable auto underscore */ + changefont(fontname); + break; + + case 'O': /* bold/shadow printing */ + case 'W': + changefont("/Courier-Bold"); + shadowprint = ON; + break; + + case '&': /* disable bold printing */ + changefont(fontname); + shadowprint = OFF; + break; + + case '/': /* ignored 2 byte escapes */ + case '\\': + case '<': + case '>': + case '%': + case '=': + case '.': + case '4': + case 'A': + case 'B': + case 'M': + case 'N': + case 'P': + case 'Q': + case 'X': + case '\010': + break; + + case ',': /* ignored 3 byte escapes */ + case '\016': + case '\021': + getc(fp_in); + break; + + case '3': /* graphics mode - should quit! */ + case '7': + case 'G': + case 'V': + case 'Y': + case 'Z': + error(FATAL, "graphics mode is not implemented"); + break; + + default: + error(FATAL, "missing case for escape o%o\n", ch); + break; + } /* End switch */ + +} /* End of escape */ + +/*****************************************************************************/ + +vmot(n) + + int n; /* move this far vertically */ + +{ + +/* + * + * Move vertically n units from where we are. + * + */ + + vpos += n; + +} /* End of vmot */ + +/*****************************************************************************/ + +vgoto(n) + + int n; /* new vertical position */ + +{ + +/* + * + * Moves to absolute vertical position n. + * + */ + + vpos = n; + +} /* End of vgoto */ + +/*****************************************************************************/ + +hmot(n) + + int n; /* move this horizontally */ + +{ + +/* + * + * Moves horizontally n units from our current position. + * + */ + + hpos += n * advance; + + if ( hpos < leftmargin ) + hpos = leftmargin; + +} /* End of hmot */ + +/*****************************************************************************/ + +hgoto(n) + + int n; /* go to this horizontal position */ + +{ + +/* + * + * Moves to absolute horizontal position n. + * + */ + + hpos = n; + +} /* End of hgoto */ + +/*****************************************************************************/ + +changefont(name) + + char *name; + +{ + +/* + * + * Changes the current font. Used to get in and out of auto underscore and bold + * printing. + * + */ + + endline(); + fprintf(fp_out, "%s f\n", name); + +} /* End of changefont */ + +/*****************************************************************************/ + +startline() + +{ + +/* + * + * Called whenever we want to be certain we're ready to start pushing characters + * into an open string on the stack. If stringcount is positive we've already + * started, so there's nothing to do. The first string starts in column 1. + * + */ + + if ( stringcount < 1 ) { + putc('(', fp_out); + stringstart = lastx = hpos; + lasty = vpos; + lasthmi = hmi; + lastc = -1; + prevx = -1; + stringcount = 1; + } /* End if */ + +} /* End of startline */ + +/*****************************************************************************/ + +endline() + +{ + +/* + * + * Generates a call to the PostScript procedure that processes the text on the + * the stack - provided stringcount is positive. + * + */ + + if ( stringcount > 0 ) + fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi); + + stringcount = 0; + +} /* End of endline */ + +/*****************************************************************************/ + +endstring() + +{ + +/* + * + * Takes the string we've been working on and adds it to the output file. Called + * when we need to adjust our horizontal position before starting a new string. + * Also called from endline() when we're done with the current line. + * + */ + + if ( stringcount > 0 ) { + fprintf(fp_out, ")%d(", stringstart); + lastx = stringstart = hpos; + stringcount++; + } /* End if */ + +} /* End of endstring */ + +/*****************************************************************************/ + +oput(ch) + + int ch; /* next output character */ + +{ + +/* + * + * Responsible for adding all printing characters from the input file to the + * open string on top of the stack. The only other characters that end up in + * that string are the quotes required for special characters. Reverse printing + * mode hasn't been tested but it should be close. hpos and lastx should disagree + * each time (except after startline() does something), and that should force a + * call to endstring() for every character. + * + */ + + if ( stringcount > 100 ) /* don't put too much on the stack */ + endline(); + + if ( vpos != lasty ) + endline(); + + if ( advance == -1 ) /* for reverse printing - move first */ + hmot(hmi); + + startline(); + + if ( lastc != ch || hpos != prevx ) { + if ( lastx != hpos ) + endstring(); + + if ( isascii(ch) && isprint(ch) ) { + if ( ch == '\\' || ch == '(' || ch == ')' ) + putc('\\', fp_out); + putc(ch, fp_out); + } else fprintf(fp_out, "\\%.3o", ch & 0377); + + lastc = ch; + prevx = hpos; + lastx += lasthmi; + } /* End if */ + + if ( advance != -1 ) + hmot(hmi); + + markedpage = TRUE; + +} /* End of oput */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.h b/sys/src/cmd/postscript/postdaisy/postdaisy.h new file mode 100755 index 000000000..e8eef0c16 --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/postdaisy.h @@ -0,0 +1,88 @@ +/* + * + * Definitions used by the PostScript translator for Diablo 1640 files. + * + * Diablo printers have horizontal and vertical resolutions of 120 and 48 dpi. + * We'll use a single resolution of 240 dpi and let the program scale horizontal + * and vertical positions by HSCALE and VSCALE. + * + */ + +#define RES 240 +#define HSCALE 2 +#define VSCALE 5 + +/* + * + * HMI is the default character spacing and VMI is the line spacing. Both values + * are in terms of the 240 dpi resolution. + * + */ + +#define HMI (12 * HSCALE) +#define VMI (8 * VSCALE) + +/* + * + * Paper dimensions don't seem to be all that important. They're just used to + * set the right and bottom margins. Both are given in terms of the 240 dpi + * resolution. + * + */ + +#define LEFTMARGIN 0 +#define RIGHTMARGIN 3168 +#define TOPMARGIN 0 +#define BOTTOMMARGIN 2640 + +/* + * + * ROWS and COLUMNS set the dimensions of the horizontal and vertical tab arrays. + * The way I've implemented both kinds of tabs leaves something to be desired, but + * it was simple and should be good enough for now. If arrays are going to be used + * to mark tab stops I probably should use malloc() to get enough space once the + * initial hmi and vmi are know. + * + */ + +#define ROWS 400 +#define COLUMNS 200 + +/* + * + * An array of type Fontmap helps convert font names requested by users into + * legitimate PostScript names. The array is initialized using FONTMAP, which must + * end with an entry that has NULL defined as its name field. + * + */ + +typedef struct { + char *name; /* user's font name */ + char *val; /* corresponding PostScript name */ +} Fontmap; + +#define FONTMAP \ + \ + { \ + "R", "Courier", \ + "I", "Courier-Oblique", \ + "B", "Courier-Bold", \ + "CO", "Courier", \ + "CI", "Courier-Oblique", \ + "CB", "Courier-Bold", \ + "CW", "Courier", \ + "PO", "Courier", \ + "courier", "Courier", \ + "cour", "Courier", \ + "co", "Courier", \ + NULL, NULL \ + } + +/* + * + * Some of the non-integer functions in postdaisy.c. + * + */ + +char *get_font(); + diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.mk b/sys/src/cmd/postscript/postdaisy/postdaisy.mk new file mode 100755 index 000000000..a771ccd6e --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/postdaisy.mk @@ -0,0 +1,93 @@ +MAKE=/bin/make +MAKEFILE=postdaisy.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +HFILES=postdaisy.h \ + $(COMMONDIR)/comments.h\ + $(COMMONDIR)/ext.h\ + $(COMMONDIR)/gen.h\ + $(COMMONDIR)/path.h + +OFILES=postdaisy.o\ + $(COMMONDIR)/glob.o\ + $(COMMONDIR)/misc.o\ + $(COMMONDIR)/request.o + +all : postdaisy + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + @if [ ! -d "$(POSTLIB)" ]; then \ + mkdir $(POSTLIB); \ + chmod 755 $(POSTLIB); \ + chgrp $(GROUP) $(POSTLIB); \ + chown $(OWNER) $(POSTLIB); \ + fi + cp postdaisy $(POSTBIN)/postdaisy + @chmod 755 $(POSTBIN)/postdaisy + @chgrp $(GROUP) $(POSTBIN)/postdaisy + @chown $(OWNER) $(POSTBIN)/postdaisy + cp postdaisy.ps $(POSTLIB)/postdaisy.ps + @chmod 644 $(POSTLIB)/postdaisy.ps + @chgrp $(GROUP) $(POSTLIB)/postdaisy.ps + @chown $(OWNER) $(POSTLIB)/postdaisy.ps + cp postdaisy.1 $(MAN1DIR)/postdaisy.1 + @chmod 644 $(MAN1DIR)/postdaisy.1 + @chgrp $(GROUP) $(MAN1DIR)/postdaisy.1 + @chown $(OWNER) $(MAN1DIR)/postdaisy.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postdaisy + +postdaisy : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postdaisy $(OFILES) + +postdaisy.o : $(HFILES) + +$(COMMONDIR)/glob.o\ +$(COMMONDIR)/misc.o\ +$(COMMONDIR)/request.o : + @cd $(COMMONDIR); $(MAKE) -f common.mk `basename $@` + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + postdaisy.1 >XXX.1; \ + mv XXX.1 postdaisy.1 + diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.ps b/sys/src/cmd/postscript/postdaisy/postdaisy.ps new file mode 100755 index 000000000..eda3a9d35 --- /dev/null +++ b/sys/src/cmd/postscript/postdaisy/postdaisy.ps @@ -0,0 +1,74 @@ +% +% Version 3.3.2 prologue for Diablo 1640 files. +% + +/#copies 1 store +/aspectratio 1 def +/font /Courier def +/formsperpage 1 def +/hmi 12 def +/landscape false def +/magnification 1 def +/margin 10 def +/orientation 0 def +/resolution 240 def +/rotation 1 def +/xoffset .25 def +/yoffset .25 def + +/roundpage true def +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/ashow {ashow} bind def % so later references don't bind +/stringwidth {stringwidth} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + /scaling 72 resolution div def + currentdict /pointsize known not {/pointsize hmi def} if + font findfont pointsize scaling div scalefont setfont + /charwidth (M) stringwidth pop def + + pagedimensions + xcenter ycenter translate + orientation rotation mul rotate + width 2 div neg height 2 div translate + xoffset inch yoffset inch neg translate + margin 2 div dup neg translate + magnification dup aspectratio mul scale + height width div 1 min dup scale + scaling dup scale +} def + +/pagedimensions { + useclippath userdict /gotpagebbox known not and { + /pagebbox [clippath pathbbox newpath] def + roundpage currentdict /roundpagebbox known and {roundpagebbox} if + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def 0 0 moveto} bind def + +/t { + charwidth sub /advance exch def + neg /y exch def + counttomark 2 idiv {y moveto advance 0 3 -1 roll ashow} repeat +} bind def + +/f {findfont pointsize scaling div scalefont setfont} bind def + +/done {/lastpage where {pop lastpage} if} def diff --git a/sys/src/cmd/postscript/postdmd/README b/sys/src/cmd/postscript/postdmd/README new file mode 100755 index 000000000..0a8b4fcc0 --- /dev/null +++ b/sys/src/cmd/postscript/postdmd/README @@ -0,0 +1,22 @@ + +DMD bitmap to PostScript translator. Much of the code came from abm, +which was written by Guy Riddle. + +By default 6 byte patterns are used to encode the output bitmap. Use +the -b option to change the pattern size. Bitmaps are unpacked one +scanline at a time and re-encoded in a format that looks like, + + bytes patterns count + +where bytes and count are decimal integers and patterns is a series +of hex digits. Bytes is the number of bytes represented by the hex +pattern, and count is the number of additional times the pattern +should be repeated. For example, + + 2 FFFF 4 + 5 FFFFFFFFFF 1 + 10 FFFFFFFFFFFFFFFFFFFF 0 + +all represent 10 consecutive bytes of ones. Scanlines are terminated +by a 0 on a line by itself. + diff --git a/sys/src/cmd/postscript/postdmd/mkfile b/sys/src/cmd/postscript/postdmd/mkfile new file mode 100755 index 000000000..1ccfb2562 --- /dev/null +++ b/sys/src/cmd/postscript/postdmd/mkfile @@ -0,0 +1,61 @@ +BUILTINS= +</$objtype/mkfile +MAKE=mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/sys/lib/postscript/bin +POSTLIB=$ROOT/sys/lib/postscript/prologues + +COMMONDIR=../common + +CC=pcc +LD=pcc + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B +LDFLAGS= + +all :V: $O.out + +install :V: $POSTBIN/$objtype/postdmd $POSTLIB/postdmd.ps $MAN1DIR/postdmd.1 + +installall :V: + for(objtype in $CPUS) { \ + $MAKE 'MAKE=$MAKE' \ + 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \ + 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \ + 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \ + 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \ + 'ROUNDPAGE=$ROUNDPAGE' \ + 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \ + install \ + } + +clean :V: + rm -f *.$O + +clobber :V: clean + rm -f $O.out + +$POSTBIN/$objtype/postdmd : $O.out + cp $prereq $target + +$POSTLIB/postdmd.ps : postdmd.ps + cp $prereq $target + +$MAN1DIR/postdmd.1 : postdmd.1 + cp $prereq $target + +$O.out : postdmd.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/request.$O $COMMONDIR/getopt.$O + $LD $LDFLAGS $prereq + +postdmd.$O : postdmd.c $COMMONDIR/comments.h $COMMONDIR/ext.h $COMMONDIR/gen.h $COMMONDIR/path.h + +%.$O: %.c + $CC $CFLAGS $stem.c + +common :V: + cd $COMMONDIR; $MAKE diff --git a/sys/src/cmd/postscript/postdmd/postdmd.1 b/sys/src/cmd/postscript/postdmd/postdmd.1 new file mode 100755 index 000000000..cb3317b14 --- /dev/null +++ b/sys/src/cmd/postscript/postdmd/postdmd.1 @@ -0,0 +1,206 @@ +.ds dQ /usr/lib/postscript +.TH POSTDMD 1 +.SH NAME +.B postdmd +\- PostScript translator for +.SM DMD +bitmap files +.SH SYNOPSIS +\*(mBpostdmd\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B postdmd +translates +.SM DMD +bitmap +.IR files , +as produced by +.BR dmdps , +or +.I files +written in the Ninth Edition +.BR bitfile (9.5) +format +into PostScript and writes the results on the +standard output. +If no +.I files +are specified, or if +.OP \- +is one of the input +.IR files , +the standard input is read. +The following +.I options +are understood: +.TP 0.75i +.OP \-b num +Pack the bitmap in the output file using +.I num +byte patterns. +A value of 0 turns off all packing of the output file. +By default +.I num +is 6. +.TP +.OP \-c num +Print +.I num +copies of each page. +By default only one copy is printed. +.TP +.OP \-f +Flip the sense of the bits in +.I files +before printing the bitmaps. +.TP +.OP \-m num +Magnify each logical page by the factor +.IR num . +Pages are scaled uniformly about the origin, +which by default is located at the center of +each page. +The default magnification is 1.0. +.TP +.OP \-n num +Print +.I num +logical pages on each piece of paper, +where +.I num +can be any positive integer. +By default +.I num +is set to 1. +.TP +.OP \-o list +Print pages whose numbers are given in the comma-separated +.IR list . +The list contains single numbers +.I N +and ranges +.IR N1\-\|N2 . +A missing +.I N1 +means the lowest numbered page, a missing +.I N2 +means the highest. +.TP +.OP \-p mode +Print +.I files +in either \*(mBportrait\fP or \*(mBlandscape\fP +.IR mode . +Only the first character of +.I mode +is significant. +The default +.I mode +is \*(mBportrait\fP. +.TP +.OP \-u +Disables much of the unpacking for Eighth +Edition bitmap files. +Usually results in smaller output files that take longer to print. +Not a recommended option. +.TP +.OP \-x num +Translate the origin +.I num +inches along the positive x axis. +The default +coordinate system has the origin fixed at the +center of the page, with positive +x to the right and positive y up the page. +Positive +.I num +moves everything right. +The default offset is 0 inches. +.TP +.OP \-y num +Translate the origin +.I num +inches along the positive y axis. +Positive +.I num +moves everything up the page. +The default offset is 0. +.TP +.TP +.OP \-L file +Use +.I file +as the PostScript prologue. +.br +The default is +.MR \*(dQ/postdmd.ps . +.PP +Three options allow insertion of arbitrary PostScript +at controlled points in the translation process: +.TP 0.75i +.OP \-C file +Copy +.I file +to the output file; +.I file +must contain legitimate PostScript. +.TP +.OP \-P string +Include +.I string +in the output file; +.I string +must be legitimate PostScript. +.TP +.OP \-R action +Requests special +.I action +(e.g., +.MR manualfeed ) +on a per page or global basis. +The +.I action +string can be given as +.IR request, +.IM request : page\f1\|, +or +.IM request : page : file\f1\|. +If +.I page +is omitted or given as 0, the request applies to all pages. +If +.I file +is omitted, the request lookup is done in +.MR \*(dQ/ps.requests . +.PP +Only one bitmap is printed on each logical page, and each of the input +.I files +must contain complete descriptions of at least one bitmap. +Decreasing the pattern size using the +.OP \-b +option may help throughput on printers with fast processors +(e.g., \s-1PS\s+1-810), +while increasing the pattern size will often be the right move +on older models +(.e.g, \s-1PS\s+1-800). +.SH DIAGNOSTICS +A 0 exit status is returned if +.I files +were successfully processed. +.br +.ne 4v +.SH FILES +.MW \*(dQ/postdmd.ps +.br +.MW \*(dQ/forms.ps +.br +.MW \*(dQ/ps.requests +.SH SEE ALSO +.BR dpost (1), +.BR postdaisy (1), +.BR postio (1), +.BR postmd (1), +.BR postprint (1), +.BR postreverse (1), +.BR posttek (1) diff --git a/sys/src/cmd/postscript/postdmd/postdmd.c b/sys/src/cmd/postscript/postdmd/postdmd.c new file mode 100755 index 000000000..27cdfe0dd --- /dev/null +++ b/sys/src/cmd/postscript/postdmd/postdmd.c @@ -0,0 +1,729 @@ +/* + * + * postdmd - PostScript translator for DMD bitmap files. + * + * A simple program that can be used to print DMD bitmaps on PostScript printers. + * Much of the code was borrowed from abm, which was written by Guy Riddle. + * + * Although the program supports two different input bitmap formats, by far the + * most important is the Eighth (and Ninth) Edition bitfile format. A bitmap in + * the bitfile format begins with a 10 byte header with the first two bytes set to + * zero. The next 8 bytes set the x and y coordinates of the bitmap's origin and + * corner (ie. the upper left and lower right corners). The compressed raster data + * follows the header and consists of control bytes followed an appropriate number + * of data bytes. Control bytes (ie. n) less than 127 means read the next 2*n bytes + * of raster data directly from the input file, while if n is larger than 128 we + * read two bytes from the input file and replicate the bytes n-128 times. After + * each scan line is recovered it's exclusive-or'd with the preceeding line to + * generate the real raster data. + * + * After each raster line is recovered postdmd encodes it in a slightly different + * format that's designed to be unpacked by a PostScript procedure that's defined + * in the prologue. By default no exclusive-or'ing is done and packing of pattern + * data can be based on any number of bytes rather than just the next two bytes. + * By default 6 byte patterns are used, but any number can be selected with the -b + * option. A non-positive argument (eg. -b0) disables all pattern encoding. Larger + * patterns increase the size of the output file, but reduce the work load that's + * forced on the PostScript interpreter. The default choices I've made (ie. 6 byte + * patterns and no exclusive-or'ing) do a decent balancing job across currently + * available PostScript printers. Larger patterns (eg. -b16) increase the output + * file size, but may be appropriate if you're running at a high baud rate (eg. + * 19.2KB), while smaller patter size (eg. -b4) may help if you've got a printer + * with a fast processor (eg. a PS-810). + * + * The encoding produced by the program (and decoded on the printer) looks like, + * + * bytes patterns count + * + * where bytes and count are decimal integers and patterns is a hex string. Bytes + * is the number of bytes represented by the hex patterns and count is the number + * of additional times the patterns should be repeated. For example, + * + * 2 FFFF 4 + * 5 FFFFFFFFFF 1 + * 10 FFFFFFFFFFFFFFFFFFFF 0 + * + * all represent 10 consecutive bytes of ones. Scanlines are terminated by a 0 on + * a line by itself. + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how this program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects + * to find the current page number on the stack. + * + * bitmap + * + * v8format flip scanlength scanlines bitmap - + * + * Prints the bitmap that's read from standard input. The bitmap consists + * of scanlines lines, each of which includes scanlength pixels. If + * v8format is true the picture is assumed to be an Eighth Edition bitmap, + * and the exclusive-or'ing will be done on the printer. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif +#include <sys/types.h> +#include <fcntl.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ + +char *optnames = "a:b:c:fm:n:o:p:ux:y:A:C:E:J:L:P:DI"; + +char *prologue = POSTDMD; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int bbox[2] = {0, 0}; /* upper right coordinates only */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +int bytespp = 6; /* bytes per pattern - on output */ +int flip = FALSE; /* ones complement the bitmap */ +int v8undo = TRUE; /* xor'ing done on host if TRUE */ +int v8format = FALSE; /* for Eighth Edition bitmaps */ + +int page = 0; /* last page we worked on */ +int printed = 0; /* and the number of pages printed */ + +int patterns; /* 16 bit patterns per scan line */ +int scanlines; /* lines in the bitmap */ +int patcount = 0; /* should be patterns * scanlines */ + +char *raster = NULL; /* next raster line */ +char *prevrast = NULL; /* and the previous one - v8format */ +char *rptr; /* next free byte in raster */ +char *eptr; /* one past the last byte in raster */ + +FILE *fp_in = NULL; /* read from this file */ +FILE *fp_out = stdout; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that translates DMD bitmap files into PostScript. There can + * be more than one bitmap per file, but none can be split across input files. + * Each bitmap goes on a page by itself. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* really just for error messages */ + + init_signals(); /* sets up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* handle the command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Make sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + +/* + * + * Reads and processes the command line options. Added the -P option so arbitrary + * PostScript code can be passed through. Expect it could be useful for changing + * definitions in the prologue for which options have not been defined. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'b': /* bytes per pattern */ + bytespp = atoi(optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'f': /* ones complement - sort of */ + flip = TRUE; + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'u': /* don't undo Eighth Edition bitmaps */ + v8undo = FALSE; + break; + + case 'x': /* shift things horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding - unnecessary */ + fontencoding = optarg; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); /* unnecessary */ + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { /* followed by stuff for multiple pages */ + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + + FILE *fp; /* next input file */ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + if ( argc < 1 ) + bitmap(stdin); + else { /* at least one argument is left */ + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp = stdin; + else if ( (fp = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + bitmap(fp); + if ( fp != stdin ) + fclose(fp); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files, so mark the end of the pages with a TRAILER + * comment, make sure the last page prints, and add things like the PAGES comment + * that can only be determined after all the input files have been read. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s 0 0 %d %d\n", BOUNDINGBOX, (bbox[0]*72+100)/100, (bbox[1]*72+100)/100); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is + * requested using the -A or -J options. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +bitmap(fp) + + FILE *fp; /* next input file */ + +{ + + int count; /* pattern repeats this many times */ + long total; /* expect this many patterns */ + +/* + * + * Reads all the bitmaps from the next input file, translates each one into + * PostScript, and arranges to have one bitmap printed on each page. Multiple + * bitmaps per input file work. + * + */ + + fp_in = fp; /* everyone reads from this file */ + + while ( dimensions() == TRUE ) { + patcount = 0; + total = scanlines * patterns; + + bbox[0] = MAX(bbox[0], patterns*16); /* for BoundingBox comment */ + bbox[1] = MAX(bbox[1], scanlines); + + redirect(++page); + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + writerequest(printed+1, fp_out); + + fprintf(fp_out, "%s ", (v8format == TRUE && v8undo == FALSE) ? "true" : "false"); + fprintf(fp_out, "%s ", (flip == TRUE) ? "true" : "false"); + fprintf(fp_out, "%d %d bitmap\n", patterns * 16, scanlines); + + while ( patcount != total && (count = getc(fp)) != EOF ) { + addrast(count); + patcount += (count & 0177); + if ( patcount % patterns == 0 ) + putrast(); + } /* End while */ + + if ( debug == ON ) + fprintf(stderr, "patterns = %d, scanlines = %d, patcount = %d\n", patterns, scanlines, patcount); + + if ( total != patcount ) + error(FATAL, "bitmap format error"); + + if ( fp_out == stdout ) printed++; + + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + } /* End while */ + +} /* End of bitmap */ + +/*****************************************************************************/ + +dimensions() + +{ + + int ox, oy; /* coordinates of the origin */ + int cx, cy; /* and right corner of the bitmap */ + int i; /* loop index */ + +/* + * + * Determines the dimensions and type of the next bitmap. Eighth edition bitmaps + * have a zero in the first 16 bits. If valid dimensions are read TRUE is returned + * to the caller. Changed so the check of whether we're done (by testing scanlines + * or patterns) comes before the malloc(). + * + */ + + if ( (scanlines = getint()) == 0 ) { + ox = getint(); + oy = getint(); + cx = getint(); + cy = getint(); + scanlines = cy - oy; + patterns = (cx - ox + 15) / 16; + v8format = TRUE; + } else patterns = getint(); + + if ( scanlines <= 0 || patterns <= 0 ) /* done - don't do the malloc() */ + return(FALSE); + + if ( raster != NULL ) free(raster); + if ( prevrast != NULL ) free(prevrast); + + if ( (rptr = raster = (char *) malloc(patterns * 2)) == NULL ) + error(FATAL, "no memory"); + + if ( (prevrast = (char *) malloc(patterns * 2)) == NULL ) + error(FATAL, "no memory"); + + for ( i = 0; i < patterns * 2; i++ ) + *(prevrast+i) = 0377; + + eptr = rptr + patterns * 2; + + return(TRUE); + +} /* End of dimensions */ + +/*****************************************************************************/ + +addrast(count) + + int count; /* repeat count for next pattern */ + +{ + + int size; /* number of bytes in next pattern */ + int l, h; /* high and low bytes */ + int i, j; /* loop indices */ + +/* + * + * Reads the input file and adds the appropriate number of bytes to the output + * raster line. If count has bit 7 on, one 16 bit pattern is read and repeated + * count & 0177 times. If bit 7 is off, count is the number of patterns read from + * fp_in - each one repeated once. + * + */ + + if ( count & 0200 ) { + size = 1; + count &= 0177; + } else { + size = count; + count = 1; + } /* End else */ + + for ( i = size; i > 0; i-- ) { + if ( (l = getc(fp_in)) == EOF || (h = getc(fp_in)) == EOF ) + return; + for ( j = count; j > 0; j-- ) { + *rptr++ = l; + *rptr++ = h; + } /* End for */ + } /* End for */ + +} /* End of addrast */ + +/*****************************************************************************/ + +putrast() + +{ + + char *p1, *p2; /* starting and ending patterns */ + int n; /* set to bytes per pattern */ + int i; /* loop index */ + +/* + * + * Takes the scanline that's been saved in *raster, encodes it according to the + * value that's been assigned to bytespp, and writes the result to *fp_out. Each + * line in the output bitmap is terminated by a 0 on a line by itself. + * + */ + + n = (bytespp <= 0) ? 2 * patterns : bytespp; + + if ( v8format == TRUE && v8undo == TRUE ) + for ( i = 0; i < patterns * 2; i++ ) + *(raster+i) = (*(prevrast+i) ^= *(raster+i)); + + for ( p1 = raster, p2 = raster + n; p1 < eptr; p1 = p2 ) + if ( patncmp(p1, n) == TRUE ) { + while ( patncmp(p2, n) == TRUE ) p2 += n; + p2 += n; + fprintf(fp_out, "%d ", n); + for ( i = 0; i < n; i++, p1++ ) + fprintf(fp_out, "%.2X", ((int) *p1) & 0377); + fprintf(fp_out, " %d\n", (p2 - p1) / n); + } else { + while ( p2 < eptr && patncmp(p2, n) == FALSE ) p2 += n; + if ( p2 > eptr ) p2 = eptr; + fprintf(fp_out, "%d ", p2 - p1); + while ( p1 < p2 ) + fprintf(fp_out, "%.2X", ((int) *p1++) & 0377); + fprintf(fp_out, " 0\n"); + } /* End else */ + + fprintf(fp_out, "0\n"); + + rptr = raster; + +} /* End of putrast */ + +/*****************************************************************************/ + +patncmp(p1, n) + + char *p1; /* first patterns starts here */ + int n; /* and extends this many bytes */ + +{ + + char *p2; /* address of the second pattern */ + +/* + * + * Compares the two n byte patterns *p1 and *(p1+n). FALSE is returned if they're + * different or extend past the end of the current raster line. + * + */ + + p2 = p1 + n; + + for ( ; n > 0; n--, p1++, p2++ ) + if ( p2 >= eptr || *p1 != *p2 ) + return(FALSE); + + return(TRUE); + +} /* End of patncmp */ + +/*****************************************************************************/ + +getint() + +{ + + int h, l; /* high and low bytes */ + +/* + * + * Reads the next two bytes from *fp_in and returns the resulting integer. + * + */ + + if ( (l = getc(fp_in)) == EOF || (h = getc(fp_in)) == EOF ) + return(-1); + + return((h & 0377) << 8 | (l & 0377)); + +} /* End of getint */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postdmd/postdmd.mk b/sys/src/cmd/postscript/postdmd/postdmd.mk new file mode 100755 index 000000000..d60ba84b8 --- /dev/null +++ b/sys/src/cmd/postscript/postdmd/postdmd.mk @@ -0,0 +1,92 @@ +MAKE=/bin/make +MAKEFILE=postdmd.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +HFILES=$(COMMONDIR)/comments.h\ + $(COMMONDIR)/ext.h\ + $(COMMONDIR)/gen.h\ + $(COMMONDIR)/path.h + +OFILES=postdmd.o\ + $(COMMONDIR)/glob.o\ + $(COMMONDIR)/misc.o\ + $(COMMONDIR)/request.o + +all : postdmd + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + @if [ ! -d "$(POSTLIB)" ]; then \ + mkdir $(POSTLIB); \ + chmod 755 $(POSTLIB); \ + chgrp $(GROUP) $(POSTLIB); \ + chown $(OWNER) $(POSTLIB); \ + fi + cp postdmd $(POSTBIN)/postdmd + @chmod 755 $(POSTBIN)/postdmd + @chgrp $(GROUP) $(POSTBIN)/postdmd + @chown $(OWNER) $(POSTBIN)/postdmd + cp postdmd.ps $(POSTLIB)/postdmd.ps + @chmod 644 $(POSTLIB)/postdmd.ps + @chgrp $(GROUP) $(POSTLIB)/postdmd.ps + @chown $(OWNER) $(POSTLIB)/postdmd.ps + cp postdmd.1 $(MAN1DIR)/postdmd.1 + @chmod 644 $(MAN1DIR)/postdmd.1 + @chgrp $(GROUP) $(MAN1DIR)/postdmd.1 + @chown $(OWNER) $(MAN1DIR)/postdmd.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postdmd + +postdmd : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postdmd $(OFILES) + +postdmd.o : $(HFILES) + +$(COMMONDIR)/glob.o\ +$(COMMONDIR)/misc.o\ +$(COMMONDIR)/request.o : + @cd $(COMMONDIR); $(MAKE) -f common.mk `basename $@` + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + postdmd.1 >XXX.1; \ + mv XXX.1 postdmd.1 + diff --git a/sys/src/cmd/postscript/postdmd/postdmd.ps b/sys/src/cmd/postscript/postdmd/postdmd.ps new file mode 100755 index 000000000..fa312af02 --- /dev/null +++ b/sys/src/cmd/postscript/postdmd/postdmd.ps @@ -0,0 +1,124 @@ +% +% Version 3.3.2 prologue for DMD bitmap files. +% + +/#copies 1 store +/aspectratio 1 def +/formsperpage 1 def +/landscape false def +/magnification 1 def +/margin 0 def +/orientation 0 def +/rotation 1 def +/screenres 100 def +/xoffset 0 def +/yoffset 0 def + +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + + pagedimensions + xcenter ycenter translate + orientation rotation mul rotate + xoffset inch yoffset inch translate + magnification dup aspectratio mul scale + + /height height margin sub def + /width width margin sub def +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def} bind def + +/bitmap { + /scanlines exch def + /scanlength exch def + /flip exch def + /v8format exch def + + /bytelength scanlength 8 idiv def + /picstr bytelength string def + /lpicstr bytelength string def + /bytelength bytelength 1 sub def + + gsave + +% First the overall scaling. + + height scanlines div width scanlength div min + 72 screenres div min + dup scale + +% Followed by the one for the unit square. + + scanlength neg 2 div scanlines neg 2 div translate + scanlength scanlines scale + v8format {getv8bitmap} {getbitmap} ifelse + grestore +} bind def + +/getbitmap { + scanlength scanlines flip [scanlength 0 0 scanlines neg 0 scanlines] { + 0 { + currentfile token pop dup + 0 eq {pop pop exit} if + /charcount exch def + picstr 1 index charcount getinterval + /repl exch def + currentfile repl readhexstring pop pop + charcount add + currentfile token pop { + picstr 1 index repl putinterval + charcount add + } repeat + } loop + picstr + } imagemask +} bind def + +/getv8bitmap { + scanlength scanlines flip not [scanlength 0 0 scanlines neg 0 scanlines] { + 0 { + currentfile token pop dup + 0 eq {pop pop exit} if + /charcount exch def + picstr 1 index charcount getinterval + /repl exch def + currentfile repl readhexstring pop pop + charcount add + currentfile token pop { + picstr 1 index repl putinterval + charcount add + } repeat + } loop + 0 0 picstr { + exch lpicstr exch get xor + lpicstr exch 2 index exch put + 1 add dup + } forall + pop pop lpicstr + } imagemask +} bind def + +/done {/lastpage where {pop lastpage} if} def diff --git a/sys/src/cmd/postscript/postgif/mkfile b/sys/src/cmd/postscript/postgif/mkfile new file mode 100755 index 000000000..667f07acb --- /dev/null +++ b/sys/src/cmd/postscript/postgif/mkfile @@ -0,0 +1,32 @@ +</$objtype/mkfile + +<../config + +TARG=postgif +OFILES=postgif.$O\ + +COMMONDIR=../common + +HFILES=$COMMONDIR/comments.h\ + $COMMONDIR/ext.h\ + $COMMONDIR/gen.h\ + $COMMONDIR/path.h\ + +BIN=$POSTBIN +LIB=$COMMONDIR/com.a$O + +</sys/src/cmd/mkone + +CC=pcc +LD=pcc +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B + +install:V: $POSTLIB/postgif.ps + +$POSTLIB/postgif.ps: postgif.ps + cp $prereq $target + +$LIB: + cd $COMMONDIR + mk install + mk clean diff --git a/sys/src/cmd/postscript/postgif/postgif.c b/sys/src/cmd/postscript/postgif/postgif.c new file mode 100755 index 000000000..d66ec6543 --- /dev/null +++ b/sys/src/cmd/postscript/postgif/postgif.c @@ -0,0 +1,755 @@ + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif +#include <sys/types.h> +#include <fcntl.h> + +#include "comments.h" +#include "gen.h" +#include "path.h" +#include "ext.h" + +#define dbprt if (debug) fprintf + +char *optnames = "a:c:fglm:n:o:p:x:y:C:E:DG:IL:P:"; +char *prologue = POSTGIF; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ +int page = 0; /* last page we worked on */ +int printed = 0; /* and the number of pages printed */ + +extern char *malloc(); +extern void free(); +extern double atof(), pow(); + +unsigned char ibuf[BUFSIZ]; +unsigned char *cmap, *gcmap, *lcmap; +unsigned char *gmap, *ggmap, *lgmap; +unsigned char *pmap; +double gamma; +float cr = 0.3, cg = 0.59, cb = 0.11; +int maplength, gmaplength, lmaplength; +int scrwidth, scrheight; +int gcolormap, lcolormap; +int bitperpixel, background; +int imageleft, imagetop; +int imagewidth, imageheight; +int interlaced, lbitperpixel; +int gray = 0; +int gammaflag = 0; +int negative = 0; +int terminate = 0; +int codesize, clearcode, endcode, curstblsize, pmindex, byteinibuf, bitsleft; +int prefix[4096], suffix[4096], cstbl[4096]; +int bburx = -32767, bbury = -32767; +FILE *fp_in = NULL; +FILE *fp_out = stdout; + +char * +allocate(size) + int size; +{ + char *p; + + if ((p = malloc(size)) == NULL) error(FATAL, "not enough memory"); + return(p); +} + +void +puthex(c, fp) + unsigned char c; + FILE *fp; +{ + static char hextbl[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + }; + + putc(hextbl[(c >> 4) & 017], fp); + putc(hextbl[c & 017], fp); +} + +void +setcolormap(bp) + int bp; +{ + int i, entries = 1, scale = 1; + unsigned char *p, *q; + + for (i = 0; i < bp; i++) entries *= 2; + for (i = 0; i < 8 - bp; i++) scale *= 2; + gcmap = (unsigned char *) allocate(entries*3); + ggmap = (unsigned char *) allocate(entries); + gmaplength = entries; + for (i = 0, p = gcmap, q = ggmap; i < 256; i += scale, p += 3, q++) { + if (negative) { + *p = 255 - i; p[1] = *p; p[2] = *p; + *q = *p; + } + else { + *p = i; p[1] = i; p[2] = i; + *q = i; + } + } + if (gammaflag) + for (i = 0, p = gcmap; i < 256; i += scale, p += 3) { + *p = (unsigned char) (pow((double) *p/256.0, gamma)*256); + p[1] = *p; p[2] = *p; + } +dbprt(stderr,"default color map:\n"); +for (i = 0; i < entries*3; i += 3) +dbprt(stderr, "%d, %d, %d\n", gcmap[i], gcmap[i+1], gcmap[i+2]); +} + +void +readgcolormap(bp) + int bp; +{ + int i, entries = 1; + unsigned char *p, *q; + + for (i = 0; i < bp; i++) entries *= 2; + gcmap = (unsigned char *) allocate(entries*3); + ggmap = (unsigned char *) allocate(entries); + gmaplength = entries; + fread(gcmap, sizeof(*gcmap), entries*3, fp_in); + if (negative) + for (i = 0, p = gcmap; i < entries*3; i++, p++) *p = 255 - *p; + for (i = 0, p = gcmap, q = ggmap; i < entries; i++, p += 3, q++) + *q = cr*(int)p[0] + cg*(int)p[1] + cb*(int)p[2] + 0.5; + if (gammaflag) + for (i = 0, p = gcmap; i < entries*3; i++, p++) + *p = (unsigned char) (pow((double) *p/256.0, gamma)*256); +dbprt(stderr,"global color map:\n"); +for (i = 0; i < entries*3; i += 3) +dbprt(stderr, "%d, %d, %d\n", gcmap[i], gcmap[i+1], gcmap[i+2]); +} + +void +readlcolormap(bp) + int bp; +{ + int i, entries = 1; + unsigned char *p, *q; + + for (i = 0; i < bp; i++) entries *= 2; + lcmap = (unsigned char *) allocate(entries*3); + lgmap = (unsigned char *) allocate(entries); + lmaplength = entries; + fread(lcmap, sizeof(*lcmap), entries*3, fp_in); + if (negative) + for (i = 0, p = lcmap; i < entries*3; i++, p++) *p = 255 - *p; + for (i = 0, p = lcmap, q = lgmap; i < entries; i++, p += 3, q++) + *q = cr*(int)p[0] + cg*(int)p[1] + cb*(int)p[2] + 0.5; + if (gammaflag) + for (i = 0, p = lcmap; i < entries*3; i++, p++) + *p = (unsigned char) (pow((double) *p/256.0, gamma)*256); +dbprt(stderr,"local color map:\n"); +for (i = 0; i < entries*3; i += 3) +dbprt(stderr, "%d, %d, %d\n", lcmap[i], lcmap[i+1], lcmap[i+2]); +} + +void +initstbl() +{ + int i, entries = 1, *p, *s; + + for (i = 0; i < codesize; i++) entries *= 2; + clearcode = entries; + endcode = clearcode + 1; + for (i = 0, p = prefix, s = suffix; i <= endcode; i++, p++, s++) { + *p = endcode; + *s = i; + } + curstblsize = endcode + 1; + pmindex = 0; + byteinibuf = 0; + bitsleft = 0; +} + +int +nextbyte() +{ + static ibufindex; + + if (byteinibuf) { + byteinibuf--; + ibufindex++; + } + else { + fread(ibuf, sizeof(*ibuf), 1, fp_in); + byteinibuf = ibuf[0]; +dbprt(stderr, "byte count: %d\n", byteinibuf); + if (byteinibuf) fread(ibuf, sizeof(*ibuf), byteinibuf, fp_in); + else error(FATAL, "encounter zero byte count block before end code"); + ibufindex = 0; + byteinibuf--; + ibufindex++; + } + return(ibuf[ibufindex-1]); +} + +int masktbl[25] = { + 0, 01, 03, 07, 017, 037, 077, 0177, 0377, 0777, 01777, 03777, 07777, + 017777, 037777, 077777, 0177777, 0377777, 0777777, 01777777, 03777777, + 07777777, 017777777, 037777777, 077777777 +}; + +int +getcode() +{ + int cs, c; + static int oldc; + + if (curstblsize < 4096) cs = cstbl[curstblsize]; + else cs = 12; + while (bitsleft < cs) { + oldc = (oldc & masktbl[bitsleft]) | ((nextbyte() & 0377) << bitsleft); + bitsleft += 8; + } + c = oldc & masktbl[cs]; + oldc = oldc >> cs; + bitsleft -= cs; +/* dbprt(stderr, "code: %d %d %d\n", curstblsize, cs, c); */ + return(c); +} + +void +putcode(c) + int c; +{ + if (prefix[c] != endcode) { + putcode(prefix[c]); + pmap[pmindex] = suffix[c]; + pmindex++; + } + else { + pmap[pmindex] = suffix[c]; + pmindex++; + } +} + +int +firstof(c) + int c; +{ + while (prefix[c] != endcode) c = prefix[c]; + return(suffix[c]); +} + +void +writeimage() +{ + int i, j, k; + +dbprt(stderr, "pmindex: %d\n", pmindex); + fputs("save\n", fp_out); + fprintf(fp_out, "/codestr %d string def\n", imagewidth); + if (!gray) { + fprintf(fp_out, "/colortbl currentfile %d string readhexstring\n", + maplength*3); + for (i = 0; i < maplength; i++) puthex(cmap[i], fp_out); + fputs("\n", fp_out); + for (i = maplength ; i < maplength*2; i++) puthex(cmap[i], fp_out); + fputs("\n", fp_out); + for (i = maplength*2 ; i < maplength*3; i++) puthex(cmap[i], fp_out); + fputs("\npop def\n", fp_out); + fprintf(fp_out, "/graytbl currentfile %d string readhexstring\n", + maplength); + for (i = 0; i < maplength; i++) puthex(gmap[i], fp_out); + fputs("\npop def\n", fp_out); + } + fprintf(fp_out, "%s %d %d %d %d gifimage\n", + gray ? "true" : "false", imagewidth, imageheight, + scrwidth - imageleft - imagewidth, scrheight - imagetop - imageheight); + if (gray) { + if (interlaced) { + int *iltbl; + + iltbl = (int *) allocate(imageheight*sizeof(int)); + j = 0; + for (i = 0; i < imageheight; i += 8) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass1: %d\n", j); + for (i = 4; i < imageheight; i += 8) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass2: %d\n", j); + for (i = 2; i < imageheight; i += 4) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass3: %d\n", j); + for (i = 1; i < imageheight; i += 2) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass4: %d\n", j); + + for (i = 0; i < imageheight; i++) { + k = iltbl[i]; + for (j = 0; j < imagewidth; j++, k++) + puthex(gmap[pmap[k]], fp_out); + fputs("\n", fp_out); + } + } + else { + for (i = 0, k = 0; i < imageheight; i++) { + for (j = 0; j < imagewidth; j++, k++) + puthex(gmap[pmap[k]], fp_out); + fputs("\n", fp_out); + } + } + } + else { + if (interlaced) { + int *iltbl; + + iltbl = (int *) allocate(imageheight*sizeof(int)); + j = 0; + for (i = 0; i < imageheight; i += 8) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass1: %d\n", j); + for (i = 4; i < imageheight; i += 8) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass2: %d\n", j); + for (i = 2; i < imageheight; i += 4) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass3: %d\n", j); + for (i = 1; i < imageheight; i += 2) { + iltbl[i] = j; + j += imagewidth; + } +dbprt(stderr, "pass4: %d\n", j); + + for (i = 0; i < imageheight; i++) { + k = iltbl[i]; + for (j = 0; j < imagewidth; j++, k++) puthex(pmap[k], fp_out); + fputs("\n", fp_out); + } + } + else { + for (i = 0, k = 0; i < imageheight; i++) { + for (j = 0; j < imagewidth; j++, k++) puthex(pmap[k], fp_out); + fputs("\n", fp_out); + } + } + } + fputs("restore\n", fp_out); +} + +void +readimage() +{ + int bytecount, zerobytecount = 0; + int code, oldcode; + + fread(ibuf, sizeof(*ibuf), 9, fp_in); + imageleft = ibuf[0] + 256*ibuf[1]; + imagetop = ibuf[2] + 256*ibuf[3]; + imagewidth = ibuf[4] + 256*ibuf[5]; + imageheight = ibuf[6] + 256*ibuf[7]; + lcolormap = ibuf[8] & 0200; + interlaced = ibuf[8] & 0100; + lbitperpixel = (ibuf[8] & 07) + 1; +dbprt(stderr, "imageleft: %d\n", imageleft); +dbprt(stderr, "imagetop: %d\n", imagetop); +dbprt(stderr, "imagewidth: %d\n", imagewidth); +dbprt(stderr, "imgaeheight: %d\n", imageheight); +dbprt(stderr, "lcolormap: %d\n", lcolormap ? 1 : 0); +dbprt(stderr, "interlaced: %d\n", interlaced ? 1 : 0); +dbprt(stderr, "lbitperpixel: %d\n", lbitperpixel); + if (lcolormap) { + readlcolormap(lbitperpixel); + cmap = lcmap; + gmap = lgmap; + maplength = lmaplength; + } + +dbprt(stderr, "start reading raster data\n"); + fread(ibuf, sizeof(*ibuf), 1, fp_in); + codesize = ibuf[0]; +dbprt(stderr, "codesize: %d\n", codesize); + pmap = (unsigned char *) allocate(imagewidth*imageheight); + initstbl(); + while ((code = getcode()) != endcode) { + if (code == clearcode) { + curstblsize = endcode + 1; + code = getcode(); + putcode(code); + oldcode = code; + } + else if (code < curstblsize) { + putcode(code); + prefix[curstblsize] = oldcode; + suffix[curstblsize] = firstof(code); + curstblsize++; + oldcode = code; + } + else { + if (code != curstblsize) error(FATAL, "code out of order"); + prefix[curstblsize] = oldcode; + suffix[curstblsize] = firstof(oldcode); + curstblsize++; + putcode(curstblsize-1); + oldcode = code; + } + } +dbprt(stderr, "finish reading raster data\n"); + + /* read the rest of the raster data */ + do { + fread(ibuf, sizeof(*ibuf), 1, fp_in); + bytecount = ibuf[0]; +dbprt(stderr, "byte count: %d\n", bytecount); + if (bytecount) fread(ibuf, sizeof(*ibuf), bytecount, fp_in); + else zerobytecount = 1; + } while (!zerobytecount); + + writeimage(); + + if (lcolormap) { + cmap = gcmap; + gmap = ggmap; + maplength = gmaplength; + free(lcmap); + free(lgmap); + } +} + +void +readextensionblock() +{ + int functioncode, bytecount, zerobytecount = 0; + + fread(ibuf, sizeof(*ibuf), 1, fp_in); + functioncode = ibuf[0]; +dbprt(stderr, "function code: %d\n", functioncode); + do { + fread(ibuf, sizeof(*ibuf), 1, fp_in); + bytecount = ibuf[0]; +dbprt(stderr, "byte count: %d\n", bytecount); + if (bytecount) fread(ibuf, sizeof(*ibuf), bytecount, fp_in); + else zerobytecount = 1; + } while (!zerobytecount); +} + +void +writebgscr() +{ + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fputs("/saveobj save def\n", fp_out); + fprintf(fp_out, "%s: %d %d %d %d\n", + "%%PageBoundingBox", 0, 0, scrwidth, scrheight); + if (scrwidth > bburx) bburx = scrwidth; + if (scrheight > bbury) bbury = scrheight; + fprintf(fp_out, "%d %d gifscreen\n", scrwidth, scrheight); +} + +void +writeendscr() +{ + if ( fp_out == stdout ) printed++; + fputs("showpage\n", fp_out); + fputs("saveobj restore\n", fp_out); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); +} + +void +redirect(pg) + int pg; /* next page we're printing */ +{ + static FILE *fp_null = NULL; /* if output is turned off */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} + +void +readgif() +{ + int i, j, k; + + for (i = 0, j = 1, k = 0; i < 13; i++) { + for (; k < j; k++) cstbl[k] = i; + j *= 2; + } + + fread(ibuf, sizeof(*ibuf), 6, fp_in); +dbprt(stderr, "%.6s\n", ibuf); + if (strncmp((char *)ibuf, "GIF87a", 6) != 0) { + fread(ibuf, sizeof(*ibuf), 122, fp_in); + fread(ibuf, sizeof(*ibuf), 6, fp_in); +dbprt(stderr, "%.6s\n", ibuf); + if (strncmp((char *)ibuf, "GIF87a", 6) != 0) + error(FATAL, "wrong GIF signature"); + } + fread(ibuf, sizeof(*ibuf), 7, fp_in); + scrwidth = ibuf[0] + 256*ibuf[1]; + scrheight = ibuf[2] + 256*ibuf[3]; + gcolormap = ibuf[4] & 0200; + bitperpixel = (ibuf[4] & 07) + 1; + background = ibuf[5]; +dbprt(stderr, "scrwidth: %d\n", scrwidth); +dbprt(stderr, "scrheight: %d\n", scrheight); +dbprt(stderr, "gcolormap: %d\n", gcolormap ? 1 : 0); +dbprt(stderr, "bitperpixel: %d\n", bitperpixel); +dbprt(stderr, "background: %d\n", background); + if (ibuf[6] != 0) error(FATAL, "wrong screen descriptor"); + if (gcolormap) readgcolormap(bitperpixel); + else setcolormap(bitperpixel); + + redirect(++page); + writebgscr(); + + cmap = gcmap; + gmap = ggmap; + maplength = gmaplength; + + do { + fread(ibuf, sizeof(*ibuf), 1, fp_in); + if (ibuf[0] == ',') readimage(); + else if (ibuf[0] == ';') terminate = 1; + else if (ibuf[0] == '!') readextensionblock(); + else + error(FATAL, "wrong image separator character or wrong GIF terminator"); + } while (!terminate); + + writeendscr(); + + free(gcmap); + free(ggmap); +} + +void +init_signals() +{ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } + else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } + + signal(SIGTERM, interrupt); +} + +void +header() +{ + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", BOUNDINGBOX, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} + +void +options() +{ + int ch; /* return value from getopt() */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'f': + negative = TRUE; + break; + + case 'g': + gray = TRUE; + break; + + case 'l': + fprintf(stdout, "/alignment true def\n"); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'x': /* shift things horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding - unnecessary */ + fontencoding = optarg; + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'G': + gammaflag = ON; + gamma = atof(optarg); + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + + } + } + + argc -= optind; /* get ready for non-option args */ + argv += optind; +} + +void +setup() +{ + /*setencoding(fontencoding);*/ + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { /* followed by stuff for multiple pages +*/ + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} + +void +arguments() +{ + if ( argc < 1 ) { + fp_in = stdin; + readgif(); + } + else { /* at least one argument is left */ + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + readgif(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } + } +} + +void +done() +{ + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s 0 0 %d %d\n", BOUNDINGBOX, bburx, bbury); + fprintf(stdout, "%s %d\n", PAGES, printed); +} + +main(agc, agv) + int agc; + char *agv[]; +{ + argc = agc; + argv = agv; + prog_name = argv[0]; + + init_signals(); + header(); + options(); + setup(); + arguments(); + done(); + + exit(0); +} + diff --git a/sys/src/cmd/postscript/postgif/postgif.ps b/sys/src/cmd/postscript/postgif/postgif.ps new file mode 100755 index 000000000..9827857f7 --- /dev/null +++ b/sys/src/cmd/postscript/postgif/postgif.ps @@ -0,0 +1,104 @@ +% +% Version 3.3.2 prologue for GIF pixmap files. +% + +/#copies 1 store +/aspectratio 1 def +/formsperpage 1 def +/landscape false def +/magnification 1 def +/margin 0 def +/orientation 0 def +/rotation 1 def +/xoffset 0 def +/yoffset 0 def + +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + + pagedimensions + xcenter ycenter translate + orientation rotation mul rotate + xoffset inch yoffset inch translate + magnification dup aspectratio mul scale + + /height height margin sub def + /width width margin sub def +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def} bind def + +/done {/lastpage where {pop lastpage} if} def + +/alignment false def + +/gifscreen { % scrwidth scrheight $ + 2 copy + + alignment { + 100 dup dtransform exch 100 exch div abs exch 100 exch div abs + 2 copy scale + /height exch height exch div def + /width exch width exch div def + } if + + height exch div exch width exch div + 2 copy lt { pop } { exch pop } ifelse + + alignment { cvi } if + + dup scale + + neg 2 div exch neg 2 div exch translate +} def + +/gifimage { % gray imagewidth imageheight xorigin yorigin $ + translate + 2 copy scale + /imageheight exch def + /imagewidth exch def + /gray exch def + imagewidth imageheight 8 [imagewidth 0 0 imageheight neg 0 imageheight] + gray { + { currentfile codestr readhexstring pop } image + } { + /colorimage where { + pop + /picstr imagewidth 3 mul string def + { currentfile codestr readhexstring pop pop + 0 1 imagewidth 1 sub { + picstr exch dup 3 mul exch colortbl exch codestr exch get + 3 mul 3 getinterval putinterval + } for picstr + } false 3 colorimage + } { + { currentfile codestr readhexstring pop pop + 0 1 imagewidth 1 sub { + codestr exch dup graytbl exch codestr exch get get put + } for codestr + } image + } ifelse + } ifelse +} def diff --git a/sys/src/cmd/postscript/postio/README b/sys/src/cmd/postscript/postio/README new file mode 100755 index 000000000..88da4bc4f --- /dev/null +++ b/sys/src/cmd/postscript/postio/README @@ -0,0 +1,20 @@ +Serial communications program for PostScript printers. + +Runs as a single read/write process (by default). Use the -R2 option +or set splitme to TRUE (file postio.c) to get separate read and write +processes. Although not the default, we recommend using separate read +and write processes. + +Sends occasional status queries (control Ts) while transmitting files. +Use the -q option or set quiet (file postio.c) to TRUE to disable status +queries. + +Datakit connections are supported on System V and Ninth Edition systems. +The syntax (for connecting to a Datakit destination) varies. Check the +SYSV and V9 versions of setupline() in file ifdef.c. + +Set DKHOST and DKSTREAMS to TRUE in postio.mk for streams based DKHOST +support. When DKSTREAMS is TRUE postio.mk uses "dknetty" as the stream +module. Settings like DKSTREAMS=dkty select a different stream module +and may be required for full Datakit support on some systems. + diff --git a/sys/src/cmd/postscript/postio/ifdef.c b/sys/src/cmd/postscript/postio/ifdef.c new file mode 100755 index 000000000..1d7be0905 --- /dev/null +++ b/sys/src/cmd/postscript/postio/ifdef.c @@ -0,0 +1,867 @@ +/* + * + * Conditionally compiled routines for setting up and reading the line. Things + * were getting out of hand with all the ifdefs, and even though this defeats + * part of the purpose of conditional complilation directives, I think it's easier + * to follow this way. Thanks to Alan Buckwalter for the System V DKHOST code. + * + * postio now can be run as separate read and write processes, but requires that + * you write a procedure called resetline() and perhaps modify readline() some. + * I've already tested the code on System V and it seems to work. Ninth Edition + * and BSD code may be missing. + * + * By request I've changed the way some of the setupline() procedures (eg. in the + * System V implementation) handle things when no line has been given. If line is + * NULL the new setupline() procedures try to continue, assuming whoever called + * postio connected stdout to the printer. Things will only work if we can read + * and write stdout! + * + */ + +#include <stdio.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <errno.h> + +#include "ifdef.h" /* conditional header file inclusion */ +#include "gen.h" /* general purpose definitions */ + +FILE *fp_ttyi, *fp_ttyo; +char *ptr = mesg; + +extern int window_size; + +/*****************************************************************************/ + +#ifdef SYSV +setupline() + +{ + + struct termio termio; + +/* + * + * Line initialization for SYSV. For now if no line is given (ie. line == NULL ) + * we continue on as before using stdout as ttyi and ttyo. Doesn't work when we're + * running in interactive mode or forcing stuff that comes back from the printer + * to stdout. Both cases are now caught by a test that's been added to routine + * initialize(). The change is primarily for the version of lp that's available + * with SVR3.2. + * + */ + +#ifdef DKHOST + if ( line != NULL && *line != '/' ) { + if ( strncmp(line, "DK:", 3) == 0 ) + line += 3; + dkhost_connect(); +#ifdef DKSTREAMS + if ( ioctl(ttyi, I_PUSH, DKSTREAMS) == -1 ) + error(FATAL, "ioctl error - %s", DKSTREAMS); + if ( ioctl(ttyi, I_PUSH, "ldterm") == -1 ) + error(FATAL, "ioctl error - ldterm"); +#endif + } else +#endif + + if ( line == NULL ) + ttyi = fileno(stdout); + else if ( (ttyi = open(line, O_RDWR)) == -1 ) + error(FATAL, "can't open %s", line); + + if ( (ttyo = dup(ttyi)) == -1 ) + error(FATAL, "can't dup file descriptor for %s", line); + + if ( stopbits == 1 ) + stopbits = 0; + else stopbits = CSTOPB; + + if ( fcntl(ttyi, F_SETFL, O_NDELAY) == -1 ) + error(FATAL, "fcntl error - F_SETFL"); + + if ( ioctl(ttyi, TCGETA, &termio) == -1 ) + error(FATAL, "ioctl error - TCGETA"); + + termio.c_iflag = IXON | IGNCR; + termio.c_oflag = 0; + termio.c_cflag = HUPCL | CREAD | CS8 | stopbits | baudrate; + termio.c_lflag = 0; + termio.c_cc[VMIN] = termio.c_cc[VTIME] = 0; + + if ( ioctl(ttyi, TCSETA, &termio) == -1 ) + error(FATAL, "ioctl error - TCSETA"); + + if ( ioctl(ttyi, TCFLSH, 2) == -1 ) + error(FATAL, "ioctl error - TCFLSH"); + + fp_ttyi = fdopen(ttyi, "r"); + +} /* End of setupline */ + +/*****************************************************************************/ + +resetline() + +{ + + int flags; /* for turning O_NDELAY off */ + struct termio termio; /* so we can reset flow control */ + +/* + * + * Only used if we're running the program as separate read and write processes. + * Called from split() after the initial connection has been made and returns + * TRUE if two processes should work. Don't know if the O_NDELAY stuff is really + * needed, but setting c_cc[VMIN] to 1 definitely is. If we leave it be (as a 0) + * the read in readline() won't block! + * + */ + + if ( (flags = fcntl(ttyi, F_GETFL, 0)) == -1 ) + error(FATAL, "fcntl error - F_GETFL"); + + flags &= ~O_NDELAY; + + if ( fcntl(ttyi, F_SETFL, flags) == -1 ) + error(FATAL, "fcntl error - F_SETFL"); + + if ( ioctl(ttyi, TCGETA, &termio) == -1 ) + error(FATAL, "ioctl error - TCGETA"); + + termio.c_iflag &= ~IXANY; + termio.c_iflag |= IXON | IXOFF; + termio.c_cc[VMIN] = 1; + termio.c_cc[VTIME] = 0; + + if ( ioctl(ttyi, TCSETA, &termio) == -1 ) + error(FATAL, "ioctl error - TCSETA"); + + return(TRUE); + +} /* End of resetline */ + +/*****************************************************************************/ + +setupstdin(mode) + + int mode; /* what to do with stdin settings */ + +{ + + struct termio termio; + + static int saved = FALSE; + static struct termio oldtermio; + +/* + * + * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for + * stdin. Expect something like raw mode with no echo will be set up. Explicit + * code to ensure blocking reads probably isn't needed because blocksize is set + * to 1 when we're in interactive mode, but I've included it anyway. + * + */ + + if ( interactive == TRUE ) + switch ( mode ) { + case 0: + if ( isatty(0) != 1 ) + error(FATAL, "stdin not a terminal - can't run interactive mode"); + if ( ioctl(0, TCGETA, &oldtermio) == -1 ) + error(FATAL, "can't save terminal settings"); + saved = TRUE; + break; + + case 1: + termio = oldtermio; + termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL); + termio.c_cc[VMIN] = 1; + termio.c_cc[VTIME] = 0; + ioctl(0, TCSETA, &termio); + break; + + case 2: + if ( saved == TRUE ) + ioctl(0, TCSETA, &oldtermio); + break; + } /* End switch */ + +} /* End of setupstdin */ + +/*****************************************************************************/ + +readline() + +{ + + int n; /* read() return value */ + int ch; /* for interactive mode */ + + static int tries = 0; /* consecutive times read returned 0 */ + +/* + * + * Reads characters coming back from the printer on ttyi up to a newline (or EOF) + * or until no more characters are available. Characters are put in mesg[], the + * string is terminated with '\0' when we're done with a line and TRUE is returned + * to the caller. If complete line wasn't available FALSE is returned. Interactive + * mode should loop here forever, except during start(), echoing characters to + * stdout. If it happens to leave FALSE should be returned. The non-blocking read + * gets us out until split() is called. + * + * Some users (apparently just on 3B2 DKHOST systems) have had problems with the + * two process implementation that's forced me to kludge things up some. When a + * printer (on those systems) is turned off while postio is transmitting files + * the write process hangs in writeblock() (postio.c) - it's typically in the + * middle of a write() call, while the read() call (below) continually returns 0. + * In the original code readline() returned FALSE when read() returned 0 and we + * get into a loop that never ends - because the write process is hung. In the + * one process implementation having read return 0 is legitimate because the line + * is opened for no delay, but with two processes the read() blocks and a return + * value of 0 should never occur. From my point of view the real problem is that + * the write() call hangs on 3B2 DKHOST systems and apparently doesn't anywhere + * else. If the write returned anything less than or equal to 0 writeblock() would + * shut things down. The kludge I've implemented counts the number of consecutive + * times read() returns a 0 and if it exceeds a limit (100) the read process will + * shut things down. In fact one return of 0 from read() when we're in the two + * process mode is undoubtedly sufficient and no counting should be necessary!!! + * Moving the check to getstatus() should also work and is probably where things + * belong. + * + */ + + if ( interactive == FALSE ) { + while ( (n = read(ttyi, ptr, 1)) != 0 ) { + if ( n < 0 ) + if ( errno == EINTR ) + continue; + else error(FATAL, "error reading %s", line); + tries = 0; + if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) { + *(ptr+1) = '\0'; + if ( *ptr == '\004' ) + strcpy(ptr, "%%[ status: endofjob ]%%\n"); + ptr = mesg; + return(TRUE); + } /* End if */ + ptr++; + } /* End while */ + if ( canread == TRUE && canwrite == FALSE ) /* read process kludge */ + if ( ++tries > 100 ) + error(FATAL, "printer appears to be offline - shutting down"); + return(FALSE); + } /* End if */ + + if ( canwrite == TRUE ) /* don't block during start() */ + return(FALSE); + + while ( (ch = getc(fp_ttyi)) != EOF ) + putc(ch, stdout); + return(FALSE); + +} /* End of readline */ +#endif + +/*****************************************************************************/ + +#ifdef V9 +#include <ipc.h> + +char tbuf[256]; /* temporary input buffer */ +char *nptr = tbuf; /* next character comes from here */ +char *eptr = tbuf; /* one past the last character in tbuf */ + +setupline() + +{ + + struct sgttyb sgtty; + struct ttydevb ttydev; /* for setting up the line */ + static struct tchars tchar = { '\377', /* interrupt */ + '\377', /* quit */ + '\021', /* start output */ + '\023', /* stop output */ + '\377', /* end-of-file */ + '\377' /* input delimiter */ + }; + +/* + * + * Line initialization for V9. + * + */ + + if ( line == NULL ) { + ttyi = ttyo = 1; + return; + } /* End if */ + alarm(120); /* watch for hanging opens */ + if ( line[0] == '/' ) { + if ( (ttyi = open(line, O_RDWR)) == -1 ) + error(FATAL, "can't open %s", line); + } else if ((ttyi = ipcopen(ipcpath(line, "dk", 0), "")) < 0) { + sleep(5); /* wait for Datakit to hangup */ + if ((ttyi = ipcopen(ipcpath(line, "dk", 0), "")) < 0) { + fprintf(stderr, "%s", errstr); + error(FATAL, "can't ipcopen %s", line); + } + } + alarm(0); + + if ( (ttyo = dup(ttyi)) == -1 ) + error(FATAL, "can't dup file descriptor for %s", line); + + if ( ioctl(ttyi, FIOPUSHLD, &tty_ld) == -1 ) + error(FATAL, "ioctl error - FIOPUSHLD"); + + if ( ioctl(ttyi, TIOCGDEV, &ttydev) == -1 ) + error(FATAL, "ioctl error - TIOCGDEV"); + + if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCGETP"); + + sgtty.sg_flags &= ~ECHO; + sgtty.sg_flags &= ~CRMOD; + sgtty.sg_flags |= CBREAK; + ttydev.ispeed = baudrate; + ttydev.ospeed = baudrate; + + if ( ioctl(ttyi, TIOCSDEV, &ttydev) == -1 ) + error(FATAL, "ioctl error - TIOCSDEV"); + + if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCSETP"); + + if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 ) + error(FATAL, "ioctl error - TIOCSETC"); + + fp_ttyi = fdopen(ttyi, "r"); + +} /* End of setupline */ + +/*****************************************************************************/ + +resetline() + +{ + + struct sgttyb sgtty; + +/* + * + * Only used if we're running the program as separate read and write processes. + * Called from split() after the initial connection has been made and returns + * TRUE if two processes should work. Haven't tested or even compiled the stuff + * for separate read and write processes on Ninth Edition systems - no guarantees + * even though we return TRUE! + * + */ + + if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCGETP"); + + sgtty.sg_flags |= TANDEM; + + if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCSETP"); + + return(TRUE); + +} /* End of resetline */ + +/*****************************************************************************/ + +setupstdin(mode) + + int mode; /* what to do with stdin settings */ + +{ + + struct sgttyb sgtty; + + static int saved = FALSE; + static struct sgttyb oldsgtty; + +/* + * + * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for + * stdin. Expect something like raw mode with no echo will be set up. Need to make + * sure interrupt and quit still work - they're the only good way to exit when + * we're running interactive mode. I haven't tested or even compiled this code + * so there are no guarantees. + * + */ + + if ( interactive == TRUE ) + switch ( mode ) { + case 0: + if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 ) + error(FATAL, "can't save terminal settings"); + saved = TRUE; + break; + + case 1: + sgtty = oldsgtty; + sgtty.sg_flags &= ~ECHO; + sgtty.sg_flags |= CBREAK; + ioctl(0, TIOCSETP, &sgtty); + break; + + case 2: + if ( saved == TRUE ) + ioctl(0, TIOCSETP, &oldsgtty); + break; + } /* End switch */ + +} /* End of setupstdin */ + +/*****************************************************************************/ + +readline() + +{ + + int n; /* read() return value */ + int ch; /* for interactive mode */ + +/* + * + * Reads characters coming back from the printer on ttyi up to a newline (or EOF) + * and transfers each line to the mesg[] array. Everything available on ttyi is + * initially stored in tbuf[] and a line at a time is transferred from there to + * mesg[]. The string in mesg[] is terminated with a '\0' and TRUE is returned to + * the caller when we find a newline, EOF, or reach the end of the mesg[] array. + * If nothing is available on ttyi we return FALSE if a single process is being + * used for reads and writes, while in the two process implementation we force a + * one character read. Interactive mode loops here forever, except during start(), + * echoing everything that comes back on ttyi to stdout. The performance of a + * simple getc/putc loop for interactive mode was unacceptable when run under mux + * and has been replaced by more complicated code. When layers wasn't involved + * the getc/putc loop worked well. + * + */ + + if ( interactive == FALSE ) { + while ( 1 ) { + while ( nptr < eptr ) { /* grab characters from tbuf */ + *ptr = *nptr++; + if ( *ptr == '\r' ) continue; + if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) { + *(ptr+1) = '\0'; + if ( *ptr == '\004' ) + strcpy(ptr, "%%[ status: endofjob ]%%\n"); + ptr = mesg; + return(TRUE); + } /* End if */ + ++ptr; + } /* End for */ + + nptr = eptr = tbuf; + if ( ioctl(ttyi, FIONREAD, &n) < 0 ) + if ( errno == EINTR ) + continue; + else error(FATAL, "ioctl error - FIONREAD"); + if ( n <= 0 ) + if ( canwrite == TRUE ) + return(FALSE); + n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf))); + if ( (n = read(ttyi, tbuf, n)) < 0 ) + if ( errno == EINTR ) + continue; + else error(FATAL, "error reading line %s", line); + else eptr = nptr + n; + } /* End while */ + } /* End if */ + + if ( canwrite == TRUE ) /* don't block during start() */ + return(FALSE); + + while ( 1 ) { /* only interactive mode gets here */ + if ( ioctl(ttyi, FIONREAD, &n) < 0 ) + error(FATAL, "ioctl error - FIONREAD"); + n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf))); + if ( (n = read(ttyi, tbuf, n)) < 0 ) + error(FATAL, "error reading line %s", line); + else if ( n == 0 ) /* should not happen */ + error(FATAL, "end of file in interactive mode"); + if ( write(1, tbuf, n) != n ) + error(FATAL, "error writing to stdout"); + } /* End while */ + + return(FALSE); + +} /* End of readline */ +#endif + +/*****************************************************************************/ + +#ifdef BSD4_2 +setupline() + +{ + + struct sgttyb sgtty; + static struct tchars tchar = { '\377', /* interrupt */ + '\377', /* quit */ + '\021', /* start output */ + '\023', /* stop output */ + '\377', /* end-of-file */ + '\377' /* input delimiter */ + }; + long lmodes; + int disc = NTTYDISC; + +/* + * + * Line initialization for BSD4_2. As in the System V code, if no line is given + * (ie. line == NULL) we continue on as before using stdout as ttyi and ttyo. + * + */ + + if ( line == NULL ) + ttyi = fileno(stdout); + else if ( (ttyi = open(line, O_RDWR)) == -1 ) + error(FATAL, "can't open %s", line); + + if ( (ttyo = dup(ttyi)) == -1 ) + error(FATAL, "can't dup file descriptor for %s", line); + + if (ioctl(ttyi, TIOCSETD, &disc) == -1 ) + error(FATAL, "ioctl error - TIOCSETD"); + + if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCGETP"); + + if ( ioctl(ttyi, TIOCLGET, &lmodes) == -1 ) + error(FATAL, "ioctl error - TIOCLGET"); + + sgtty.sg_flags &= ~ECHO; + sgtty.sg_flags &= ~CRMOD; + sgtty.sg_flags |= CBREAK; + sgtty.sg_ispeed = baudrate; + sgtty.sg_ospeed = baudrate; + lmodes |= LDECCTQ; + + if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCSETP"); + + if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 ) + error(FATAL, "ioctl error - TIOCSETC"); + + if ( ioctl(ttyi, TIOCLSET, &lmodes) == -1 ) + error(FATAL, "ioctl error - TIOCLSET"); + + fp_ttyi = fdopen(ttyi, "r"); + +} /* End of setupline */ + +/*****************************************************************************/ + +resetline() + +{ + + struct sgttyb sgtty; + +/* + * + * Only used if we're running the program as separate read and write processes. + * Called from split() after the initial connection has been made and returns + * TRUE if two processes should work. Haven't tested or even compiled the stuff + * for separate read and write processes on Berkeley systems - no guarantees + * even though we return TRUE! + * + */ + + if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCGETP"); + + sgtty.sg_flags |= TANDEM; + + if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 ) + error(FATAL, "ioctl error - TIOCSETP"); + + return(TRUE); + +} /* End of resetline */ + +/*****************************************************************************/ + +setupstdin(mode) + + int mode; /* what to do with stdin settings */ + +{ + + struct sgttyb sgtty; + + static int saved = FALSE; + static struct sgttyb oldsgtty; + +/* + * + * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for + * stdin. Expect something like raw mode with no echo will be set up. Need to make + * sure interrupt and quit still work - they're the only good way to exit when + * we're running interactive mode. I haven't tested or even compiled this code + * so there are no guarantees. + * + */ + + if ( interactive == TRUE ) + switch ( mode ) { + case 0: + if ( isatty(0) != 1 ) + error(FATAL, "stdin not a terminal - can't run interactive mode"); + if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 ) + error(FATAL, "can't save terminal settings"); + saved = TRUE; + break; + + case 1: + sgtty = oldsgtty; + sgtty.sg_flags &= ~ECHO; + sgtty.sg_flags |= CBREAK; + ioctl(0, TIOCSETP, &sgtty); + break; + + case 2: + if ( saved == TRUE ) + ioctl(0, TIOCSETP, &oldsgtty); + break; + } /* End switch */ + +} /* End of setupstdin */ + +/*****************************************************************************/ + +readline() + +{ + + int n; /* read() return value */ + int ch; /* for interactive mode */ + +/* + * + * Reads characters coming back from the printer on ttyo up to a newline (or EOF) + * or until no more characters are available. Characters are put in mesg[], the + * string is terminated with '\0' when we're done with a line and TRUE is returned + * to the caller. If complete line wasn't available FALSE is returned. Interactive + * mode should loop here forever, except during start(), echoing characters to + * stdout. If it happens to leave FALSE should be returned. Probably should read + * everything available on ttyi into a temporary buffer and work from there rather + * than reading one character at a time. + * + */ + + if ( interactive == FALSE ) { + while ( 1 ) { + if ( ioctl(ttyi, FIONREAD, &n) < 0 ) + if ( errno == EINTR ) + continue; + else error(FATAL, "ioctl error - FIONREAD"); + if ( n <= 0 ) + if ( canwrite == TRUE ) + return(FALSE); + else n = 1; + for ( ; n > 0; n-- ) { + /*if ( read(ttyi, ptr, 1) < 0 )*/ + if ( (*ptr = getc(fp_ttyi)) == EOF ) + if ( errno == EINTR ) + continue; + else error(FATAL, "error reading %s", line); + if ( *ptr == '\r' ) continue; + if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) { + *(ptr+1) = '\0'; + if ( *ptr == '\004' ) + strcpy(ptr, "%%[ status: endofjob ]%%\n"); + ptr = mesg; + return(TRUE); + } /* End if */ + ++ptr; + } /* End for */ + } /* End while */ + } /* End if */ + + if ( canwrite == TRUE ) /* don't block during start() */ + return(FALSE); + + while ( (ch = getc(fp_ttyi)) != EOF ) + putc(ch, stdout); + return(FALSE); + +} /* End of readline */ + +/*****************************************************************************/ + +/* @(#)strspn.c 1.2 */ +/*LINTLIBRARY*/ +/* + * Return the number of characters in the maximum leading segment + * of string which consists solely of characters from charset. + */ +int +strspn(string, charset) +char *string; +register char *charset; +{ + register char *p, *q; + + for(q=string; *q != '\0'; ++q) { + for(p=charset; *p != '\0' && *p != *q; ++p) + ; + if(*p == '\0') + break; + } + return(q-string); +} + +/* @(#)strpbrk.c 1.2 */ +/*LINTLIBRARY*/ +/* + * Return ptr to first occurance of any character from `brkset' + * in the character string `string'; NULL if none exists. + */ + +char * +strpbrk(string, brkset) +register char *string, *brkset; +{ + register char *p; + + do { + for(p=brkset; *p != '\0' && *p != *string; ++p) + ; + if(*p != '\0') + return(string); + } + while(*string++); + return((char*)0); +} + +/* @(#)strtok.c 1.2 */ +/* 3.0 SID # 1.2 */ +/*LINTLIBRARY*/ +/* + * uses strpbrk and strspn to break string into tokens on + * sequentially subsequent calls. returns NULL when no + * non-separator characters remain. + * `subsequent' calls are calls with first argument NULL. + */ + + +extern int strspn(); +extern char *strpbrk(); + +char * +strtok(string, sepset) +char *string, *sepset; +{ + register char *p, *q, *r; + static char *savept; + + /*first or subsequent call*/ + p = (string == (char*)0)? savept: string; + + if(p == 0) /* return if no tokens remaining */ + return((char*)0); + + q = p + strspn(p, sepset); /* skip leading separators */ + + if(*q == '\0') /* return if no tokens remaining */ + return((char*)0); + + if((r = strpbrk(q, sepset)) == (char*)0) /* move past token */ + savept = 0; /* indicate this is last token */ + else { + *r = '\0'; + savept = ++r; + } + return(q); +} +#endif + +/*****************************************************************************/ + +#ifdef DKHOST + +#ifndef DKSTREAMS +short dkrmode[3] = {DKR_TIME, 0, 0}; +#endif + +dkhost_connect() + +{ + + int ofd; /* for saving and restoring stderr */ + int dfd; + int retrytime = 5; + +/* + * + * Tries to connect to a Datakit destination. The extra stuff I've added to save + * and later restore stderr is primarily for our spooling setup at Murray Hill. + * postio is usually called with stderr directed to a file that will be returned + * to the user when the job finishes printing. Problems encountered by dkdial(), + * like busy messages, go to stderr but don't belong in the user's mail. They'll + * be temporarily directed to the log file. After we've connected stderr will be + * restored. + * + */ + + if ( *line == '\0' ) + error(FATAL, "incomplete Datakit line"); + + if ( fp_log != NULL && fp_log != stderr ) { /* redirect dkdial errors */ + ofd = dup(2); + close(2); + dup(fileno(fp_log)); + } /* End if */ + + while ( (dfd = ttyi = dkdial(line)) < 0 ) { + if ( retrytime < 0 ) + error(FATAL, "can't connect to %s", line); + sleep(retrytime++); + if ( retrytime > 60 ) + retrytime = 60; + } /* End while */ + + if ( fp_log != NULL && fp_log != stderr ) { /* restore stderr */ + close(2); + dup(ofd); + close(ofd); + } /* End if */ + +#ifndef DKSTREAMS + if ( ioctl(ttyi, DIOCRMODE, dkrmode) == -1 ) + error(FATAL, "ioctl error - DIOCRMODE"); + +#ifdef DIOURPWD + if ( window_size > 0 ) { + short dkparm[3]; + + dkparm[0] = dkminor(ttyi); + dkparm[1] = 1; + dkparm[2] = window_size; + if ( ioctl(ttyi, DIOURPWD, dkparm) < 0 || ioctl(ttyi, DIOCFLUSH, 0) < 0 ) + error(NON_FATAL, "WSA failed"); + } /* End if */ +#endif + + line = dtnamer(dkminor(ttyi)); + + if ( (ttyi = open(line, O_RDWR)) == -1 ) + error(FATAL, "can't open %s", line); + + close(dfd); +#endif + +} /* End of dkhost_connect */ +#endif + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postio/ifdef.h b/sys/src/cmd/postscript/postio/ifdef.h new file mode 100755 index 000000000..f158c46db --- /dev/null +++ b/sys/src/cmd/postscript/postio/ifdef.h @@ -0,0 +1,66 @@ +/* + * + * Conditional compilation definitions needed in ifdef.c and postio.c. + * + */ + +#ifdef SYSV +#include <termio.h> + +#ifdef DKSTREAMS +#include <sys/stream.h> +#include <sys/stropts.h> +#endif + +#endif + +#ifdef V9 +#include <sys/filio.h> +#include <sys/ttyio.h> + +extern int tty_ld; +#endif + +#ifdef BSD4_2 +#include <sgtty.h> +#include <sys/time.h> +#include <errno.h> + +#define FD_ZERO(s) (s) = 0 +#define FD_SET(n,s) (s) |= 1 << (n) + +extern int errno; +#endif + +#ifdef DKHOST +#include <dk.h> +#include <sysexits.h> + +extern char *dtnamer(); +extern int dkminor(); +#endif + +/* + * + * External variable declarations - most (if not all) are defined in postio.c and + * needed by the routines in ifdef.c. + * + */ + +extern char *line; /* printer is on this line */ +extern int ttyi; /* input */ +extern int ttyo; /* and output file descriptors */ +extern FILE *fp_log; /* just for DKHOST stuff */ + +extern char mesg[]; /* exactly what came back on ttyi */ +extern char *endmesg; /* one in front of last free slot in mesg */ +extern int next; /* next character goes in mesg[next] */ + +extern short baudrate; /* printer is running at this speed */ +extern int stopbits; /* and expects this many stop bits */ +extern int interactive; /* TRUE for interactive mode */ + +extern int whatami; /* a READ or WRITE process - or both */ +extern int canread; /* allows reads */ +extern int canwrite; /* and writes if TRUE */ + diff --git a/sys/src/cmd/postscript/postio/postio.1 b/sys/src/cmd/postscript/postio/postio.1 new file mode 100755 index 000000000..3075951b7 --- /dev/null +++ b/sys/src/cmd/postscript/postio/postio.1 @@ -0,0 +1,308 @@ +.TH POSTIO 1 "DWB 3.2" +.SH NAME +.B postio +\- serial interface for PostScript printers +.SH SYNOPSIS +\*(mBpostio\f1 +.OP \-l line +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B postio +sends +.I files +to the PostScript printer attached to +.IR line . +If no +.I files +are specified the standard input is sent. +The first group of +.I options +should be sufficient for most applications: +.TP 0.75i +.OP \-b speed +Transmit data over +.I line +at baud rate +.I speed. +Recognized baud rates are 1200, 2400, 4800, 9600, and 19200. +The default +.I speed +is 9600 baud. +.TP +.OP \-c +Do not send +.MR ^C s +(interrupts) to the printer, +which means +.B postio +does not force a busy printer into the idle state. +.TP +.OP \-l line +Connect to printer attached to +.IR line . +In most cases there is no default and +.B postio +must be able to read and write +.IR line . +If +.I line +does not begin with +.MW / +it is treated as a Datakit destination. +.TP +.OP \-q +Prevents status queries while +.I files +are being sent to the printer. +When status queries are disabled a dummy message is appended +to the log file before each block is transmitted. +.TP +.OP \-B num +Set internal buffer size for reading and writing +.I files +to +.I num +bytes +(default is 2048 bytes). +.TP +.OP \-D +Enable debug mode. +Guarantees that everything read on +.I line +will be added to the log file (standard error by default). +.TP +.OP \-L file +Data received on +.I line +gets put in +.IR file . +The default log +.I file +is standard error. +Printer or status messages that do not indicate a change in state +are not normally written to +.I file +but can be forced out using the +.OP \-D +option. +.TP +.OP \-P string +Send +.I string +to the printer before any of the input files. +The default +.I string +is simple PostScript code that disables timeouts. +.TP +.OP \-R num +Run +.B postio +as a single process if +.I num +is 1 or as separate read and write processes if +.I num +is 2. +By default +.B postio +runs as a single process. +.PP +The next two +.I options +are provided for users who expect to run +.B postio +on their own. +Neither is suitable for use in spooler interface +programs: +.TP 0.35i +.OP \-i +Run the program in interactive mode. +Any +.I files +are sent first and followed by the standard input. +Forces separate read and write processes +and overrides many other options. +To exit interactive mode use your interrupt or quit character. +To get a friendly interactive connection with the printer type +.MW executive +on a line by itself. +.TP +.OP \-t +Data received on +.I line +and not recognized as printer or status information is written to +the standard output. +Forces separate read and write processes. +Convenient if you have a PostScript program that +will be returning useful data to the host. +.PP +The last option is not generally recommended and should only +be used if all else fails to provide a reliable connection: +.TP 0.35i +.OP \-S +Slow the transmission of data to the printer. +Severely limits throughput, runs as a single process, +disables the +.OP \-q +option, limits the internal buffer size to 1024 bytes, +can use an excessive amount of +.SM CPU +time, and does nothing in interactive mode. +.PP +Best performance is usually obtained by using +a large internal buffer +.OP -B "" ) ( +and by running the program as separate read and write processes +.OP \-R2 "" ). ( +Inability to fork the additional process causes +.B postio +to continue as a single read/write process. +When one process is used, only data sent to the printer is flow-controlled. +.PP +The options are not all mutually exclusive. +The +.OP \-i +option always wins, selecting its own settings for whatever is +needed to run interactive mode, independent of anything else +found on the command line. +Interactive mode runs as separate read and write processes +and few of the other +.I options +accomplish anything in the presence of the +.OP \-i +option. +The +.OP \-t +option needs a reliable two way connection to the printer and +therefore tries to force separate read and write processes. +The +.OP \-S +option relies on the status query mechanism, so +.OP \-q +is disabled and the program runs as a single process. +.PP +In most cases +.B postio +starts by making a connection to +.I line +and then attempts to force the printer into the +.SM IDLE +state by sending an appropriate sequence of +.MW ^T +(status query), +.MW ^C +(interrupt), and +.MW ^D +(end of job) characters. +When the printer goes +.SM IDLE +.I files +are transmitted along with an occasional +.MW ^T +(unless the +.OP \-q +option was used). +After all the +.I files +are sent the program waits until it is reasonably sure the +job is complete. +Printer generated error messages received at any time +except while establishing the initial connection +(or when running interactive mode) cause +.B postio +to exit with a non-zero status. +In addition to being added to the log file, printer error messages +are also echoed to standard error. +.SH EXAMPLES +Run as a single process at 9600 baud and send +.I file1 +and +.I file2 +to the printer attached to +.MR /dev/tty01 : +.EX +postio -l /dev/tty01 \f2file1 file2 +.EE +Same as above except two processes are used, +the internal buffer is set to 4096 bytes, +and data returned by the printer gets put in file +.MR log : +.EX +postio -R2 -B4096 -l/dev/tty01 -Llog \f2file1 file2 +.EE +Establish an interactive connection with the printer at Datakit +destination +.MR my/printer : +.EX +postio -i -l my/printer +.EE +Send file +.MW program +to the printer connected to +.MR /dev/tty22 , +recover any data in file +.MR results , +and put log messages in file +.MR log : +.EX +postio -t -l /dev/tty22 -L log program >results +.EE +.SH DIAGNOSTICS +A 0 exit status is returned if the files ran successfully. +System errors (e.g., ``can't open the line'') set the low order +bit in the exit status, while PostScript errors set bit 1. +An exit status of 2 usually means the printer +detected a PostScript error in the input +.IR files . +.SH WARNINGS +.PP +The input +.I files +are handled as a single PostScript job. +Sending several different jobs, each with their own internal +end of job mark +.RM ( ^D ) +is not guaranteed to work properly. +.B postio +may quit before all the jobs have completed and could be restarted +before the last one finishes. +.PP +All the capabilities described above may not be available on every +machine or even across the different versions of +.SM UNIX +that are currently supported by the program. +For example, the code needed to connect to a Datakit destination may only +work on System\ V and may require that the +.SM DKHOST +software package be available at compile time. +.PP +There may be no default +.I line +so using +.OP \-l +option is strongly recommended. +If omitted +.B postio +may attempt to connect to the printer using the standard output. +If Datakit is involved the +.OP \-b +may be ineffective and attempts by +.B postio +to flow control data in both directions may not work. +The +.OP \-q +option can help if the printer is connected to \s-1RADIAN\s+1. +The +.OP \-S +option is not generally recommended and should only be used if +all else fails to establish a reliable connection. +.SH SEE ALSO +.BR buildtables (1), +.BR dpost (1), +.BR postdaisy (1), +.BR postdmd (1), +.BR postmd (1), +.BR postprint (1), +.BR postreverse (1), +.BR posttek (1), +.BR printfont (1) diff --git a/sys/src/cmd/postscript/postio/postio.c b/sys/src/cmd/postscript/postio/postio.c new file mode 100755 index 000000000..14adc77a1 --- /dev/null +++ b/sys/src/cmd/postscript/postio/postio.c @@ -0,0 +1,1212 @@ +/* + * + * postio - RS-232 serial interface for PostScript printers + * + * A simple program that manages input and output for PostScript printers. Much + * has been added and changed from early versions of the program, but the basic + * philosophy is still the same. Don't send real data until we're certain we've + * connected to a PostScript printer that's in the idle state and try to hold the + * connection until the job is completely done. It's more work than you might + * expect is necessary, but should provide a reasonably reliable spooler interface + * that can return error indications to the caller via the program's exit status. + * + * I've added code that will let you split the program into separate read/write + * processes. Although it's not the default it should be useful if you have a file + * that will be returning useful data from the printer. The two process stuff was + * laid down on top of the single process code and both methods still work. The + * implementation isn't as good as it could be, but didn't require many changes + * to the original program (despite the fact that there are now many differences). + * + * By default the program still runs as a single process. The -R2 option forces + * separate read and write processes after the intial connection is made. If you + * want that as the default initialize splitme (below) to TRUE. In addition the + * -t option that's used to force stuff not recognized as status reports to stdout + * also tries to run as two processes (by setting splitme to TRUE). It will only + * work if the required code (ie. resetline() in ifdef.c) has been implemented + * for your Unix system. I've only tested the System V code. + * + * Code needed to support interactive mode has also been added, although again it's + * not as efficient as it could be. It depends on the system dependent procedures + * resetline() and setupstdin() (file ifdef.c) and for now is only guaranteed to + * work on System V. Can be requested using the -i option. + * + * Quiet mode (-q option) is also new, but was needed for some printers connected + * to RADIAN. If you're running in quiet mode no status requests will be sent to + * the printer while files are being transmitted (ie. in send()). + * + * The program expects to receive printer status lines that look like, + * + * %%[ status: idle; source: serial 25 ]%% + * %%[ status: waiting; source: serial 25 ]%% + * %%[ status: initializing; source: serial 25 ]%% + * %%[ status: busy; source: serial 25 ]%% + * %%[ status: printing; source: serial 25 ]%% + * %%[ status: PrinterError: out of paper; source: serial 25 ]%% + * %%[ status: PrinterError: no paper tray; source: serial 25 ]%% + * + * although this list isn't complete. Sending a '\024' (control T) character forces + * the return of a status report. PostScript errors detected on the printer result + * in the immediate transmission of special error messages that look like, + * + * %%[ Error: undefined; OffendingCommand: xxx ]%% + * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%% + * + * although we only use the Error and Flushing keywords. Finally conditions, like + * being out of paper, result in other messages being sent back from the printer + * over the communications line. Typical PrinterError messages look like, + * + * %%[ PrinterError: out of paper; source: serial 25 ]%% + * %%[ PrinterError: paper jam; source: serial 25 ]%% + * + * although we only use the PrinterError keyword rather than trying to recognize + * all possible printer errors. + * + * The implications of using one process and only flow controlling data going to + * the printer are obvious. Job transmission should be reliable, but there can be + * data loss in stuff sent back from the printer. Usually that only caused problems + * with jobs designed to run on the printer and return useful data back over the + * communications line. If that's the kind of job you're sending call postio with + * the -t option. That should force the program to split into separate read and + * write processes and everything not bracketed by "%%[ " and " ]%%" strings goes + * to stdout. In otherwords the data you're expecting should be separated from the + * status stuff that goes to the log file (or stderr). The -R2 option does almost + * the same thing (ie. separate read and write processes), but everything that + * comes back from the printer goes to the log file (stderr by default) and you'll + * have to separate your data from any printer messages. + * + * A typical command line might be, + * + * postio -l /dev/tty01 -b 9600 -L log file1 file2 + * + * where -l selects the line, -b sets the baud rate, and -L selects the printer + * log file. Since there's no default line, at least not right now, you'll always + * need to use the -l option, and if you don't choose a log file stderr will be + * used. If you have a program that will be returning data the command line might + * look like, + * + * postio -t -l/dev/tty01 -b9600 -Llog file >results + * + * Status stuff goes to file log while the data you're expecting back from the + * printer gets put in file results. + * + */ + +#include <stdio.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <errno.h> + +#include "ifdef.h" /* conditional compilation stuff */ +#include "gen.h" /* general purpose definitions */ +#include "postio.h" /* some special definitions */ + +char **argv; /* global so everyone can use them */ +int argc; + +char *prog_name = ""; /* really just for error messages */ +int x_stat = 0; /* program exit status */ +int debug = OFF; /* debug flag */ +int ignore = OFF; /* what's done for FATAL errors */ + +char *line = NULL; /* printer is on this tty line */ +short baudrate = BAUDRATE; /* and running at this baud rate */ +Baud baudtable[] = BAUDTABLE; /* converts strings to termio values */ + +int stopbits = 1; /* number of stop bits */ +int tostdout = FALSE; /* non-status stuff goes to stdout? */ +int quiet = FALSE; /* no status queries in send() if TRUE */ +int interactive = FALSE; /* interactive mode */ +char *postbegin = POSTBEGIN; /* preceeds all the input files */ +int useslowsend = FALSE; /* not recommended! */ +int sendctrlC = TRUE; /* interrupt with ctrl-C when BUSY */ +int window_size = -1; /* for Datakit - use -w */ + +char *block = NULL; /* input file buffer */ +int blocksize = BLOCKSIZE; /* and its size in bytes */ +int head = 0; /* block[head] is the next character */ +int tail = 0; /* one past the last byte in block[] */ + +int splitme = FALSE; /* into READ and WRITE processes if TRUE */ +int whatami = READWRITE; /* a READ or WRITE process - or both */ +int canread = TRUE; /* allow reads */ +int canwrite = TRUE; /* and writes if TRUE */ +int otherpid = -1; /* who gets signals if greater than 1 */ +int joinsig = SIGTRAP; /* reader gets this when writing is done */ +int writedone = FALSE; /* and then sets this to TRUE */ + +char mesg[MESGSIZE]; /* exactly what came back on ttyi */ +char sbuf[MESGSIZE]; /* for parsing the message */ +int next = 0; /* next character goes in mesg[next] */ +char *mesgptr = NULL; /* printer message starts here in mesg[] */ +char *endmesg = NULL; /* as far as readline() can go in mesg[] */ + +Status status[] = STATUS; /* for converting status strings */ +int nostatus = NOSTATUS; /* default getstatus() return value */ + +int currentstate = NOTCONNECTED; /* what's happening START, SEND, or DONE */ + +int ttyi = 0; /* input */ +int ttyo = 2; /* and output file descriptors */ + +FILE *fp_log = stderr; /* log file for stuff from the printer */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that manages input and output for PostScript printers. Can run + * as a single process or as separate read/write processes. What's done depends on + * the value assigned to splitme when split() is called. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* really just for error messages */ + + init_signals(); /* sets up interrupt handling */ + options(); /* get command line options */ + initialize(); /* must be done after options() */ + start(); /* make sure the printer is ready */ + split(); /* into read/write processes - maybe */ + arguments(); /* then send each input file */ + done(); /* wait until the printer is finished */ + cleanup(); /* make sure the write process stops */ + + exit(x_stat); /* everything probably went OK */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + + void interrupt(); /* handles them if we catch signals */ + +/* + * + * Makes sure we handle interrupts. The proper way to kill the program, if + * necessary, is to do a kill -15. That forces a call to interrupt(), which in + * turn tries to reset the printer and then exits with a non-zero status. If the + * program is running as two processes, sending SIGTERM to either the parent or + * child should clean things up. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_sig */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + char *optnames = "b:cil:qs:tw:B:L:P:R:SDI"; + + extern char *optarg; /* used by getopt() */ + extern int optind; + +/* + * + * Reads and processes the command line options. The -R2, -t, and -i options all + * force separate read and write processes by eventually setting splitme to TRUE + * (check initialize()). The -S option is not recommended and should only be used + * as a last resort! + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'b': /* baud rate string */ + baudrate = getbaud(optarg); + break; + + case 'c': /* no ctrl-C's */ + sendctrlC = FALSE; + break; + + case 'i': /* interactive mode */ + interactive = TRUE; + break; + + case 'l': /* printer line */ + line = optarg; + break; + + case 'q': /* no status queries - for RADIAN? */ + quiet = TRUE; + break; + + case 's': /* use 2 stop bits - for UNISON? */ + if ( (stopbits = atoi(optarg)) < 1 || stopbits > 2 ) + stopbits = 1; + break; + + case 't': /* non-status stuff goes to stdout */ + tostdout = TRUE; + break; + + case 'w': /* Datakit window size */ + window_size = atoi(optarg); + break; + + case 'B': /* set the job buffer size */ + if ( (blocksize = atoi(optarg)) <= 0 ) + blocksize = BLOCKSIZE; + break; + + case 'L': /* printer log file */ + if ( (fp_log = fopen(optarg, "w")) == NULL ) { + fp_log = stderr; + error(NON_FATAL, "can't open log file %s", optarg); + } /* End if */ + break; + + case 'P': /* initial PostScript code */ + postbegin = optarg; + break; + + case 'R': /* run as one or two processes */ + if ( atoi(optarg) == 2 ) + splitme = TRUE; + else splitme = FALSE; + break; + + case 'S': /* slow and kludged up version of send */ + useslowsend = TRUE; + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +getbaud(rate) + + char *rate; /* string representing the baud rate */ + +{ + + int i; /* for looking through baudtable[] */ + +/* + * + * Called from options() to convert a baud rate string into an appropriate termio + * value. *rate is looked up in baudtable[] and if it's found, the corresponding + * value is returned to the caller. + * + */ + + for ( i = 0; baudtable[i].rate != NULL; i++ ) + if ( strcmp(rate, baudtable[i].rate) == 0 ) + return(baudtable[i].val); + + error(FATAL, "don't recognize baud rate %s", rate); + +} /* End of getbaud */ + +/*****************************************************************************/ + +initialize() + +{ + +/* + * + * Initialization, a few checks, and a call to setupline() (file ifdef.c) to open + * and configure the communications line. Settings for interactive mode always + * take precedence. The setupstdin() call with an argument of 0 saves the current + * terminal settings if interactive mode has been requested - otherwise nothing's + * done. Unbuffering stdout (via the setbuf() call) isn't really needed on System V + * since it's flushed whenever terminal input is requested. It's more efficient if + * we buffer the stdout (on System V) but safer (for other versions of Unix) if we + * include the setbuf() call. + * + */ + + whatami = READWRITE; /* always run start() as one process */ + canread = canwrite = TRUE; + + if ( tostdout == TRUE ) /* force separate read/write processes */ + splitme = TRUE; + + if ( interactive == TRUE ) { /* interactive mode settings always win */ + quiet = FALSE; + tostdout = FALSE; + splitme = TRUE; + blocksize = 1; + postbegin = NULL; + useslowsend = FALSE; + nostatus = INTERACTIVE; + setbuf(stdout, NULL); + } /* End if */ + + if ( useslowsend == TRUE ) { /* last resort only - not recommended */ + quiet = FALSE; + splitme = FALSE; + if ( blocksize > 1024 ) /* don't send too much all at once */ + blocksize = 1024; + } /* End if */ + + if ( tostdout == TRUE && fp_log == stderr ) + fp_log = NULL; + + if ( line == NULL && (interactive == TRUE || tostdout == TRUE) ) + error(FATAL, "a printer line must be supplied - use the -l option"); + + if ( (block = malloc(blocksize)) == NULL ) + error(FATAL, "no memory"); + + endmesg = mesg + sizeof mesg - 2; /* one byte from last position in mesg */ + + setupline(); /* configure the communications line */ + setupstdin(0); /* save current stdin terminal settings */ + +} /* End of initialize */ + +/*****************************************************************************/ + +start() + +{ + +/* + * + * Tries to put the printer in the IDLE state before anything important is sent. + * Run as a single process no matter what has been assigned to splitme. Separate + * read and write processes, if requested, will be created after we're done here. + * + */ + + logit("printer startup\n"); + + currentstate = START; + clearline(); + + while ( 1 ) + switch ( getstatus(1) ) { + case IDLE: + case INTERACTIVE: + if ( postbegin != NULL && *postbegin != '\0' ) + Write(ttyo, postbegin, strlen(postbegin)); + clearline(); + return; + + case BUSY: + if ( sendctrlC == TRUE ) { + Write(ttyo, "\003", 1); + Rest(1); + } /* End if */ + break; + + case WAITING: + case ERROR: + case FLUSHING: + Write(ttyo, "\004", 1); + Rest(1); + break; + + case PRINTERERROR: + Rest(15); + break; + + case DISCONNECT: + error(FATAL, "Disconnected - printer may be offline"); + break; + + case ENDOFJOB: + case UNKNOWN: + clearline(); + break; + + default: + Rest(1); + break; + } /* End switch */ + +} /* End of start */ + +/*****************************************************************************/ + +split() + +{ + + int pid; + void interrupt(); + +/* + * + * If splitme is TRUE we fork a process, make the parent handle reading, and let + * the child take care of writing. resetline() (file ifdef.c) contains all the + * system dependent code needed to reset the communications line for separate + * read and write processes. For now it's expected to return TRUE or FALSE and + * that value controls whether we try the fork. I've only tested the two process + * stuff for System V. Other versions of resetline() may just be dummy procedures + * that always return FALSE. If the fork() failed previous versions continued as + * a single process, although the implementation wasn't quite right, but I've now + * decided to quit. The main reason is a Datakit channel may be configured to + * flow control data in both directions, and if we run postio over that channel + * as a single process we likely will end up in deadlock. + * + */ + + if ( splitme == TRUE ) + if ( resetline() == TRUE ) { + pid = getpid(); + signal(joinsig, interrupt); + if ( (otherpid = fork()) == -1 ) + error(FATAL, "can't fork"); + else if ( otherpid == 0 ) { + whatami = WRITE; + nostatus = WRITEPROCESS; + otherpid = pid; + setupstdin(1); + } else whatami = READ; + } else if ( interactive == TRUE || tostdout == TRUE ) + error(FATAL, "can't create two process - check resetline()"); + else error(NON_FATAL, "running as a single process - check resetline()"); + + canread = (whatami & READ) ? TRUE : FALSE; + canwrite = (whatami & WRITE) ? TRUE : FALSE; + +} /* End of split */ + +/*****************************************************************************/ + +arguments() + +{ + + int fd_in; /* next input file */ + +/* + * + * Makes sure all the non-option command line arguments are processed. If there + * aren't any arguments left when we get here we'll send stdin. Input files are + * only read and sent to the printer if canwrite is TRUE. Checking it here means + * we won't have to do it in send(). If interactive mode is TRUE we'll stay here + * forever sending stdin when we run out of files - exit with a break. Actually + * the loop is bogus and used at most once when we're in interactive mode because + * stdin is in a pseudo raw mode and the read() in readblock() should never see + * the end of file. + * + */ + + if ( canwrite == TRUE ) + do /* loop is for interactive mode */ + if ( argc < 1 ) + send(fileno(stdin), "pipe.end"); + else { + while ( argc > 0 ) { + if ( (fd_in = open(*argv, O_RDONLY)) == -1 ) + error(FATAL, "can't open %s", *argv); + send(fd_in, *argv); + close(fd_in); + argc--; + argv++; + } /* End while */ + } /* End else */ + while ( interactive == TRUE ); + +} /* End of arguments */ + +/*****************************************************************************/ + +send(fd_in, name) + + int fd_in; /* next input file */ + char *name; /* and it's pathname */ + +{ + +/* + * + * Sends file *name to the printer. There's nothing left here that depends on + * sending and receiving status reports, although it can be reassuring to know + * the printer is responding and processing our job. Only the writer gets here + * in the two process implementation, and in that case split() has reset nostatus + * to WRITEPROCESS and that's what getstatus() always returns. For now we accept + * the IDLE state and ENDOFJOB as legitimate and ignore the INITIALIZING state. + * + */ + + if ( interactive == FALSE ) + logit("sending file %s\n", name); + + currentstate = SEND; + + if ( useslowsend == TRUE ) { + slowsend(fd_in); + return; + } /* End if */ + + while ( readblock(fd_in) ) + switch ( getstatus(0) ) { + case IDLE: + case BUSY: + case WAITING: + case PRINTING: + case ENDOFJOB: + case PRINTERERROR: + case UNKNOWN: + case NOSTATUS: + case WRITEPROCESS: + case INTERACTIVE: + writeblock(); + break; + + case ERROR: + fprintf(stderr, "%s", mesg); /* for csw */ + error(USER_FATAL, "PostScript Error"); + break; + + case FLUSHING: + error(USER_FATAL, "Flushing Job"); + break; + + case DISCONNECT: + error(FATAL, "Disconnected - printer may be offline"); + break; + } /* End switch */ + +} /* End of send */ + +/*****************************************************************************/ + +done() + +{ + + int sleeptime = 15; /* for 'out of paper' etc. */ + +/* + * + * Tries to stay connected to the printer until we're reasonably sure the job is + * complete. It's the only way we can recover error messages or data generated by + * the PostScript program and returned over the communication line. Actually doing + * it correctly for all possible PostScript jobs is more difficult that it might + * seem. For example if we've sent several jobs, each with their own EOF mark, then + * waiting for ENDOFJOB won't guarantee all the jobs have completed. Even waiting + * for IDLE isn't good enough. Checking for the WAITING state after all the files + * have been sent and then sending an EOF may be the best approach, but even that + * won't work all the time - we could miss it or might not get there. Even sending + * our own special PostScript job after all the input files has it's own different + * set of problems, but probably could work (perhaps by printing a fake status + * message or just not timing out). Anyway it's probably not worth the trouble so + * for now we'll quit if writedone is TRUE and we get ENDOFJOB or IDLE. + * + * If we're running separate read and write processes the reader gets here after + * after split() while the writer goes to send() and only gets here after all the + * input files have been transmitted. When they're both here the writer sends the + * reader signal joinsig and that forces writedone to TRUE in the reader. At that + * point the reader can begin looking for an indication of the end of the job. + * The writer hangs around until the reader kills it (usually in cleanup()) sending + * occasional status requests. + * + */ + + if ( canwrite == TRUE ) + logit("waiting for end of job\n"); + + currentstate = DONE; + writedone = (whatami == READWRITE) ? TRUE : FALSE; + + while ( 1 ) { + switch ( getstatus(1) ) { + + case WRITEPROCESS: + if ( writedone == FALSE ) { + sendsignal(joinsig); + Write(ttyo, "\004", 1); + writedone = TRUE; + sleeptime = 1; + } /* End if */ + Rest(sleeptime++); + break; + + case WAITING: + Write(ttyo, "\004", 1); + Rest(1); + sleeptime = 15; + break; + + case IDLE: + case ENDOFJOB: + if ( writedone == TRUE ) { + logit("job complete\n"); + return; + } /* End if */ + break; + + case BUSY: + case PRINTING: + case INTERACTIVE: + sleeptime = 15; + break; + + case PRINTERERROR: + Rest(sleeptime++); + break; + + case ERROR: + fprintf(stderr, "%s", mesg); /* for csw */ + error(USER_FATAL, "PostScript Error"); + return; + + case FLUSHING: + error(USER_FATAL, "Flushing Job"); + return; + + case DISCONNECT: + error(FATAL, "Disconnected - printer may be offline"); + return; + + default: + Rest(1); + break; + } /* End switch */ + + if ( sleeptime > 60 ) + sleeptime = 60; + } /* End while */ + +} /* End of done */ + +/*****************************************************************************/ + +cleanup() + +{ + + int w; + +/* + * + * Only needed if we're running separate read and write processes. Makes sure the + * write process is killed after the read process has successfully finished with + * all the jobs. sendsignal() returns a -1 if there's nobody to signal so things + * work when we're running a single process. + * + */ + + while ( sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ; + +} /* End of cleanup */ + +/*****************************************************************************/ + +readblock(fd_in) + + int fd_in; /* current input file */ + +{ + + static long blocknum = 1; + +/* + * + * Fills the input buffer with the next block, provided we're all done with the + * last one. Blocks from fd_in are stored in array block[]. head is the index + * of the next byte in block[] that's supposed to go to the printer. tail points + * one past the last byte in the current block. head is adjusted in writeblock() + * after each successful write, while head and tail are reset here each time + * a new block is read. Returns the number of bytes left in the current block. + * Read errors cause the program to abort. The fake status message that's put out + * in quiet mode is only so you can look at the log file and know something's + * happening - take it out if you want. + * + */ + + if ( head >= tail ) { /* done with the last block */ + if ( (tail = read(fd_in, block, blocksize)) == -1 ) + error(FATAL, "error reading input file"); + if ( quiet == TRUE && tail > 0 ) /* put out a fake message? */ + logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++); + head = 0; + } /* End if */ + + return(tail - head); + +} /* End of readblock */ + +/*****************************************************************************/ + +writeblock() + +{ + + int count; /* bytes successfully written */ + +/* + * + * Called from send() when it's OK to send the next block to the printer. head + * is adjusted after the write, and the number of bytes that were successfully + * written is returned to the caller. + * + */ + + if ( (count = write(ttyo, &block[head], tail - head)) == -1 ) + error(FATAL, "error writing to %s", line); + else if ( count == 0 ) + error(FATAL, "printer appears to be offline"); + + head += count; + return(count); + +} /* End of writeblock */ + +/*****************************************************************************/ + +getstatus(t) + + int t; /* sleep time after sending '\024' */ + +{ + + int gotline = FALSE; /* value returned by readline() */ + int state = nostatus; /* representation of the current state */ + int mesgch; /* to restore mesg[] when tostdout == TRUE */ + + static int laststate = NOSTATUS; /* last state recognized */ + +/* + * + * Looks for things coming back from the printer on the communications line, parses + * complete lines retrieved by readline(), and returns an integer representation + * of the current printer status to the caller. If nothing was available a status + * request (control T) is sent to the printer and nostatus is returned to the + * caller (provided quiet isn't TRUE). Interactive mode either never returns from + * readline() or returns FALSE. + * + */ + + if ( canread == TRUE && (gotline = readline()) == TRUE ) { + state = parsemesg(); + if ( state != laststate || state == UNKNOWN || mesgptr != mesg || debug == ON ) + logit("%s", mesg); + + if ( tostdout == TRUE && currentstate != START ) { + mesgch = *mesgptr; + *mesgptr = '\0'; + fprintf(stdout, "%s", mesg); + fflush(stdout); + *mesgptr = mesgch; /* for ERROR in send() and done() */ + } /* End if */ + return(laststate = state); + } /* End if */ + + if ( (quiet == FALSE || currentstate != SEND) && + (tostdout == FALSE || currentstate == START) && interactive == FALSE ) { + if ( Write(ttyo, "\024", 1) != 1 ) + error(FATAL, "printer appears to be offline"); + if ( t > 0 ) Rest(t); + } /* End if */ + + return(nostatus); + +} /* End of getstatus */ + +/*****************************************************************************/ + +parsemesg() + +{ + + char *e; /* end of printer message in mesg[] */ + char *key, *val; /* keyword/value strings in sbuf[] */ + char *p; /* for converting to lower case etc. */ + int i; /* where *key was found in status[] */ + +/* + * + * Parsing the lines that readline() stores in mesg[] is messy, and what's done + * here isn't completely correct nor as fast as it could be. The general format + * of lines that come back from the printer (assuming no data loss) is: + * + * str%%[ key: val; key: val; key: val ]%%\n + * + * where str can be most anything not containing a newline and printer reports + * (eg. status or error messages) are bracketed by "%%[ " and " ]%%" strings and + * end with a newline. Usually we'll have the string or printer report but not + * both. For most jobs the leading string will be empty, but could be anything + * generated on a printer and returned over the communications line using the + * PostScript print operator. I'll assume PostScript jobs are well behaved and + * never bracket their messages with "%%[ " and " ]%%" strings that delimit status + * or error messages. + * + * Printer reports consist of one or more key/val pairs, and what we're interested + * in (status or error indications) may not be the first pair in the list. In + * addition we'll sometimes want the value associated with a keyword (eg. when + * key = status) and other times we'll want the keyword (eg. when key = Error or + * Flushing). The last pair isn't terminated by a semicolon and a value string + * often contains many space separated words and it can even include colons in + * meaningful places. I've also decided to continue converting things to lower + * case before doing the lookup in status[]. The isupper() test is for Berkeley + * systems. + * + */ + + if ( *(mesgptr = find("%%[ ", mesg)) != '\0' && *(e = find(" ]%%", mesgptr+4)) != '\0' ) { + strcpy(sbuf, mesgptr+4); /* don't change mesg[] */ + sbuf[e-mesgptr-4] = '\0'; /* ignore the trailing " ]%%" */ + + for ( key = strtok(sbuf, " :"); key != NULL; key = strtok(NULL, " :") ) { + if ( (val = strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0 ) + key = val; + + for ( ; *key == ' '; key++ ) ; /* skip any leading spaces */ + for ( p = key; *p; p++ ) /* convert to lower case */ + if ( *p == ':' ) { + *p = '\0'; + break; + } else if ( isupper(*p) ) *p = tolower(*p); + + for ( i = 0; status[i].state != NULL; i++ ) + if ( strcmp(status[i].state, key) == 0 ) + return(status[i].val); + } /* End for */ + } else if ( strcmp(mesg, "CONVERSATION ENDED.\n") == 0 ) + return(DISCONNECT); + + return(mesgptr == '\0' ? nostatus : UNKNOWN); + +} /* End of parsemesg */ + +/*****************************************************************************/ + +char *find(str1, str2) + + char *str1; /* look for this string */ + char *str2; /* in this one */ + +{ + + char *s1, *s2; /* can't change str1 or str2 too fast */ + +/* + * + * Looks for *str1 in string *str2. Returns a pointer to the start of the substring + * if it's found or to the end of string str2 otherwise. + * + */ + + for ( ; *str2 != '\0'; str2++ ) { + for ( s1 = str1, s2 = str2; *s1 != '\0' && *s1 == *s2; s1++, s2++ ) ; + if ( *s1 == '\0' ) + break; + } /* End for */ + + return(str2); + +} /* End of find */ + +/*****************************************************************************/ + +clearline() + +{ + +/* + * + * Reads characters from the input line until nothing's left. Don't do anything if + * we're currently running separate read and write processes. + * + */ + + if ( whatami == READWRITE ) + while ( readline() != FALSE ) ; + +} /* End of clearline */ + +/*****************************************************************************/ + +sendsignal(sig) + + int sig; /* this goes to the other process */ + +{ + +/* + * + * Sends signal sig to the other process if we're running as separate read and + * write processes. Returns the result of the kill if there's someone else to + * signal or -1 if we're running alone. + * + */ + + if ( whatami != READWRITE && otherpid > 1 ) + return(kill(otherpid, sig)); + + return(-1); + +} /* End of sendsignal */ + +/*****************************************************************************/ + +void interrupt(sig) + + int sig; /* signal that we caught */ + +{ + +/* + * + * Caught a signal - all except joinsig cause the program to quit. joinsig is the + * signal sent by the writer to the reader after all the jobs have been transmitted. + * Used to tell the read process when it can start looking for the end of the job. + * + */ + + signal(sig, SIG_IGN); + + if ( sig != joinsig ) { + x_stat |= FATAL; + if ( canread == TRUE ) + if ( interactive == FALSE ) + error(NON_FATAL, "signal %d abort", sig); + else error(NON_FATAL, "quitting"); + quit(sig); + } /* End if */ + + writedone = TRUE; + signal(joinsig, interrupt); + +} /* End of interrupt */ + +/*****************************************************************************/ + +logit(mesg, a1, a2, a3) + + char *mesg; /* control string */ + unsigned a1, a2, a3; /* and possible arguments */ + +{ + +/* + * + * Simple routine that's used to write a message to the log file. + * + */ + + if ( mesg != NULL && fp_log != NULL ) { + fprintf(fp_log, mesg, a1, a2, a3); + fflush(fp_log); + } /* End if */ + +} /* End of logit */ + +/*****************************************************************************/ + +error(kind, mesg, a1, a2, a3) + + int kind; /* FATAL or NON_FATAL error */ + char *mesg; /* error message control string */ + unsigned a1, a2, a3; /* control string arguments */ + +{ + + FILE *fp_err; + +/* + * + * Called when we've run into some kind of program error. First *mesg is printed + * using the control string arguments a?. If kind is FATAL and we're not ignoring + * errors the program will be terminated. If mesg is NULL or *mesg is the NULL + * string nothing will be printed. + * + */ + + fp_err = (fp_log != NULL) ? fp_log : stderr; + + if ( mesg != NULL && *mesg != '\0' ) { + fprintf(fp_err, "%s: ", prog_name); + fprintf(fp_err, mesg, a1, a2, a3); + putc('\n', fp_err); + } /* End if */ + + x_stat |= kind; + + if ( kind != NON_FATAL && ignore == OFF ) + quit(SIGTERM); + +} /* End of error */ + +/*****************************************************************************/ + +quit(sig) + + int sig; + +{ + + int w; + +/* + * + * Makes sure everything is properly cleaned up if there's a signal or FATAL error + * that should cause the program to terminate. The sleep by the write process is + * to help give the reset sequence a chance to reach the printer before we break + * the connection - primarily for printers connected to Datakit. There's a very + * slight chance the reset sequence that's sent to the printer could get us stuck + * here. Simplest solution is don't bother to send it - everything works without it. + * Flushing ttyo would be better, but means yet another system dependent procedure + * in ifdef.c! I'll leave things be for now. + * + * Obscure problem on PS-810 turbos says wait a bit after sending an interrupt. + * Seem to remember the printer getting into a bad state immediately after the + * top was opened when the toner light was on. A sleep after sending the ctrl-C + * seemed to fix things. + * + */ + + signal(sig, SIG_IGN); + ignore = ON; + + while ( sendsignal(sig) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ; + + setupstdin(2); + + if ( currentstate != NOTCONNECTED ) { + if ( sendctrlC == TRUE ) { + Write(ttyo, "\003", 1); + Rest(1); /* PS-810 turbo problem?? */ + } /* End if */ + Write(ttyo, "\004", 1); + } /* End if */ + + alarm(0); /* prevents sleep() loop on V9 systems */ + Rest(2); + + exit(x_stat); + +} /* End of quit */ + +/*****************************************************************************/ + +Rest(t) + + int t; + +{ + +/* + * + * Used to replace sleep() calls. Only needed if we're running the program as + * a read and write process and don't want to have the read process sleep. Most + * sleeps are in the code because of the non-blocking read used by the single + * process implementation. Probably should be a macro. + * + */ + + if ( t > 0 && canwrite == TRUE ) + sleep(t); + +} /* End of Rest */ + +/*****************************************************************************/ + +Read(fd, buf, n) + + int fd; + char *buf; + int n; + +{ + + int count; + +/* + * + * Used to replace some of the read() calls. Only needed if we're running separate + * read and write processes. Should only be used to replace read calls on ttyi. + * Always returns 0 to the caller if the process doesn't have its READ flag set. + * Probably should be a macro. + * + */ + + if ( canread == TRUE ) { + if ( (count = read(fd, buf, n)) == -1 && errno == EINTR ) + count = 0; + } else count = 0; + + return(count); + +} /* End of Read */ + +/*****************************************************************************/ + +Write(fd, buf, n) + + int fd; + char *buf; + int n; + +{ + + int count; + +/* + * + * Used to replace some of the write() calls. Again only needed if we're running + * separate read and write processes. Should only be used to replace write calls + * on ttyo. Always returns n to the caller if the process doesn't have its WRITE + * flag set. Should also probably be a macro. + * + */ + + if ( canwrite == TRUE ) { + if ( (count = write(fd, buf, n)) == -1 && errno == EINTR ) + count = n; + } else count = n; + + return(count); + +} /* End of Write */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postio/postio.h b/sys/src/cmd/postscript/postio/postio.h new file mode 100755 index 000000000..c0ac6ad18 --- /dev/null +++ b/sys/src/cmd/postscript/postio/postio.h @@ -0,0 +1,209 @@ +/* + * + * POSTBEGIN, if it's not NULL, is some PostScript code that's sent to the printer + * before any of the input files. It's not terribly important since the same thing + * can be accomplished in other ways, but this approach is convenient. POSTBEGIN + * is initialized so as to disable job timeouts. The string can also be set on the + * command line using the -P option. + * + */ + +#define POSTBEGIN "statusdict /waittimeout 0 put\n" + +/* + * + * The following help determine where postio is when it's running - either in the + * START, SEND, or DONE states. Primarily controls what's done in getstatus(). + * RADIAN occasionally had problems with two way conversations. Anyway this stuff + * can be used to prevent status queries while we're transmitting a job. Enabled + * by the -q option. + * + */ + +#define NOTCONNECTED 0 +#define START 1 +#define SEND 2 +#define DONE 3 + +/* + * + * Previous versions of postio only ran as a single process. That was (and still + * is) convenient, but meant we could only flow control one direction. Data coming + * back from the printer occasionally got lost, but that didn't often hurt (except + * for lost error messages). Anyway I've added code that lets you split the program + * into separate read and write processes, thereby helping to prevent data loss in + * both directions. It should be particularly useful when you're sending a job that + * you expect will be returning useful data over the communications line. + * + * The next three definitions control what's done with data on communications line. + * The READ flag means the line can be read, while the WRITE flag means it can be + * written. When we're running as a single process both flags are set. I tried to + * overlay the separate read/write process code on what was there and working for + * one process. The implementation isn't as good as it could be, but should be + * safe. The single process version still works, and remains the default. + * + */ + +#define READ 1 +#define WRITE 2 +#define READWRITE 3 + +/* + * + * Messages generated on the printer and returned over the communications line + * look like, + * + * %%[ status: idle; source: serial 25 ]%% + * %%[ status: waiting; source: serial 25 ]%% + * %%[ status: initializing; source: serial 25 ]%% + * %%[ status: busy; source: serial 25 ]%% + * %%[ status: printing; source: serial 25 ]%% + * %%[ status: PrinterError: out of paper; source: serial 25 ]%% + * %%[ status: PrinterError: no paper tray; source: serial 25 ]%% + * + * %%[ PrinterError: out of paper; source: serial 25 ]%% + * %%[ PrinterError: no paper tray; source: serial 25 ]%% + * + * %%[ Error: undefined; OffendingCommand: xxx ]%% + * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%% + * + * although the list isn't meant to be complete. + * + * The following constants are used to classify the recognized printer states. + * readline() reads complete lines from ttyi and stores them in array mesg[]. + * getstatus() looks for the "%%[ " and " ]%%" delimiters that bracket printer + * messages and if found it tries to parse the enclosed message. After the lookup + * one of the following numbers is returned as an indication of the existence or + * content of the printer message. The return value is used in start(), send(), + * and done() to figure out what's happening and what can be done next. + * + */ + +#define BUSY 0 /* processing data already sent */ +#define WAITING 1 /* printer wants more data */ +#define PRINTING 2 /* printing a page */ +#define IDLE 3 /* ready to start the next job */ +#define ENDOFJOB 4 /* readline() builds this up on EOF */ +#define PRINTERERROR 5 /* PrinterError - eg. out of paper */ +#define ERROR 6 /* some kind of PostScript error */ +#define FLUSHING 7 /* throwing out the rest of the job */ +#define INITIALIZING 8 /* printer is booting */ +#define DISCONNECT 9 /* from Datakit! */ +#define UNKNOWN 10 /* in case we missed anything */ +#define NOSTATUS 11 /* no response from the printer */ + +#define WRITEPROCESS 12 /* dummy states for write process */ +#define INTERACTIVE 13 /* and interactive mode */ + +/* + * + * An array of type Status is used, in getstatus(), to figure out the printer's + * current state. Just helps convert strings representing the current state into + * integer codes that other routines use. + * + */ + +typedef struct { + char *state; /* printer's current status */ + int val; /* value returned by getstatus() */ +} Status; + +/* + * + * STATUS is used to initialize an array of type Status that translates the ASCII + * strings returned by the printer into appropriate codes that can be used later + * on in the program. getstatus() converts characters to lower case, so if you + * add any entries make them lower case and put them in before the UNKNOWN entry. + * The lookup terminates when we get a match or when an entry with a NULL state + * is found. + * + */ + +#define STATUS \ + \ + { \ + "busy", BUSY, \ + "waiting", WAITING, \ + "printing", PRINTING, \ + "idle", IDLE, \ + "endofjob", ENDOFJOB, \ + "printererror", PRINTERERROR, \ + "error", ERROR, \ + "flushing", FLUSHING, \ + "initializing", INITIALIZING, \ + NULL, UNKNOWN \ + } + +/* + * + * The baud rate can be set on the command line using the -b option. If you omit + * it BAUDRATE will be used. + * + */ + +#define BAUDRATE B9600 + +/* + * + * An array of type Baud is used, in routine getbaud(), to translate ASCII strings + * into termio values that represent the requested baud rate. + * + */ + +typedef struct { + char *rate; /* string identifying the baud rate */ + short val; /* and its termio.h value */ +} Baud; + +/* + * + * BAUDTABLE initializes the array that's used to translate baud rate requests + * into termio values. It needs to end with an entry that has NULL assigned to + * the rate field. + * + */ + +#define BAUDTABLE \ + \ + { \ + "9600", B9600, \ + "B9600", B9600, \ + "19200", EXTA, \ + "19.2", EXTA, \ + "B19200", EXTA, \ + "EXTA", EXTA, \ + "1200", B1200, \ + "B1200", B1200, \ + "2400", B2400, \ + "B2400", B2400, \ + "B4800", B4800, \ + "4800", B4800, \ + "38400", EXTB, \ + "38.4", EXTB, \ + "B38400", EXTB, \ + "EXTB", EXTB, \ + NULL, B9600 \ + } + +/* + * + * A few miscellaneous definitions. BLOCKSIZE is the default size of the buffer + * used for reading the input files (changed with the -B option). MESGSIZE is the + * size of the character array used to store printer status lines - don't make it + * too small! + * + */ + +#define BLOCKSIZE 2048 +#define MESGSIZE 512 + +/* + * + * Some of the non-integer valued functions used in postio.c. + * + */ + +char *find(); + +char *malloc(); +char *strtok(); diff --git a/sys/src/cmd/postscript/postio/postio.mk b/sys/src/cmd/postscript/postio/postio.mk new file mode 100755 index 000000000..6e17273fd --- /dev/null +++ b/sys/src/cmd/postscript/postio/postio.mk @@ -0,0 +1,109 @@ +MAKE=/bin/make +MAKEFILE=postio.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +DKLIB=-ldk +DKHOST=FALSE +DKSTREAMS=FALSE + +# +# Need dk.h and libdk.a for Datakit support on System V. We recommend you put +# them in standard places. If it's not possible define DKHOSTDIR (below) and +# try uncommenting the following lines: +# +# DKHOSTDIR=/usr +# CFLAGS=$(CFLGS) -D$(SYSTEM) -I$(COMMONDIR) -I$(DKHOSTDIR)/include +# EXTRA=-Wl,-L$(DKHOSTDIR)/lib +# + +HFILES=postio.h\ + ifdef.h\ + $(COMMONDIR)/gen.h + +OFILES=postio.o\ + ifdef.o\ + slowsend.o + +all : postio + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + cp postio $(POSTBIN)/postio + @chmod 755 $(POSTBIN)/postio + @chgrp $(GROUP) $(POSTBIN)/postio + @chown $(OWNER) $(POSTBIN)/postio + cp postio.1 $(MAN1DIR)/postio.1 + @chmod 644 $(MAN1DIR)/postio.1 + @chgrp $(GROUP) $(MAN1DIR)/postio.1 + @chown $(OWNER) $(MAN1DIR)/postio.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postio + +postio :: + @CFLAGS="$(CFLAGS)"; export CFLAGS; \ + DKLIB=" "; export DKLIB; \ + if [ "$(SYSTEM)" != V9 ]; \ + then \ + if [ "$(DKHOST)" = TRUE ]; then \ + if [ "$(DKSTREAMS)" != FALSE ]; then \ + if [ "$(DKSTREAMS)" = TRUE ]; \ + then CFLAGS="$$CFLAGS -DDKSTREAMS=\\\"dknetty\\\""; \ + else CFLAGS="$$CFLAGS -DDKSTREAMS=\\\"$(DKSTREAMS)\\\""; \ + fi; \ + fi; \ + CFLAGS="$$CFLAGS -DDKHOST"; export CFLAGS; \ + DKLIB=-ldk; export DKLIB; \ + SYSTEM=SYSV; export SYSTEM; \ + fi; \ + else DKLIB=-lipc; export DKLIB; \ + fi; \ + CFLAGS="$$CFLAGS -D$$SYSTEM"; export CFLAGS; \ + $(MAKE) -e -f $@.mk compile + +compile : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postio $(OFILES) $(EXTRA) $(DKLIB) + +postio.o : $(HFILES) +slowsend.o : postio.h $(COMMONDIR)/gen.h +ifdef.o : ifdef.h $(COMMONDIR)/gen.h + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^DKLIB=.*'DKLIB=$(DKLIB)'" \ + -e "s'^DKHOST=.*'DKHOST=$(DKHOST)'" \ + -e "s'^DKSTREAMS=.*'DKSTREAMS=$(DKSTREAMS)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE) + diff --git a/sys/src/cmd/postscript/postio/postio.mk.old b/sys/src/cmd/postscript/postio/postio.mk.old new file mode 100755 index 000000000..e5469869a --- /dev/null +++ b/sys/src/cmd/postscript/postio/postio.mk.old @@ -0,0 +1,84 @@ +MAKE=/bin/make +MAKEFILE=postio.mk + +SYSTEM=V9 +VERSION=3.3.1 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript + +COMMONDIR=../common + +DKLIB=-lipc +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -D$(SYSTEM) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +# +# Need dk.h and libdk.a for Datakit support on System V. We recommend you put +# them in standard places. If it's not possible define DKHOSTDIR (below) and +# try uncommenting the following lines: +# +# DKHOSTDIR=/usr +# CFLAGS=$(CFLGS) -D$(SYSTEM) -I$(COMMONDIR) -I$(DKHOSTDIR)/include +# EXTRA=-Wl,-L$(DKHOSTDIR)/lib +# + +HFILES=postio.h\ + ifdef.h\ + $(COMMONDIR)/gen.h + +OFILES=postio.o\ + ifdef.o\ + slowsend.o + +all : postio + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + cp postio $(POSTBIN)/postio + @chmod 755 $(POSTBIN)/postio + @chgrp $(GROUP) $(POSTBIN)/postio + @chown $(OWNER) $(POSTBIN)/postio + cp postio.1 $(MAN1DIR)/postio.1 + @chmod 644 $(MAN1DIR)/postio.1 + @chgrp $(GROUP) $(MAN1DIR)/postio.1 + @chown $(OWNER) $(MAN1DIR)/postio.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postio + +postio : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postio $(OFILES) $(EXTRA) $(DKLIB) + +postio.o : $(HFILES) +slowsend.o : postio.h $(COMMONDIR)/gen.h +ifdef.o : ifdef.h $(COMMONDIR)/gen.h + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^CFLGS=.*'CFLGS=$(CFLGS)'" \ + -e "s'^DKLIB=.*'DKLIB=$(DKLIB)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE) + diff --git a/sys/src/cmd/postscript/postio/slowsend.c b/sys/src/cmd/postscript/postio/slowsend.c new file mode 100755 index 000000000..dbe8ca874 --- /dev/null +++ b/sys/src/cmd/postscript/postio/slowsend.c @@ -0,0 +1,121 @@ +/* + * + * Stuff that slows the transmission of jobs to PostScript printers. ONLY use it + * if you appear to be having trouble with flow control. The idea is simple - only + * send a significant amount of data when we're certain the printer is in the + * WAITING state. Depends on receiving status messages and only works when the + * program is run as a single process. What's done should stop printer generated + * XOFFs - provided our input buffer (ie. blocksize) is sufficiently small. Was + * originally included in the postio.tmp directory, but can now be requested with + * the -S option. Considered eliminating this code, but some printers still depend + * on it. In particular Datakit connections made using Datakit PVCs and DACUs seem + * to have the most problems. Much of the new stuff that was added can't work when + * you use this code and will be automatically disabled. + * + */ + +#include <stdio.h> + +#include "gen.h" +#include "postio.h" + +extern char *block; +extern int blocksize; +extern int head; +extern int tail; +extern char *line; +extern char mesg[]; +extern int ttyo; + +/*****************************************************************************/ + +slowsend(fd_in) + + int fd_in; /* next input file */ + +{ + +/* + * + * A slow version of send() that's very careful about when data is sent to the + * printer. Should help prevent overflowing the printer's input buffer, provided + * blocksize is sufficiently small (1024 should be safe). It's a totally kludged + * up routine that should ONLY be used if you have constant transmission problems. + * There's really no way it will be able to drive a printer much faster that about + * six pages a minute, even for the simplest jobs. Get it by using the -S option. + * + */ + + while ( readblock(fd_in) ) + switch ( getstatus(0) ) { + case WAITING: + writeblock(blocksize); + break; + + case BUSY: + case IDLE: + case PRINTING: + writeblock(30); + break; + + case NOSTATUS: + case UNKNOWN: + break; + + case PRINTERERROR: + sleep(30); + break; + + case ERROR: + fprintf(stderr, "%s", mesg); /* for csw */ + error(FATAL, "PostScript Error"); + break; + + case FLUSHING: + error(FATAL, "Flushing Job"); + break; + + case DISCONNECT: + error(FATAL, "Disconnected - printer may be offline"); + break; + + default: + sleep(2); + break; + } /* End switch */ + +} /* End of send */ + +/*****************************************************************************/ + +static writeblock(num) + + int num; /* most bytes we'll write */ + +{ + + int count; /* bytes successfully written */ + +/* + * + * Called from send() when it's OK to send the next block to the printer. head + * is adjusted after the write, and the number of bytes that were successfully + * written is returned to the caller. + * + */ + + if ( num > tail - head ) + num = tail - head; + + if ( (count = write(ttyo, &block[head], num)) == -1 ) + error(FATAL, "error writing to %s", line); + else if ( count == 0 ) + error(FATAL, "printer appears to be offline"); + + head += count; + return(count); + +} /* End of writeblock */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postmd/README b/sys/src/cmd/postscript/postmd/README new file mode 100755 index 000000000..43433c360 --- /dev/null +++ b/sys/src/cmd/postscript/postmd/README @@ -0,0 +1,23 @@ + +A program that displays a matrix as a gray scale image on PostScript +printers. May be useful if you have a large matrix and want a simple +way to look for patterns. Expect a 600x600 matrix is an optimistic +upper limit on a 300 dpi printers using 5 shades of gray and 8.5x11 +inch paper. + +Matrix elements are a series of floating point numbers arranged in +the input file in row major order. By default each matrix is assumed +to be square and the number of rows (and columns) is set to the square +root of the number of elements in the input file. White space, including +newlines, is not used to determine the matrix dimensions. Each matrix +element is mapped into an integer in the range 0 to 255 (254 by default) +and PostScript's image operator maps that integer into a gray scale +appropriate for the printer. + +The mapping from floating point matrix elements to integers is controlled +by an interval list and grayscale map. The default interval list is +"-1,0,1" which partitions the real line into 7 regions. The default +grayscale map gets darker as the regions move from left to right along +the real line. The -i option changes the interval list and the -g option +modifies the grayscale mapping. Check the man page for more details. + diff --git a/sys/src/cmd/postscript/postmd/mkfile b/sys/src/cmd/postscript/postmd/mkfile new file mode 100755 index 000000000..0b9cf9872 --- /dev/null +++ b/sys/src/cmd/postscript/postmd/mkfile @@ -0,0 +1,61 @@ +BUILTINS= +</$objtype/mkfile +MAKE=mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/sys/lib/postscript/bin +POSTLIB=$ROOT/sys/lib/postscript/prologues + +COMMONDIR=../common + +CC=pcc +LD=pcc + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B +LDFLAGS= + +all :V: $O.out + +install :V: $POSTBIN/$objtype/postmd $POSTLIB/postmd.ps $MAN1DIR/postmd.1 + +installall :V: + for(objtype in $CPUS) { \ + $MAKE 'MAKE=$MAKE' \ + 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \ + 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \ + 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \ + 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \ + 'ROUNDPAGE=$ROUNDPAGE' \ + 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \ + install \ + } + +clean :V: + rm -f *.$O + +clobber :V: clean + rm -f $O.out + +$POSTBIN/$objtype/postmd : $O.out + cp $prereq $target + +$POSTLIB/postmd.ps : postmd.ps + cp $prereq $target + +$MAN1DIR/postmd.1 : postmd.1 + cp $prereq $target + +$O.out : postmd.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/request.$O $COMMONDIR/tempnam.$O $COMMONDIR/getopt.$O + $LD $LDFLAGS $prereq + +postmd.o : postmd.h $COMMONDIR/comments.h $COMMONDIR/ext.h $COMMONDIR/gen.h $COMMONDIR/path.h + +%.$O: %.c + $CC $CFLAGS $stem.c + +common :V: + cd $COMMONDIR; $MAKE diff --git a/sys/src/cmd/postscript/postmd/postmd.1 b/sys/src/cmd/postscript/postmd/postmd.1 new file mode 100755 index 000000000..fb67d969e --- /dev/null +++ b/sys/src/cmd/postscript/postmd/postmd.1 @@ -0,0 +1,330 @@ +.ds dQ /usr/lib/postscript +.TH POSTMD 1 "DWB 3.2" +.SH NAME +.B postmd +\- matrix display program for PostScript printers +.SH SYNOPSIS +\*(mBpostmd\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B postmd +reads a series of floating point numbers from +.IR files , +translates them into a PostScript gray scale image, +and writes the results on the standard output. +In a typical application the numbers might be +the elements of a large matrix, +written in row major order, +while the printed image could help locate +patterns in the matrix. +If no +.I files +are specified, or if +.OP \- +is one of the input +.IR files , +the standard input is read. +The following +.I options +are understood: +.TP 0.75i +.OP \-b num +Pack the bitmap in the output file using +.I num +byte patterns. +A value of 0 turns off all packing of the output file. +By default +.I num +is 6. +.TP +.OP \-c num +Print +.I num +copies of each page. +By default only one copy is printed. +.TP +.OP \-d dimen +Sets the default matrix dimensions for all input +.I files +to +.IR dimen . +The +.I dimen +string can be given as rows or rows\^\(mu\^columns. +If columns is omitted it will be set to rows. +By default +.B postmd +assumes each matrix is square and sets the number of rows +and columns to the square root of the number of elements in +each input file. +.TP +.OP \-g list +.I list +is a comma- or space-separated string of integers, each lying between +0 and 255 inclusive, +that assigns PostScript gray scales to the regions of the real line +selected by the +.OP \-i +option. +255 corresponds to white and 0 to black. +.B postmd +assigns a default gray scale that omits white (i.e., 255) and gets +darker as the regions move from left to right along the real line. +.TP +.OP \-i list +.I list +is a comma- or space-separated string of +.I N +floating point numbers that +partition the real line into +.RI 2 N +1 +regions. +The +.I list +must be given in increasing numerical order. +The partitions are used to map floating point numbers read from the input +.I files +into gray scale integers that are assigned automatically by +.B postmd +or arbitrarily selected using the +.OP \-g +option. +The default interval +.I list +is ``\*(mB\-1,0,1\fP'' which partions the real line into 7 regions. +.TP +.OP \-m num +Magnify each logical page by the factor +.IR num . +Pages are scaled uniformly about the origin, +which by default is located at the center of +each page. +The default magnification is 1.0. +.TP +.OP \-n num +Print +.I num +logical pages on each piece of paper, +where +.I num +can be any positive integer. +By default +.I num +is set to 1. +.TP +.OP \-o list +Print pages whose numbers are given in the comma separated +.IR list . +The list contains single numbers +.I N +and ranges +.IR N1\-\|N2 . +A missing +.I N1 +means the lowest numbered page, a missing +.I N2 +means the highest. +.TP +.OP \-p mode +Print +.I files +in either \*(mBportrait\fP or \*(mBlandscape\fP +.IR mode . +Only the first character of +.I mode +is significant. +The default +.I mode +is \*(mBportrait\fP. +.TP +.OP \-w window +.I window +is a comma- or space-separated list of four positive integers that +select the upper left and lower right corners of a submatrix from +each of the input +.IR files . +Row and column indices start at 1 in the upper left corner and the +numbers in the input +.I files +are assumed to be written in row major order. +By default the entire matrix is displayed. +.TP +.OP \-x num +Translate the origin +.I num +inches along the positive x axis. +The default +coordinate system has the origin fixed at the +center of the page, with positive +x to the right and positive y up the page. +Positive +.I num +moves everything right. +The default offset is 0 inches. +.TP +.OP \-y num +Translate the origin +.I num +inches along the positive y axis. +Positive +.I num +moves everything up the page. +The default offset is 0. +.TP +.OP \-E name +Set the character encoding for text fonts to +.IR name . +Requesting +.I name +means include file +.MI \*(dQ/ name .enc \f1. +A nonexistent encoding file is silently ignored. +The default selects file +.MR \*(dQ/Default.enc . +.TP +.OP \-L file +Use +.I file +as the PostScript prologue. +.br +The default is +.MR \*(dQ/postmd.ps . +.PP +Three options allow insertion of arbitrary PostScript +at controlled points in the translation process: +.TP 0.75i +.OP \-C file +Copy +.I file +to the output file; +.I file +must contain legitimate PostScript. +.TP +.OP \-P string +Include +.I string +in the output file; +.I string +must be legitimate PostScript. +.TP +.OP \-R action +Requests special +.I action +(e.g., +.MR manualfeed ) +on a per page or global basis. +The +.I action +string can be given as +.IR request , +.IM request : page\f1\|, +or +.IM request : page : file\f1\|. +If +.I page +is omitted or given as 0, the request +applies to all pages. +If +.I file +is omitted, the request +lookup is done in +.MR \*(dQ/ps.requests . +.PP +Only one matrix is displayed on each logical page, +and each of the input +.I files +must contain complete descriptions of exactly one matrix. +Matrix elements are floating point numbers arranged in row major order in +each input file. +White space, including newlines, is not used to determine matrix +dimensions. +By default +.B postmd +assumes each matrix is square and sets the number of rows and columns +to the square root of the number of elements in the input file. +Supplying default dimensions on the command line using the +.OP \-d +option overrides this default behavior, and in that case the +dimensions apply to all input +.IR files . +.PP +An optional header can be supplied with each input file and is used +to set the matrix dimensions, the partition of the real line, the gray scale +map, and a window into the matrix. +The header consists of keyword/value pairs, each on a separate line. +It begins on the first line of each input file and ends with the +first unrecognized string, which should be the first matrix element. +Values set in the header take precedence, but only apply to the +current input file. +Recognized header keywords are +.MR dimension , +.MR interval , +.MR grayscale , +and +.MR window . +The syntax of the value string that follows each keyword parallels what is +accepted by the +.OP \-d , +.OP \-i , +.OP \-g , +and +.OP \-w +options. +.SH EXAMPLES +For example, suppose +.I file +initially contains the 1000 numbers +in a 20\(mu50 matrix. +Then the command line: +.EX +postmd -d20x50 -i"-100 100" -g0,128,254,128,0 \f2file +.EE +and prepending the header, +.EX +dimension 20x50 +interval -100.0 .100e+3 +grayscale 0 128 254 128 0 +.EE +to +.I file +and typing the command line: +.EX +postmd \f2file +.EE +produce exactly the same output. +The interval list partitions the real line into five regions and +the gray scale list maps numbers less than \-100 or greater than 100 +into 0 (i.e., black), numbers equal to \-100 or 100 into 128 +(i.e., 50 percent +black), and numbers between \-100 and 100 into 254 (i.e., almost white). +.SH DIAGNOSTICS +A 0 exit status is returned if +.I files +were successfully processed. +.SH WARNINGS +The largest matrix that can be adequately displayed is a function +of the interval and gray scale lists, the printer resolution, +and the paper size. +A 600\(mu600 matrix is an optimistic upper bound for a two element interval +list (i.e. five regions) using 8.5\(mu11 inch paper on a 300 dpi printer. +.PP +Using white (i.e., 255) in a gray scale list is not recommended and will not +show up in the legend and bar graph that +.B postmd +displays below each image. +.SH FILES +.MW \*(dQ/postmd.ps +.br +.MW \*(dQ/forms.ps +.br +.MW \*(dQ/ps.requests +.SH SEE ALSO +.BR dpost (1), +.BR postdaisy (1), +.BR postdmd (1), +.BR postio (1), +.BR postprint (1), +.BR postreverse (1), +.BR posttek (1), +.BR psencoding (1) diff --git a/sys/src/cmd/postscript/postmd/postmd.c b/sys/src/cmd/postscript/postmd/postmd.c new file mode 100755 index 000000000..01df4b43d --- /dev/null +++ b/sys/src/cmd/postscript/postmd/postmd.c @@ -0,0 +1,1157 @@ +/* + * + * postmd - matrix display program for PostScript printers. + * + * A simple program that can be used to display a matrix as a gray scale image on + * a PostScript printer using the image operator. Much of the code was borrowed + * from postdmd, the bitmap display program DMD screen dumps. May help if you have + * a large matix (of floating point numbers) and want a simple way to look for + * patterns. + * + * Matrix elements are a series of floating point numbers arranged in the input + * file in row major order. The actual matrix elements can be preceeded by a simple + * header that sets things like the matrix dimensions, interval list, and possibly + * a window into the matrix that we'll use for display. The dimension statement is + * perhaps the most important. If present it determines the number of rows and + * columns in the matrix. For example, either of the following defines a 50x50 + * matrix, + * + * dimension 50 + * dimension 50x50 + * + * If no dimension statement appears in the input file, the matrix is assumed to + * be square, and the number of rows (and columns) is set to the square root of + * the number of elements in the input file. + * + * Each matrix element is mapped into an integer in the range 0 to 255 (actually + * 254) and PostScript's image operator then maps that number into a gray scale + * appropriate for the particular printer. The mapping from the floating point + * matrix elements to integers is accomplished using an interval list that can be + * set using the -i option. The format of the interval string is, + * + * num1,num2,num3,...,numn + * + * where each num is a floating point number. The list must be given in increasing + * numerical order. A list of n numbers partitions the real line into 2n+1 regions + * given as, + * + * region1 element < num1 + * region2 element = num1 + * region3 element < num2 + * region4 element = num2 + * . + * . + * . + * region2n element = numn + * region2n+1 element > numn + * + * Every number in a region is mapped one integer in the range 0 to 254, and that + * number, when displayed on a printer using the image operator, prints as a square + * filled with a gray shade that reflects the integer that was chosen. 0 maps to + * black and 255 maps to white (which by default will not be used). + * + * The default gray scale gets darker as the region number increases, but can be + * changed by supplying a gray scale list with the -g option or in the optional + * matrix header. The color map is again a comman or space separated list that + * looks like, + * + * color1,color2, ... ,color2n+1 + * + * where color1 applies to region 1 and color2n+1 applies to region2n+1. Each + * number in the list should be an integer between 0 and 255. If less than 2n+1 + * colors are given default assignments will be used for missing regions. + * + * The size of the matrix that we can display reasonably well is a function of the + * number of elements in the interval list, paper size, and printer resolution. + * For example a 300dpi printer using 8.5x11 inch paper gives us an image area of + * about 2400x2400 pixels. An interval list of two numbers generates five separate + * regions and will therefore need that many different shades of gray. Since we're + * not using white we'll need to partion our image area into 4x4 pixel squares, + * and that means a 600x600 matrix is about as big as we can go. In practice that's + * optimistic, but the argument illustrates some of the limitations. + * + * A submatrix can be selected to display by windowing into the matrix. The window + * list can be given using the -w option or can be set in the optional header that + * can preceed each matrix. The list should be a comma or space separated list + * that looks like, + * + * lower-column, lower-row, upper-column, upper-row + * + * where each element in the list must be a positive integer. Rows and columns in + * the input matrix start at 1. The dimension of the displayed window will be from + * lower-column to upper-column and from lower-row to upper-row inclusive. + * + * The encoding produced by the program is essentially identical to what's done + * by postdmd. See the comments at the beginning of that program if you need more + * details. The prologue also shares much of the same code. + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how this program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects + * to find the current page number on the stack. + * + * bitmap + * + * columns rows bitmap - + * + * Prints the image that's read as a hex string from standard input. The + * image consists of rows lines, each of which includes columns elements. + * Eight bits per pixel are used to encode the matrix elements. + * + * labelmatrix + * + * matrixname matrixlimits labelmatrix - + * + * Prints string matrixname just below the lower left corner of the image + * and prints string martixlimits near the lower right corner. Outlines + * the entire image with a (one pixel wide) box and then draws tick marks + * along the top and left sides of the image. One tick mark is printed + * for every ten elements. + * + * legend + * + * n1 ... nN N c1 m1 ... cM mM total regions legend - + * + * Prints the legend as a bar graph below the matrix image. n1 ... nN are + * strings that represent the interval list. c1 m1 ... cm mM are pairs + * that consist of a region's color and the statistics count. Actually + * the c's are trivial procedures that just leave a one character string + * on the stack when they're executed by image - which is the way the + * bar graph is drawn. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif +#include <sys/types.h> +#include <fcntl.h> +#include <string.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ +#include "postmd.h" /* special matrix display definitions */ + +char *optnames = "a:b:c:d:g:i:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI"; + +char *prologue = POSTMD; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ +char *temp_dir = TEMPDIR; /* temp directory for copying stdin */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ +int bytespp = 6; /* bytes per pattern - on output */ + +int dostats = ON; /* permanent statistics flag */ +int nxtstat = ON; /* and the one for the next matrix */ + +char *interval = DFLTILIST; /* string representations of the interval */ +char *colormap = NULL; /* color map */ +char *window = NULL; /* and window lists */ +char *matrixname = "pipe.end"; /* name for the next plot */ + +Ilist ilist[128]; /* active interval list and color map */ +int next = 0; /* one past the last element in ilist[] */ +int regions; /* an index assigned to the last region */ +int wlist[4]; /* upper left and lower right corners */ + +int page = 0; /* last page we worked on */ +int printed = 0; /* and the number of pages printed */ + +int dfltrows = 0; /* default rows */ +int dfltcols = 0; /* and columns - changed by -d option */ +int rows; /* real number of rows */ +int columns; /* and columns in the matrix */ +int patcount = 0; /* will be set to columns * rows */ + +double element; /* next matrix element */ + +char *raster = NULL; /* next raster line */ +char *rptr; /* next free byte in raster */ +char *eptr; /* one past the last byte in raster */ + +FILE *fp_in = stdin; /* read from this file */ +FILE *fp_out = stdout; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * Bitmap display program for matrices. Only one matrix is allowed per input file, + * and each one will be displayed on a page by itself. Input files consist of an + * optional header followed by floating point numbers that represent the matrix + * elements - in row major order. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* really just for error messages */ + + init_signals(); /* sets up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* handle the command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Make sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + signal(SIGFPE, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + +/* + * + * Reads and processes the command line options. Added the -P option so arbitrary + * PostScript code can be passed through. Expect it could be useful for changing + * definitions in the prologue for which options have not been defined. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'b': /* bytes per pattern - on output */ + bytespp = atoi(optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'd': /* default matrix dimensions */ + sscanf(optarg, "%dx%d", &dfltrows, &dfltcols); + break; + + case 'g': /* set the colormap (ie. grayscale) */ + colormap = optarg; + break; + + case 'i': /* matrix element interval list */ + interval = optarg; + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'w': /* set the window */ + window = optarg; + break; + + case 'x': /* shift things horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + if ( argc < 1 ) + matrix(); + else { /* at least one argument is left */ + while ( argc > 0 ) { + matrixname = *argv; + if ( strcmp(*argv, "-") == 0 ) { + fp_in = stdin; + matrixname = "pipe.end"; + } else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + matrix(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files, so mark the end of the pages, make sure the + * last page is printed, and restore the initial environment. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %d\n", PAGES, printed); + + if ( temp_file != NULL ) + unlink(temp_file); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct provided it's not NULL. Accounting + * is requested using the -A or -J options. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +matrix() + +{ + + int count; /* pattern repeats this many times */ + long total; /* expect this many patterns */ + +/* + * + * Reads a matrix from *fp_in, translates it into a PostScript gray scale image, + * and writes the result on stdout. For now only one matrix is allowed per input + * file. Matrix elements are floating point numbers arranged in row major order + * in the input file. In addition each input file may contain an optional header + * that defines special things like the dimension of the matrix, a window into + * the matrix that will be displayed, and an interval list. + * + * If we're reading from stdin we first make a copy in a temporary file so we can + * can properly position ourselves after we've looked for the header. Originally + * wasn't always making a copy of stdin, but I've added a few things to what's + * accepted in the header and this simplifies the job. An alternative would be + * to always require a header and mark the end of it by some string. Didn't like + * that approach much - may fix things up later. + * + */ + + if ( fp_in == stdin ) /* make a copy so we can seek etc. */ + copystdin(); + + rows = dfltrows; /* new dimensions for the next matrix */ + columns = dfltcols; + + buildilist(interval); /* build the default ilist[] */ + addcolormap(colormap); /* add the colormap - if not NULL */ + setwindow(window); /* and setup the initial matrix window */ + nxtstat = dostats; /* want statistics? */ + getheader(); /* matrix dimensions at the very least */ + dimensions(); /* make sure we have the dimensions etc. */ + + patcount = 0; + total = rows * columns; + + eptr = rptr + (wlist[2] - wlist[0] + 1); + + redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d %d bitmap\n", wlist[2] - wlist[0] + 1, wlist[3] - wlist[1] + 1); + + while ( patcount != total && fscanf(fp_in, "%f", &element) != EOF ) { + if ( inwindow() ) *rptr++ = mapfloat(element); + if ( ++patcount % columns == 0 ) + if ( inrange() ) + putrow(); + } /* End while */ + + if ( total != patcount ) + error(FATAL, "matrix format error"); + + labelmatrix(); + + if ( fp_out == stdout ) printed++; + + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + +} /* End of matrix */ + +/*****************************************************************************/ + +copystdin() + +{ + + int fd_out; /* for the temporary file */ + int fd_in; /* for stdin */ + int buf[512]; /* buffer for reads and writes */ + int count; /* number of bytes put in buf */ + +/* + * + * If we're reading the matrix from stdin and the matrix dimension isn't set by + * a dimension statement at the beginning of the file we'll copy stdin to a + * temporary file and reset *fp_in so reads come from the temp file. Simplifies + * reading the header (if present), but is expensive. + * + */ + + if ( temp_file != NULL ) /* been here already */ + unlink(temp_file); + + if ( (temp_file = tempnam(temp_dir, "post")) == NULL ) + error(FATAL, "can't generate temp file name"); + + if ( (fd_out = creat(temp_file, 0660)) == -1 ) + error(FATAL, "can't create %s", temp_file); + + fd_in = fileno(stdin); + + while ( (count = read(fd_in, buf, sizeof(buf))) > 0 ) + if ( write(fd_out, buf, count) != count ) + error(FATAL, "error writing to %s", temp_file); + + close(fd_out); + + if ( (fp_in = fopen(temp_file, "r")) == NULL ) + error(FATAL, "can't open %s", temp_file); + +} /* End of copystdin */ + +/*****************************************************************************/ + +getheader() + +{ + + char buf[512]; /* temporary string space */ + char *cmap = NULL; /* remember header colormap list */ + long pos; /* for seeking back to first element */ + +/* + * + * Looks for the optional header information at the beginning of the input file, + * reads it if it's there, and sets *fp_in to be just past the header. That should + * be the beginning of the matrix element list. The recognized header keywords are + * dimension, interval, colormap (or grayscale), window, name, and statistics. All + * are optional, but may be useful in a spooling environment when the user doesn't + * doesn't actually run the translator. + * + * The dimension statement specifies the number of rows and columns. For example + * either of the following two lines define a 50 by 50 element matrix, + * + * dimension 50 + * dimension 50x50 + * + * The first integer is the number of rows and the second, if given, is the number + * of columns. If columns are missing from the dimension statement we assume the + * matrix is square. + * + * interval can be used to redefine the interval list used for mapping floating + * point numbers into integers in the range 0 to 254. The string following the + * interval keyword has the same format as the -i option. For example to set the + * interval list to -1, 0, and 1 you can add the line, + * + * interval -1,0,1 + * + * The numbers are floats given in increasing order, and separated by commas or + * blanks. The last interval list in a header takes precedence. + * + * colormap can be used to redefine the grayscale list. The string following + * the colormap keyword has the same format as the -g option. For example + * + * colormap 0,50,100,150,200,250 + * or grayscale 0,50,100,150,200,250 + * + * The window keyword can be used to select a submatrix. The numbers following + * window are the upper left and lower right matix coordinates. May not be + * implemented yet but shouldn't be difficult. For example + * + * window 10 10 40 40 + * + * selects the submatrix with corners at (10, 10) and (40, 40). The edges of the + * window are included in the display. + * + * The name keyword can be used to define the title of the display. For example, + * + * name Plot Of Matrix 1 + * + * prints the string "Plot Of Matrix 1" at the top of the page. Everything up to + * the next newline is taken as the name string. + * + */ + + pos = ftell(fp_in); + + while ( fscanf(fp_in, "%s", buf) != EOF ) { + if ( strncmp(buf, "dimension", strlen("dimension")) == 0 ) + fscanf(fp_in, "%dx%d", &rows, &columns); + else if ( strncmp(buf, "window", strlen("window")) == 0 ) { + fgets(buf, sizeof(buf), fp_in); + setwindow(buf); + } else if ( strncmp(buf, "name", strlen("name")) == 0 ) { + fgets(buf, sizeof(buf), fp_in); + matrixname = savestring(buf); + } else if ( strncmp(buf, "colormap", strlen("colormap")) == 0 ) { + fgets(buf, sizeof(buf), fp_in); + cmap = savestring(buf); + } else if ( strncmp(buf, "grayscale", strlen("grayscale")) == 0 ) { + fgets(buf, sizeof(buf), fp_in); + cmap = savestring(buf); + } else if ( strncmp(buf, "interval", strlen("interval")) == 0 ) { + fgets(buf, sizeof(buf), fp_in); + buildilist(buf); + } else if ( strncmp(buf, "statistics", strlen("statistics")) == 0 ) { + fscanf(fp_in, "%s", buf); + if ( strcmp(buf, "on") == 0 || strcmp(buf, "ON") == 0 ) + nxtstat = ON; + else nxtstat = OFF; + } else break; + pos = ftell(fp_in); + } /* End while */ + + addcolormap(cmap); /* must happen last */ + fseek(fp_in, pos, 0); /* back to the start of the matrix */ + +} /* End of getheader */ + +/*****************************************************************************/ + +dimensions() + +{ + + char buf[100]; /* temporary storage for the elements */ + long count = 0; /* number of elements in the matrix */ + long pos; /* matrix elements start here */ + +/* + * + * Need to know the dimensions of the matrix before we can go any farther. If + * rows and columns are still 0 we'll read the entire input file, starting from + * the current position, count the number of elements, take the square root of it, + * and use it as the number of rows and columns. Then we seek back to the start + * of the real matrix, make sure columns is set, and allocate enough memory for + * storing each raster line. After we're certain we've got the number of rows and + * columns we check the window coordinates, and if they're not legitimate they're + * reset to cover the entire matrix. + * + */ + + if ( rows == 0 ) { + pos = ftell(fp_in); + while ( fscanf(fp_in, "%s", buf) != EOF ) + count++; + rows = sqrt((double) count); + fseek(fp_in, pos, 0); + } /* End if */ + + if ( columns <= 0 ) columns = rows; + + if ( raster != NULL ) free(raster); + + if ( (rptr = raster = malloc(columns)) == NULL ) + error(FATAL, "no memory"); + + eptr = rptr + columns; + + if ( rows <= 0 || columns <= 0 ) + error(FATAL, "bad matrix dimensions"); + + if ( wlist[0] > wlist[2] || wlist[1] > wlist[3] ) { + wlist[0] = wlist[1] = 1; + wlist[2] = columns; + wlist[3] = rows; + } /* End if */ + +} /* End of dimensions */ + +/*****************************************************************************/ + +buildilist(list) + + char *list; /* use this as the interval list */ + +{ + + static char *templist = NULL; /* a working copy of the list */ + char *ptr; /* next number in *templist */ + int i; /* loop index - for checking the list */ + +/* + * + * Reads string *list and builds up the ilist[] that will be used in the next + * matrix. Since strtok() modifies the string it's parsing we make a copy first. + * The format of the interval list is described in detail in the comments at the + * beginning of this program. Basically consists of a comma or space separated + * list of floating point numbers that must be given in increasing numerical order. + * The list determines how floating point numbers are mapped into integers in the + * range 0 to 254. + * + */ + + if ( templist != NULL ) /* free the space used by the last list */ + free(templist); + + while ( isascii(*list) && isspace(*list) ) + list++; + + for ( ptr = list, regions = 3; *ptr != '\0'; ptr++ ) { + if ( *ptr == ',' || *ptr == '/' || isspace(*ptr) ) + regions += 2; + while ( isascii(*ptr) && isspace(*ptr) ) ptr++; + } /* End for */ + + next = 0; + templist = savestring(list); + + ptr = strtok(templist, ",/ \t\n"); + while ( ptr != NULL ) { + ilist[next].count = 0; + ilist[next++].color = 254 * (regions - 1 - next) / (regions - 1); + ilist[next].val = atof(ptr); + ilist[next].count = 0; + ilist[next++].color = 254 * (regions - 1 - next) / (regions - 1); + ptr = strtok(NULL, ",/ \t\n"); + } /* End while */ + + ilist[next].count = 0; + ilist[next].color = 254 * (regions - 1 - next) / (regions - 1); + + if ( next == 0 ) /* make sure we have a list */ + error(FATAL, "missing interval list"); + + for ( i = 3; i < next; i += 2 ) /* that's in increasing numerical order */ + if ( ilist[i].val <= ilist[i-2].val ) + error(FATAL, "bad interval list"); + +} /* End of buildilist */ + +/*****************************************************************************/ + +addcolormap(list) + + char *list; /* use this color map */ + +{ + + static char *templist = NULL; /* a working copy of the color list */ + char *ptr; /* next color in *templist */ + int i = 0; /* assigned to this region in ilist[] */ + +/* + * + * Assigns the integers in *list to the color field for the regions defined in + * ilist[]. Assumes ilist[] has already been setup. + * + */ + + if ( list != NULL ) { + if ( templist != NULL ) + free(templist); + templist = savestring(list); + + ptr = strtok(templist, ",/ \t\n"); + while ( ptr != NULL ) { + ilist[i++].color = atoi(ptr) % 256; + ptr = strtok(NULL, ",/ \t\n"); + } /* End while */ + } /* End if */ + +} /* End of addcolormap */ + +/*****************************************************************************/ + +setwindow(list) + + char *list; /* corners of window into the matrix */ + +{ + + static char *templist = NULL; /* a working copy of the window list */ + char *ptr; /* next window coordinate in *templist */ + int i = 0; /* assigned to this region in wlist[] */ + +/* + * + * Sets up an optional window into the matrix. + * + */ + + wlist[0] = wlist[1] = 1; + wlist[2] = wlist[3] = 0; + + if ( list != NULL ) { + if ( templist != NULL ) + free(templist); + templist = savestring(list); + + ptr = strtok(templist, ",/ \t\n"); + while ( ptr != NULL ) { + wlist[i++] = atoi(ptr); + ptr = strtok(NULL, ",/ \t\n"); + } /* End while */ + } /* End if */ + +} /* End of setwindow */ + +/*****************************************************************************/ + +inwindow() + +{ + + int r; /* row of the patcount element */ + int c; /* column of the patcount element */ + +/* + * + * Checks if the patcount element of the matrix is in the window. + * + */ + + r = (patcount/columns) + 1; + c = (patcount%columns) + 1; + + return((c >= wlist[0]) && (r >= wlist[1]) && (c <= wlist[2]) && (r <= wlist[3])); + +} /* End of inwindow */ + +/*****************************************************************************/ + +inrange() + +{ + +/* + * + * Checks if the current row lies in the window. Used right before we output the + * raster lines. + * + */ + + return(((patcount/columns) >= wlist[1]) && ((patcount/columns) <= wlist[3])); + +} /* End of inrange */ + +/*****************************************************************************/ + +mapfloat(element) + + double element; /* floating point matrix element */ + +{ + + int i; /* loop index */ + +/* + * + * Maps element into an integer in the range 0 to 255, and returns the result to + * the caller. Mapping is done using the color map that was saved in ilist[]. Also + * updates the count field for the region that contains element - not good! + * + */ + + for ( i = 1; i < next && ilist[i].val < element; i += 2 ) ; + + if ( i > next || element < ilist[i].val ) + i--; + + ilist[i].count++; + return(ilist[i].color); + +} /* End of mapfloat */ + +/*****************************************************************************/ + +putrow() + +{ + + char *p1, *p2; /* starting and ending columns */ + int n; /* set to bytes per pattern */ + int i; /* loop index */ + +/* + * + * Takes the scanline that's been saved in *raster, encodes it according to the + * value that's been assigned to bytespp, and writes the result to *fp_out. Each + * line in the output bitmap is terminated by a 0 on a line by itself. + * + */ + + n = (bytespp <= 0) ? columns : bytespp; + + for ( p1 = raster, p2 = raster + n; p1 < eptr; p1 = p2 ) + if ( patncmp(p1, n) == TRUE ) { + while ( patncmp(p2, n) == TRUE ) p2 += n; + p2 += n; + fprintf(fp_out, "%d ", n); + for ( i = 0; i < n; i++, p1++ ) + fprintf(fp_out, "%.2X", ((int) *p1) & 0377); + fprintf(fp_out, " %d\n", (p2 - p1) / n); + } else { + while ( p2 < eptr && patncmp(p2, n) == FALSE ) p2 += n; + if ( p2 > eptr ) p2 = eptr; + fprintf(fp_out, "%d ", p2 - p1); + while ( p1 < p2 ) + fprintf(fp_out, "%.2X", ((int) *p1++) & 0377); + fprintf(fp_out, " 0\n"); + } /* End else */ + + fprintf(fp_out, "0\n"); + + rptr = raster; + +} /* End of putrow */ + +/*****************************************************************************/ + +labelmatrix() + +{ + + int total; /* number of elements in the window */ + int i; /* loop index */ + +/* + * + * Responsible for generating the PostScript calls that label the matrix, generate + * the legend, and print the matrix name. + * + */ + + fprintf(fp_out, "(%s) ((%d, %d) to (%d, %d)) labelmatrix\n", matrixname, + wlist[0], wlist[1], wlist[2], wlist[3]); + + total = (wlist[2] - wlist[0] + 1) * (wlist[3] - wlist[1] + 1); + + if ( nxtstat == OFF ) + for ( i = 0; i < regions; i++ ) + ilist[i].count = 0; + + for ( i = 1; i < next; i += 2 ) + fprintf(fp_out, "(%g) ", ilist[i].val); + fprintf(fp_out, "%d ", (regions - 1) / 2); + + for ( i = regions - 1; i >= 0; i-- ) + fprintf(fp_out, "{(\\%.3o)} %d ", ilist[i].color, ilist[i].count); + fprintf(fp_out, "%d %d legend\n", total, regions); + +} /* End of labelmatrix */ + +/*****************************************************************************/ + +patncmp(p1, n) + + char *p1; /* first patterns starts here */ + int n; /* and extends this many bytes */ + +{ + + char *p2; /* address of the second pattern */ + +/* + * + * Compares the two n byte patterns *p1 and *(p1+n). FALSE if returned is they're + * different or extend past the end of the current raster line. + * + */ + + p2 = p1 + n; + + for ( ; n > 0; n--, p1++, p2++ ) + if ( p2 >= eptr || *p1 != *p2 ) + return(FALSE); + + return(TRUE); + +} /* End of patncmp */ + +/*****************************************************************************/ + +char *savestring(str) + + char *str; /* save this string */ + +{ + + char *ptr = NULL; /* at this address */ + +/* + * + * Copies string *str to a permanent place and returns the address to the caller. + * + */ + + if ( str != NULL && *str != '\0' ) { + if ( (ptr = malloc(strlen(str) + 1)) == NULL ) + error(FATAL, "no memory available for string %s", str); + strcpy(ptr, str); + } /* End if */ + + return(ptr); + +} /* End of savestring */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postmd/postmd.h b/sys/src/cmd/postscript/postmd/postmd.h new file mode 100755 index 000000000..715596a1f --- /dev/null +++ b/sys/src/cmd/postscript/postmd/postmd.h @@ -0,0 +1,69 @@ +/* + * + * An interval list used to map matrix elements into integers in the range 0 to + * 254 representing shades of gray on a PostScript printer. The list can be given + * using the -i option or can be set in the optional header that can preceed each + * matrix. The list should be a comma or space separated list that looks like, + * + * num1,num2, ... ,numn + * + * where each num is a floating point number. The list must be given in increasing + * numerical order. The n numbers in the list partion the real line into 2n+1 + * regions given by, + * + * region1 element < num1 + * region2 element = num1 + * region3 element < num2 + * region4 element = num3 + * . . + * . . + * . . + * region2n element = numn + * region2n+1 element > numn + * + * Every number in a given region is mapped into an integer in the range 0 to 254 + * and that number, when displayed on a PostScript printer using the image operator, + * prints as a square filled with a gray scale that reflects the integer that was + * chosen. 0 maps to black and 255 white (that's why 255 is normally omitted). + * + * The shades of gray chosen by the program are normally generated automatically, + * but can be reassigned using the -g option or by including a grayscale line in + * the optional header. The grayscale list is comma or space separated list of + * integers between 0 and 255 that's used to map individual regions into arbitray + * shade of gray, thus overriding the default choice made in the program. The list + * should look like, + * + * color1,color2, ... ,color2n+1 + * + * where color1 applies to region1 and color2n+1 applies to region2n+1. If less + * than 2n+1 numbers are given the default assignments will be used for the missing + * regions. Each color must be an integer in the range 0 to 255. + * + * The default interval list is given below. The default grayscale maps 254 (almost + * white) into the first region and 0 (black) into the last. + * + */ + +#define DFLTILIST "-1,0,1" + +/* + * + * The active interval list is built from an interval string and stored in an array + * whose elements are of type Ilist. + * + */ + +typedef struct { + double val; /* only valid in kind is ENDPOINT */ + int color; /* gray scale color */ + long count; /* statistics for each region */ +} Ilist; + +/* + * + * Non-integer function declarations. + * + */ + +char *savestring(); + diff --git a/sys/src/cmd/postscript/postmd/postmd.mk b/sys/src/cmd/postscript/postmd/postmd.mk new file mode 100755 index 000000000..ca131c555 --- /dev/null +++ b/sys/src/cmd/postscript/postmd/postmd.mk @@ -0,0 +1,95 @@ +MAKE=/bin/make +MAKEFILE=postmd.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +HFILES=postmd.h\ + $(COMMONDIR)/comments.h\ + $(COMMONDIR)/ext.h\ + $(COMMONDIR)/gen.h\ + $(COMMONDIR)/path.h + +OFILES=postmd.o\ + $(COMMONDIR)/glob.o\ + $(COMMONDIR)/misc.o\ + $(COMMONDIR)/request.o\ + $(COMMONDIR)/tempnam.o + +all : postmd + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + @if [ ! -d "$(POSTLIB)" ]; then \ + mkdir $(POSTLIB); \ + chmod 755 $(POSTLIB); \ + chgrp $(GROUP) $(POSTLIB); \ + chown $(OWNER) $(POSTLIB); \ + fi + cp postmd $(POSTBIN)/postmd + @chmod 755 $(POSTBIN)/postmd + @chgrp $(GROUP) $(POSTBIN)/postmd + @chown $(OWNER) $(POSTBIN)/postmd + cp postmd.ps $(POSTLIB)/postmd.ps + @chmod 644 $(POSTLIB)/postmd.ps + @chgrp $(GROUP) $(POSTLIB)/postmd.ps + @chown $(OWNER) $(POSTLIB)/postmd.ps + cp postmd.1 $(MAN1DIR)/postmd.1 + @chmod 644 $(MAN1DIR)/postmd.1 + @chgrp $(GROUP) $(MAN1DIR)/postmd.1 + @chown $(OWNER) $(MAN1DIR)/postmd.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postmd + +postmd : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postmd $(OFILES) -lm + +postmd.o : $(HFILES) + +$(COMMONDIR)/glob.o\ +$(COMMONDIR)/misc.o\ +$(COMMONDIR)/request.o\ +$(COMMONDIR)/tempnam.o : + @cd $(COMMONDIR); $(MAKE) -f common.mk SYSTEM=$(SYSTEM) `basename $@` + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + postmd.1 >XXX.1; \ + mv XXX.1 postmd.1 + diff --git a/sys/src/cmd/postscript/postmd/postmd.ps b/sys/src/cmd/postscript/postmd/postmd.ps new file mode 100755 index 000000000..6a5661e2c --- /dev/null +++ b/sys/src/cmd/postscript/postmd/postmd.ps @@ -0,0 +1,177 @@ +% +% Version 3.3.2 prologue for matrix display files. +% + +/#copies 1 store +/aspectratio 1 def +/font /Helvetica def +/formsperpage 1 def +/landscape false def +/magnification 1 def +/margin 10 def +/orientation 0 def +/rotation 1 def +/size 9 def +/statspace 1.6 def +/ticklength .06 def +/tickspacing 10 def +/xoffset 0 def +/yoffset 0 def + +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/show {show} bind def % so later references don't bind +/stringwidth {stringwidth} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + + pagedimensions + height width lt { + /statspace statspace height width div mul def + /size size height width div mul def + /ticklength ticklength height width div mul def + } if + /height height margin sub statspace inch sub ticklength inch sub size 6 mul sub def + /width width margin sub ticklength inch sub def + xcenter ycenter translate + orientation rotation mul rotate + xoffset inch yoffset inch translate + 0 height 2 div height width min 2 div sub translate + 0 statspace inch 2 div translate + magnification dup aspectratio mul scale + + 0 setlinewidth +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def} bind def + +/bitmap { + /scanlines exch def + /scanlength exch def + + /picstr scanlength string def + + gsave + height scanlines div width scanlength div min + /scaling exch def + scaling scaling scale + + scanlength neg 2 div scanlines neg 2 div translate + scanlength scanlines scale + getbitmap + grestore +} bind def + +/getbitmap { + scanlength scanlines 8 [scanlength 0 0 scanlines neg 0 scanlines] { + 0 { + currentfile token pop dup + 0 eq {pop pop exit} if + /charcount exch def + picstr 1 index charcount getinterval + /repl exch def + currentfile repl readhexstring pop pop + charcount add + currentfile token pop { + picstr 1 index repl putinterval + charcount add + } repeat + } loop + picstr + } image +} bind def + +/labelmatrix { + /matrixlimits exch def + /matrixname exch def + + gsave + scaling scaling scale + font findfont size scaling div scalefont setfont + scanlength neg 2 div scanlines 2 div translate + + 0 scanlines size 1.5 mul scaling div add neg moveto + matrixname show + + scanlength scanlines size 1.5 mul scaling div add neg moveto + matrixlimits stringwidth pop neg 0 rmoveto + matrixlimits show + + newpath + 0 0 moveto + scanlength 0 rlineto + 0 scanlines neg rlineto + scanlength neg 0 rlineto + closepath stroke + + scanlength tickspacing idiv 1 add tickspacing 0 ticks + scanlines tickspacing idiv 1 add 0 tickspacing neg ticks + grestore +} bind def + +/ticks { + /dy exch def + /dx exch def + + /tl ticklength inch scaling div def + newpath + 0 0 moveto + { + gsave dx 0 eq {tl neg 0} {0 tl} ifelse rlineto stroke grestore + dx dy rmoveto + } repeat +} bind def + +/legend { + /regions exch def + /total exch def + + gsave + width height min 2 div neg dup size 2 mul sub translate + 0 statspace inch neg translate + + gsave + regions { + gsave + total div statspace inch size 2 mul sub mul size 2 mul add + width height min regions div exch scale + 1 1 8 [1 0 0 1 0 0] 5 -1 roll image + grestore + width height min regions div 0 translate + } repeat + grestore + + width height min size 1.5 mul neg translate + font findfont size scalefont setfont + dup dup add 1 add width height min exch div /interval exch def + { + interval neg 0 translate + interval 2 div neg 0 translate + dup stringwidth pop 2 div neg 0 moveto show + interval 2 div neg 0 translate + } repeat + grestore +} bind def + +/done {/lastpage where {pop lastpage} if} def diff --git a/sys/src/cmd/postscript/postprint/README b/sys/src/cmd/postscript/postprint/README new file mode 100755 index 000000000..f6185bdce --- /dev/null +++ b/sys/src/cmd/postscript/postprint/README @@ -0,0 +1,4 @@ + +Simple ASCII file to PostScript translator. The -e options is new +and allows access to all characters in PostScript fonts. + diff --git a/sys/src/cmd/postscript/postprint/mkfile b/sys/src/cmd/postscript/postprint/mkfile new file mode 100755 index 000000000..c1b3572d7 --- /dev/null +++ b/sys/src/cmd/postscript/postprint/mkfile @@ -0,0 +1,33 @@ +</$objtype/mkfile + +<../config + +TARG=postprint +OFILES=postprint.$O\ + +COMMONDIR=../common + +HFILES=postprint.h\ + $COMMONDIR/comments.h\ + $COMMONDIR/ext.h\ + $COMMONDIR/gen.h\ + $COMMONDIR/path.h\ + +BIN=$POSTBIN +LIB=$COMMONDIR/com.a$O + +</sys/src/cmd/mkone + +CC=pcc +LD=pcc +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B + +install:V: $POSTLIB/postprint.ps + +$POSTLIB/postprint.ps: postprint.ps + cp $prereq $target + +$LIB: + cd $COMMONDIR + mk install + mk clean diff --git a/sys/src/cmd/postscript/postprint/postprint.c b/sys/src/cmd/postscript/postprint/postprint.c new file mode 100755 index 000000000..6dab5c118 --- /dev/null +++ b/sys/src/cmd/postscript/postprint/postprint.c @@ -0,0 +1,794 @@ +/* + * + * postprint - PostScript translator for ASCII files. + * + * A simple program that translates ASCII files into PostScript. All it really + * does is expand tabs and backspaces, handle character quoting, print text lines, + * and control when pages are started based on the requested number of lines per + * page. + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following procedures are defined + * in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how the program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects + * to find the current page number on the stack. + * + * l + * + * string l - + * + * Prints string starting in the first column and then goes to the next + * line. + * + * L + * + * mark string column string column ... L mark + * + * Prints each string on the stack starting at the horizontal position + * selected by column. Used when tabs and spaces can be sufficiently well + * compressed to make the printer overhead worthwhile. Always used when + * we have to back up. + * + * LL + * + * mark string column string column ... LL mark + * + * Like L, but only used to prevent potential PostScript stack overflow + * from too many string/column pairs. Stays on the current line. It will + * not be needed often!! + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * Almost everything has been changed in this version of postprint. The program + * is more intelligent, especially about tabs, spaces, and backspacing, and as a + * result output files usually print faster. Output files also now conform to + * Adobe's file structuring conventions, which is undoubtedly something I should + * have done in the first version of the program. If the number of lines per page + * is set to 0, which can be done using the -l option, pointsize will be used to + * guess a reasonable value. The estimate is based on the values of LINESPP, + * POINTSIZE, and pointsize, and assumes LINESPP lines would fit on a page if + * we printed in size POINTSIZE. Selecting a point size using the -s option and + * adding -l0 to the command line forces the guess to be made. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif +#include <sys/types.h> +#include <fcntl.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ +#include "postprint.h" /* a few special definitions */ + +char *optnames = "a:c:ef:l:m:n:o:p:r:s:t:x:y:A:C:E:J:L:P:R:DI"; + +char *prologue = POSTPRINT; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +int linespp = LINESPP; /* number of lines per page */ +int pointsize = POINTSIZE; /* in this point size */ +int tabstops = TABSTOPS; /* tabs set at these columns */ +int crmode = 0; /* carriage return mode - 0, 1, or 2 */ +int extended = TRUE; /* use escapes for unprintable chars */ + +int col = 1; /* next character goes in this column */ +int line = 1; /* on this line */ + +int stringcount = 0; /* number of strings on the stack */ +int stringstart = 1; /* column where current one starts */ + +Fontmap fontmap[] = FONTMAP; /* for translating font names */ +char *fontname = "Courier"; /* use this PostScript font */ + +int page = 0; /* page we're working on */ +int printed = 0; /* printed this many pages */ + +FILE *fp_in = stdin; /* read from this file */ +FILE *fp_out = stdout; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that translates ASCII files into PostScript. If there's more + * than one input file, each begins on a new page. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* really just for error messages */ + + init_signals(); /* sets up interrupt handling */ + header(); /* PostScript header and prologue */ + options(); /* handle the command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Makes sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + if ( DOROUND ) + cat(ROUNDPAGE); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + +/* + * + * Reads and processes the command line options. Added the -P option so arbitrary + * PostScript code can be passed through. Expect it could be useful for changing + * definitions in the prologue for which options have not been defined. + * + * Although any PostScript font can be used, things will only work well for + * constant width fonts. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'e': /* obsolete - it's now always on */ + extended = TRUE; + break; + + case 'f': /* use this PostScript font */ + fontname = get_font(optarg); + fprintf(stdout, "/font /%s def\n", fontname); + break; + + case 'l': /* lines per page */ + linespp = atoi(optarg); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'r': /* carriage return mode */ + crmode = atoi(optarg); + break; + + case 's': /* point size */ + pointsize = atoi(optarg); + fprintf(stdout, "/pointsize %s def\n", optarg); + break; + + case 't': /* tabstops */ + tabstops = atoi(optarg); + break; + + case 'x': /* shift things horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +char *get_font(name) + + char *name; /* name the user asked for */ + +{ + + int i; /* for looking through fontmap[] */ + +/* + * + * Called from options() to map a user's font name into a legal PostScript name. + * If the lookup fails *name is returned to the caller. That should let you choose + * any PostScript font, although things will only work well for constant width + * fonts. + * + */ + + for ( i = 0; fontmap[i].name != NULL; i++ ) + if ( strcmp(name, fontmap[i].name) == 0 ) + return(fontmap[i].val); + + return(name); + +} /* End of get_font */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. linespp (lines per page) can be set using the -l + * option. If it's not positive we calculate a reasonable value using the + * requested point size - assuming LINESPP lines fit on a page in point size + * POINTSIZE. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + + if ( linespp <= 0 ) + linespp = LINESPP * POINTSIZE / pointsize; + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll translate stdin. + * + */ + + if ( argc < 1 ) + text(); + else { /* at least one argument is left */ + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + text(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files, so mark the end of the pages with a TRAILER + * comment, make sure the last page prints, and add things like the PAGES comment + * that can only be determined after all the input files have been read. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is + * requested using the -A or -J options. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +text() + +{ + + int ch; /* next input character */ + +/* + * + * Translates *fp_in into PostScript. Intercepts space, tab, backspace, newline, + * return, and formfeed. Everything else goes to oput(), which handles quoting + * (if needed) and escapes for nonascii characters if extended is TRUE. The + * redirect(-1) call forces the initial output to go to /dev/null - so stuff + * that formfeed() does at the end of each page goes to /dev/null rather than + * the real output file. + * + */ + + redirect(-1); /* get ready for the first page */ + formfeed(); /* force PAGE comment etc. */ + + while ( (ch = getc(fp_in)) != EOF ) + switch ( ch ) { + case '\n': + newline(); + break; + + case '\t': + case '\b': + case ' ': + spaces(ch); + break; + + case '\014': + formfeed(); + break; + + case '\r': + if ( crmode == 1 ) + spaces(ch); + else if ( crmode == 2 ) + newline(); + break; + + default: + oput(ch); + break; + } /* End switch */ + + formfeed(); /* next file starts on a new page? */ + +} /* End of text */ + +/*****************************************************************************/ + +formfeed() + +{ + +/* + * + * Called whenever we've finished with the last page and want to get ready for the + * next one. Also used at the beginning and end of each input file, so we have to + * be careful about what's done. The first time through (up to the redirect() call) + * output goes to /dev/null. + * + * Adobe now recommends that the showpage operator occur after the page level + * restore so it can be easily redefined to have side-effects in the printer's VM. + * Although it seems reasonable I haven't implemented it, because it makes other + * things, like selectively setting manual feed or choosing an alternate paper + * tray, clumsy - at least on a per page basis. + * + */ + + if ( fp_out == stdout ) /* count the last page */ + printed++; + + endline(); /* print the last line */ + + fprintf(fp_out, "cleartomark\n"); + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + + if ( ungetc(getc(fp_in), fp_in) == EOF ) + redirect(-1); + else redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d pagesetup\n", printed+1); + + line = 1; + +} /* End of formfeed */ + +/*****************************************************************************/ + +newline() + +{ + +/* + * + * Called when we've read a newline character. The call to startline() ensures + * that at least an empty string is on the stack. + * + */ + + startline(); + endline(); /* print the current line */ + + if ( ++line > linespp ) /* done with this page */ + formfeed(); + +} /* End of newline */ + +/*****************************************************************************/ + +spaces(ch) + + int ch; /* next input character */ + +{ + + int endcol; /* ending column */ + int i; /* final distance - in spaces */ + +/* + * + * Counts consecutive spaces, tabs, and backspaces and figures out where the next + * string should start. Once that's been done we try to choose an efficient way + * to output the required number of spaces. The choice is between using procedure + * l with a single string on the stack and L with several string and column pairs. + * We usually break even, in terms of the size of the output file, if we need four + * consecutive spaces. More means using L decreases the size of the file. For now + * if there are less than 6 consecutive spaces we just add them to the current + * string, otherwise we end that string, follow it by its starting position, and + * begin a new one that starts at endcol. Backspacing is always handled this way. + * + */ + + startline(); /* so col makes sense */ + endcol = col; + + do { + if ( ch == ' ' ) + endcol++; + else if ( ch == '\t' ) + endcol += tabstops - ((endcol - 1) % tabstops); + else if ( ch == '\b' ) + endcol--; + else if ( ch == '\r' ) + endcol = 1; + else break; + } while ( ch = getc(fp_in) ); /* if ch is 0 we'd quit anyway */ + + ungetc(ch, fp_in); /* wasn't a space, tab, or backspace */ + + if ( endcol < 1 ) /* can't move past left edge */ + endcol = 1; + + if ( (i = endcol - col) >= 0 && i < 6 ) + for ( ; i > 0; i-- ) + oput((int)' '); + else { + endstring(); + col = stringstart = endcol; + } /* End else */ + +} /* End of spaces */ + +/*****************************************************************************/ + +startline() + +{ + +/* + * + * Called whenever we want to be certain we're ready to start pushing characters + * into an open string on the stack. If stringcount is positive we've already + * started, so there's nothing to do. The first string starts in column 1. + * + */ + + if ( stringcount < 1 ) { + putc('(', fp_out); + stringstart = col = 1; + stringcount = 1; + } /* End if */ + +} /* End of startline */ + +/*****************************************************************************/ + +endstring() + +{ + +/* + * + * End the current string and start a new one. + * + */ + + if ( stringcount > 100 ) { /* don't put too much on the stack */ + fprintf(fp_out, ")%d LL\n(", stringstart-1); + stringcount = 2; /* kludge - don't let endline() use l */ + } else { + fprintf(fp_out, ")%d(", stringstart-1); + stringcount++; + } /* End else */ + +} /* End of endstring */ + +/*****************************************************************************/ + +endline() + +{ + +/* + * + * Generates a call to the PostScript procedure that processes all the text on + * the stack - provided stringcount is positive. If one string is on the stack + * the fast procedure (ie. l) is used to print the line, otherwise the slower + * one that processes string and column pairs is used. + * + */ + + if ( stringcount == 1 ) + fprintf(fp_out, ")l\n"); + else if ( stringcount > 1 ) + fprintf(fp_out, ")%d L\n", stringstart-1); + + stringcount = 0; + +} /* End of endline */ + +/*****************************************************************************/ + +oput(ch) + + int ch; /* next output character */ + +{ + +/* + * + * Responsible for adding all printing characters from the input file to the + * open string on top of the stack. + * + */ + + if ( isascii(ch) && isprint(ch) ) { + startline(); + if ( ch == '(' || ch == ')' || ch == '\\' ) + putc('\\', fp_out); + putc(ch, fp_out); + col++; + } else if ( extended == TRUE ) { + startline(); + fprintf(fp_out, "\\%.3o", ch & 0377); + col++; + } /* End if */ + +} /* End of oput */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postprint/postprint.h b/sys/src/cmd/postscript/postprint/postprint.h new file mode 100755 index 000000000..07c14fe51 --- /dev/null +++ b/sys/src/cmd/postscript/postprint/postprint.h @@ -0,0 +1,49 @@ +/* + * + * Default lines per page, tab stops, and point size. + * + */ + +#define LINESPP 66 +#define TABSTOPS 8 +#define POINTSIZE 10 + +/* + * + * An array of type Fontmap helps convert font names requested by users into + * legitimate PostScript names. The array is initialized using FONTMAP, which must + * end with an entry that has NULL defined as its name field. The only fonts that + * are guaranteed to work well are the constant width fonts. + * + */ + +typedef struct { + char *name; /* user's font name */ + char *val; /* corresponding PostScript name */ +} Fontmap; + +#define FONTMAP \ + \ + { \ + "R", "Courier", \ + "I", "Courier-Oblique", \ + "B", "Courier-Bold", \ + "CO", "Courier", \ + "CI", "Courier-Oblique", \ + "CB", "Courier-Bold", \ + "CW", "Courier", \ + "PO", "Courier", \ + "courier", "Courier", \ + "cour", "Courier", \ + "co", "Courier", \ + NULL, NULL \ + } + +/* + * + * Some of the non-integer functions in postprint.c. + * + */ + +char *get_font(); + diff --git a/sys/src/cmd/postscript/postprint/postprint.ps b/sys/src/cmd/postscript/postprint/postprint.ps new file mode 100755 index 000000000..315b5639a --- /dev/null +++ b/sys/src/cmd/postscript/postprint/postprint.ps @@ -0,0 +1,75 @@ +% +% Version 3.3.2 prologue for text files. +% + +/#copies 1 store +/aspectratio 1 def +/font /Courier def +/formsperpage 1 def +/landscape false def +/magnification 1 def +/margin 10 def +/orientation 0 def +/pointsize 10 def +/rotation 1 def +/xoffset .25 def +/yoffset .25 def + +/roundpage true def +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/show {show} bind def % so later references don't bind +/stringwidth {stringwidth} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + font findfont pointsize scalefont setfont + /charwidth (M) stringwidth pop def + /linespace pointsize pointsize .10 mul add neg def + + pagedimensions + xcenter ycenter translate + orientation rotation mul rotate + width 2 div neg height 2 div translate + xoffset inch yoffset inch neg translate + margin 2 div dup neg translate + magnification dup aspectratio mul scale + height width div 1 min dup scale + 0 linespace translate +} def + +/pagedimensions { + useclippath userdict /gotpagebbox known not and { + /pagebbox [clippath pathbbox newpath] def + roundpage currentdict /roundpagebbox known and {roundpagebbox} if + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def 0 0 moveto 0} bind def + +/L { + counttomark 2 idiv {charwidth mul currentpoint exch pop moveto show} repeat + linespace add dup 0 exch moveto +} bind def + +/l {show linespace add dup 0 exch moveto} bind def + +/LL { + counttomark 2 idiv {charwidth mul currentpoint exch pop moveto show} repeat +} bind def + +/done {/lastpage where {pop lastpage} if} def diff --git a/sys/src/cmd/postscript/postreverse/README b/sys/src/cmd/postscript/postreverse/README new file mode 100755 index 000000000..d7038ae88 --- /dev/null +++ b/sys/src/cmd/postscript/postreverse/README @@ -0,0 +1,10 @@ + +A simple program that reverses the pages in PostScript files that +conform to Adobe's Version 1.0 or Version 2.0 file structuring +conventions. + +postrevese also handles a small class of files that violate page +independence (eg. output from dpost) and can be used with all the +translators in this package. The output can be conforming even if +the input file wasn't. + diff --git a/sys/src/cmd/postscript/postreverse/mkfile b/sys/src/cmd/postscript/postreverse/mkfile new file mode 100755 index 000000000..0e935e804 --- /dev/null +++ b/sys/src/cmd/postscript/postreverse/mkfile @@ -0,0 +1,29 @@ +</$objtype/mkfile + +<../config + +COMMONDIR=../common + +TARG=postreverse + +OFILES=postreverse.$O\ + +HFILES=postreverse.h\ + $COMMONDIR/comments.h\ + $COMMONDIR/ext.h\ + $COMMONDIR/gen.h\ + $COMMONDIR/path.h\ + +BIN=$POSTBIN +LIB=$COMMONDIR/com.a$O + +</sys/src/cmd/mkone + +CC=pcc +LD=pcc +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B + +$LIB: + cd $COMMONDIR + mk install + mk clean diff --git a/sys/src/cmd/postscript/postreverse/postreverse.c b/sys/src/cmd/postscript/postreverse/postreverse.c new file mode 100755 index 000000000..de7448f09 --- /dev/null +++ b/sys/src/cmd/postscript/postreverse/postreverse.c @@ -0,0 +1,541 @@ +/* + * + * postreverse - reverse the page order in certain PostScript files. + * + * Page reversal relies on being able to locate sections of a document using file + * structuring comments defined by Adobe (ie. the 1.0 and now 2.0 conventions) and + * a few I've added. Among other things a minimally conforming document, according + * to the 1.0 conventions, + * + * 1) Marks the end of the prologue with an %%EndProlog comment. + * + * 2) Starts each page with a %%Page: comment. + * + * 3) Marks the end of all the pages %%Trailer comment. + * + * 4) Obeys page independence (ie. pages can be arbitrarily rearranged). + * + * The most important change (at least for this program) that Adobe made in going + * from the 1.0 to the 2.0 structuring conventions was in the prologue. They now + * say the prologue should only define things, and the global initialization that + * was in the prologue (1.0 conventions) should now come after the %%EndProlog + * comment but before the first %%Page: comment and be bracketed by %%BeginSetup + * and %%EndSetup comments. So a document that conforms to Adobe's 2.0 conventions, + * + * 1) Marks the end of the prologue (only definitions) with %%EndProlog. + * + * 2) Brackets global initialization with %%BeginSetup and %%EndSetup comments + * which come after the prologue but before the first %Page: comment. + * + * 3) Starts each page with a %%Page: comment. + * + * 4) Marks the end of all the pages with a %%Trailer comment. + * + * 5) Obeys page independence. + * + * postreverse can handle documents that follow the 1.0 or 2.0 conventions, but has + * also been extended slightly so it works properly with the translators (primarily + * dpost) supplied with this package. The page independence requirement has been + * relaxed some. In particular definitions exported to the global environment from + * within a page should be bracketed by %%BeginGlobal and %%EndGlobal comments. + * postreverse pulls them out of each page and inserts them in the setup section + * of the document, immediately before it writes the %%EndProlog (for version 1.0) + * or %%EndSetup (for version 2.0) comments. + * + * In addition postreverse accepts documents that choose to mark the end of each + * page with a %%EndPage: comment, which from a translator's point of view is often + * a more natural approach. Both page boundary comments (ie. Page: and %%EndPage:) + * are also accepted, but be warned that everything between consecutive %%EndPage: + * and %%Page: comments will be ignored. + * + * So a document that will reverse properly with postreverse, + * + * 1) Marks the end of the prologue with %%EndProlog. + * + * 2) May have a %%BeginSetup/%%EndSetup comment pair before the first %%Page: + * comment that brackets any global initialization. + * + * 3) Marks the start of each page with a %%Page: comment, or the end of each + * page with a %%EndPage: comment. Both page boundary comments are allowed. + * + * 4) Marks the end of all the pages with a %%Trailer comment. + * + * 5) Obeys page independence or violates it to a rather limited extent and + * marks the violations with %%BeginGlobal and %%EndGlobal comments. + * + * If no file arguments are given postreverse copies stdin to a temporary file and + * then processes that file. That means the input is read three times (rather than + * two) whenever we handle stdin. That's expensive, and shouldn't be too difficult + * to fix, but I haven't gotten around to it yet. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <fcntl.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for temporary directory */ +#include "ext.h" /* external variable declarations */ +#include "postreverse.h" /* a few special definitions */ + +int page = 1; /* current page number */ +int forms = 1; /* forms per page in the input file */ + +char *temp_dir = TEMPDIR; /* temp directory for copying stdin */ + +Pages pages[1000]; /* byte offsets for all pages */ +int next_page = 0; /* next page goes here */ +long start; /* starting offset for next page */ +long endoff = -1; /* offset where TRAILER was found */ +int noreverse = FALSE; /* don't reverse pages if TRUE */ +char *endprolog = ENDPROLOG; /* occasionally changed to ENDSETUP */ + +double version = 3.3; /* of the input file */ +int ignoreversion = FALSE; /* ignore possible forms.ps problems */ + +char buf[2048]; /* line buffer for input file */ + +FILE *fp_in; /* stuff is read from this file */ +FILE *fp_out = stdout; /* and written here */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that reverses the pages in specially formatted PostScript + * files. Will work with all the translators in this package, and should handle + * any document that conforms to Adobe's version 1.0 or 2.0 file structuring + * conventions. Only one input file is allowed, and it can either be a named (on + * the command line) file or stdin. + * + */ + + argc = agc; /* other routines may want them */ + argv = agv; + + prog_name = argv[0]; /* just for error messages */ + + init_signals(); /* sets up interrupt handling */ + options(); /* first get command line options */ + arguments(); /* then process non-option arguments */ + done(); /* and clean things up */ + + exit(x_stat); /* not much could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Makes sure we handle interrupts properly. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* return value from getopt() */ + char *optnames = "n:o:rvT:DI"; + + extern char *optarg; /* used by getopt() */ + extern int optind; + +/* + * + * Reads and processes the command line options. The -r option (ie. the one that + * turns page reversal off) is really only useful if you want to take dpost output + * and produce a page independent output file. In that case global definitions + * made within pages and bracketed by %%BeginGlobal/%%EndGlobal comments will be + * moved into the prologue or setup section of the document. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'n': /* forms per page */ + if ( (forms = atoi(optarg)) <= 0 ) + error(FATAL, "illegal forms request %s", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'r': /* don't reverse the pages */ + noreverse = TRUE; + break; + + case 'v': /* ignore possible forms.ps problems */ + ignoreversion = TRUE; + break; + + case 'T': /* temporary file directory */ + temp_dir = optarg; + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't understand the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c\n", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +arguments() + +{ + + char *name; /* name of the input file */ + +/* + * + * postreverse only handles one input file at a time, so if there's more than one + * argument left when we get here we'll quit. If none remain we copy stdin to a + * temporary file and process that file. + * + */ + + if ( argc > 1 ) /* can't handle more than one file */ + error(FATAL, "too many arguments"); + + if ( argc == 0 ) /* copy stdin to a temporary file */ + name = copystdin(); + else name = *argv; + + if ( (fp_in = fopen(name, "r")) == NULL ) + error(FATAL, "can't open %s", name); + + reverse(); + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Cleans things up after we've finished reversing the pages in the input file. + * All that's really left to do is remove the temp file, provided we used one. + * + */ + + if ( temp_file != NULL ) + unlink(temp_file); + +} /* End of done */ + +/*****************************************************************************/ + +char *copystdin() + +{ + + int fd_out; /* for the temporary file */ + int fd_in; /* for stdin */ + int count; /* number of bytes put in buf[] */ + +/* + * + * Copies stdin to a temporary file and returns the pathname of that file to the + * caller. It's an expensive way of doing things, because it means we end up + * reading the input file three times - rather than just twice. Could probably be + * fixed by creating the temporary file on the fly as we read the file the first + * time. + * + */ + + if ( (temp_file = tempnam(temp_dir, "post")) == NULL ) + error(FATAL, "can't generate temp file name"); + + if ( (fd_out = creat(temp_file, 0660)) == -1 ) + error(FATAL, "can't open %s", temp_file); + + fd_in = fileno(stdin); + + while ( (count = read(fd_in, buf, sizeof(buf))) > 0 ) + if ( write(fd_out, buf, count) != count ) + error(FATAL, "error writing to %s", temp_file); + + close(fd_out); + + return(temp_file); + +} /* End of copystdin */ + +/*****************************************************************************/ + +reverse() + +{ + +/* + * + * Begins by looking for the ENDPROLOG comment in the input file. Everything up to + * that comment is copied to the output file. If the comment isn't found the entire + * input file is copied and moreprolog() returns FALSE. Otherwise readpages() reads + * the rest of the input file and remembers (in pages[]) where each page starts and + * ends. In addition everything bracketed by %%BeginGlobal and %%EndGlobal comments + * is immediately added to the new prologue (or setup section) and ends up being + * removed from the individual pages. When readpages() finds the TRAILER comment + * or gets to the end of the input file we go back to the pages[] array and use + * the saved offsets to write the pages out in reverse order. Finally everything + * from the TRAILER comment to the end of the input file is copied to the output + * file. + * + */ + + if ( moreprolog(ENDPROLOG) == TRUE ) { + readpages(); + writepages(); + trailer(); + } /* End if */ + +} /* End of reverse */ + +/*****************************************************************************/ + +moreprolog(str) + + char *str; /* copy everything up to this string */ + +{ + + int len; /* length of FORMSPERPAGE string */ + int vlen; /* length of VERSION string */ + +/* + * + * Looks for string *str at the start of a line and copies everything up to that + * string to the output file. If *str isn't found the entire input file will end + * up being copied to the output file and FALSE will be returned to the caller. + * The first call (made from reverse()) looks for ENDPROLOG. Any other call comes + * from readpages() and will be looking for the ENDSETUP comment. + * + */ + + len = strlen(FORMSPERPAGE); + vlen = strlen(VERSION); + + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) { + if ( strcmp(buf, str) == 0 ) + return(TRUE); + else if ( strncmp(buf, FORMSPERPAGE, len) == 0 ) + forms = atoi(&buf[len+1]); + else if ( strncmp(buf, VERSION, vlen) == 0 ) + version = atof(&buf[vlen+1]); + fprintf(fp_out, "%s", buf); + } /* End while */ + + return(FALSE); + +} /* End of moreprolog */ + +/*****************************************************************************/ + +readpages() + +{ + + int endpagelen; /* length of ENDPAGE */ + int pagelen; /* and PAGE strings */ + int sawendpage = TRUE; /* ENDPAGE equivalent marked last page */ + int gotpage = FALSE; /* TRUE disables BEGINSETUP stuff */ + +/* + * + * Records starting and ending positions of the requested pages (usually all of + * them), puts global definitions in the prologue, and remembers where the TRAILER + * was found. + * + * Page boundaries are marked by the strings PAGE, ENDPAGE, or perhaps both. + * Application programs will normally find one or the other more convenient, so + * in most cases only one kind of page delimiter will be found in a particular + * document. + * + */ + + pages[0].start = ftell(fp_in); /* first page starts after ENDPROLOG */ + endprolog = ENDPROLOG; + + endpagelen = strlen(ENDPAGE); + pagelen = strlen(PAGE); + + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) + if ( buf[0] != '%' ) + continue; + else if ( strncmp(buf, ENDPAGE, endpagelen) == 0 ) { + if ( in_olist(page++) == ON ) { + pages[next_page].empty = FALSE; + pages[next_page++].stop = ftell(fp_in); + } /* End if */ + pages[next_page].start = ftell(fp_in); + sawendpage = TRUE; + gotpage = TRUE; + } else if ( strncmp(buf, PAGE, pagelen) == 0 ) { + if ( sawendpage == FALSE && in_olist(page++) == ON ) { + pages[next_page].empty = FALSE; + pages[next_page++].stop = ftell(fp_in) - strlen(buf); + } /* End if */ + pages[next_page].start = ftell(fp_in) - strlen(buf); + sawendpage = FALSE; + gotpage = TRUE; + } else if ( gotpage == FALSE && strcmp(buf, BEGINSETUP) == 0 ) { + fprintf(fp_out, "%s", endprolog); + fprintf(fp_out, "%s", BEGINSETUP); + moreprolog(ENDSETUP); + endprolog = ENDSETUP; + } else if ( strcmp(buf, BEGINGLOBAL) == 0 ) { + moreprolog(ENDGLOBAL); + } else if ( strcmp(buf, TRAILER) == 0 ) { + if ( sawendpage == FALSE ) + pages[next_page++].stop = ftell(fp_in) - strlen(buf); + endoff = ftell(fp_in); + break; + } /* End if */ + +} /* End of readpages */ + +/*****************************************************************************/ + +writepages() + +{ + + int i, j, k; /* loop indices */ + +/* + * + * Goes through the pages[] array, usually from the bottom up, and writes out all + * the pages. Documents that print more than one form per page cause things to get + * a little more complicated. Each physical page has to have its subpages printed + * in the correct order, and we have to build a few dummy subpages for the last + * (and now first) sheet of paper, otherwise things will only occasionally work. + * + */ + + fprintf(fp_out, "%s", endprolog); + + if ( noreverse == FALSE ) /* fill out the first page */ + for ( i = (forms - next_page % forms) % forms; i > 0; i--, next_page++ ) + pages[next_page].empty = TRUE; + else forms = next_page; /* turns reversal off in next loop */ + + for ( i = next_page - forms; i >= 0; i -= forms ) + for ( j = i, k = 0; k < forms; j++, k++ ) + if ( pages[j].empty == TRUE ) { + if ( ignoreversion == TRUE || version > 3.1 ) { + fprintf(fp_out, "%s 0 0\n", PAGE); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s 0 0\n", ENDPAGE); + } else { + fprintf(fp_out, "%s 0 0\n", PAGE); + fprintf(fp_out, "save showpage restore\n"); + fprintf(fp_out, "%s 0 0\n", ENDPAGE); + } /* End else */ + } else copypage(pages[j].start, pages[j].stop); + +} /* End of writepages */ + +/*****************************************************************************/ + +copypage(start, stop) + + long start; /* starting from this offset */ + long stop; /* and ending here */ + +{ + +/* + * + * Copies the page beginning at offset start and ending at stop to the output + * file. Global definitions are skipped since they've already been added to the + * prologue. + * + */ + + fseek(fp_in, start, 0); + + while ( ftell(fp_in) < stop && fgets(buf, sizeof(buf), fp_in) != NULL ) + if ( buf[0] == '%' && strcmp(buf, BEGINGLOBAL) == 0 ) + while ( fgets(buf, sizeof(buf), fp_in) != NULL && strcmp(buf, ENDGLOBAL) != 0 ) ; + else fprintf(fp_out, "%s", buf); + +} /* End of copypage */ + +/*****************************************************************************/ + +trailer() + +{ + +/* + * + * Makes sure everything from the TRAILER string to EOF is copied to the output + * file. + * + */ + + if ( endoff > 0 ) { + fprintf(fp_out, "%s", TRAILER); + fseek(fp_in, endoff, 0); + while ( fgets(buf, sizeof(buf), fp_in) != NULL ) + fprintf(fp_out, "%s", buf); + } /* End if */ + +} /* End of trailer */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postreverse/postreverse.h b/sys/src/cmd/postscript/postreverse/postreverse.h new file mode 100755 index 000000000..edae7a277 --- /dev/null +++ b/sys/src/cmd/postscript/postreverse/postreverse.h @@ -0,0 +1,21 @@ +/* + * + * An array of type Pages is used to keep track of the starting and ending byte + * offsets for the pages we've been asked to print. + * + */ + +typedef struct { + long start; /* page starts at this byte offset */ + long stop; /* and ends here */ + int empty; /* dummy page if TRUE */ +} Pages; + +/* + * + * Some of the non-integer functions in postreverse.c. + * + */ + +char *copystdin(); + diff --git a/sys/src/cmd/postscript/postscript.mk b/sys/src/cmd/postscript/postscript.mk new file mode 100755 index 000000000..6e65d2e58 --- /dev/null +++ b/sys/src/cmd/postscript/postscript.mk @@ -0,0 +1,202 @@ +# +# Top level makefile. Instructions are included here and in the README file. +# +# First save a copy of this file. Then adjust the following definitions (all +# come immediatedly after the initial block of comments): +# +# MAKE where make lives +# +# MAKEFILE name of this file - for recursive make calls. Must change +# if you rename this file. +# +# SYSTEM best match for your version of Unix. Current choices for +# SYSTEM are: +# +# SYSV - System V +# V9 - Ninth Edition +# BSD4_2 - Berkeley (eg. Sun) +# +# Controls conditional compilation in a few places. +# +# VERSION refers to the Version of the DWB package +# +# GROUP group assigned to all installed files +# +# OWNER owner of everything that's installed +# +# HOSTDIR hostresident font directory for PostScript printers. Only +# used in the font download program. +# +# FONTDIR width table directory - for troff and dpost +# +# MAN1DIR command manpages. A command and its manpage are installed +# together - there's no easy way to avoid it. Setting MAN1DIR +# to an existing temporary directory (e.g. /tmp) means an +# install will work but manpages won't go anywhere permanent. +# MAN1DIR must already exist - it will not be created during +# an install. +# +# POSTBIN where most PostScript support programs go. dpost and picpack +# are the exceptions. +# +# POSTLIB prologues and miscellaneous PostScript files. Primarily for +# the programs that live in POSTBIN. +# +# CFLGS common compiler options - used to build CFLAGS in the low +# level makefiles. CFLGS and LDFLGS are best set on the make +# command line. +# +# LDFLGS common link editor options - used to build LDFLAGS in the +# low level makefiles. LDFLGS and CFLGS are best set on the +# make command line. +# +# DKHOST set it to TRUE to compile the DKHOST Datakit support code +# in postio. Temporarily resets SYSTEM to SYSV if DKHOST is +# TRUE and SYSTEM is BSD4_2. Ignored if SYSTEM is not SYSV +# or BSD4_2. +# +# DKSTREAMS enables streams based DKHOST support in postio when DKHOST +# is TRUE and SYSTEM is SYSV or BSD4_2. Choices are TRUE, +# FALSE, or a stream module name (e.g. dknetty or dkty). TRUE +# selects dknetty. Newer systems may expect dkty. +# +# ROUNDPAGE must only be set to TRUE or FALSE. TRUE means translators +# include code that maps clipping path dimensions into known +# paper sizes. +# +# TARGETS the default list of what's built by make. Each target must +# be the name of a source directory. A target that names a +# non-existent source directory is ignored. Setting TARGETS +# on the make command line overrides the default list. +# +# Source files must be updated whenever this file changes. If you change any +# definitions type, +# +# make -f postscript.mk changes +# +# to update the source files, man pages, and low level makefiles. +# +# To build (but not install) the default package (i.e. everything named by +# TARGETS) type, +# +# make -f postscript.mk all +# +# The recommended way to build and install the package is, +# +# make -f postscript.mk all install +# +# Although you'll likely have to be root for the install to work. +# +# After the package is installed use, +# +# make -f postscript.mk clobber +# +# to delete binary files and compiled programs from the source directories. +# +# Set TARGETS on the command line to select part of the package. For example, +# +# make -f postscript.mk TARGETS="dpost devpost" all install +# +# builds and installs dpsot and the PostScript font tables. Quotes hide white +# space from the shell. +# + +MAKE=/bin/make +MAKEFILE=postscript.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +ROOT= +FONTDIR=$(ROOT)/usr/lib/font +HOSTDIR=$(ROOT)/usr/lib/font/postscript +MAN1DIR=$(ROOT)/tmp +POSTBIN=$(ROOT)/usr/bin/postscript +POSTLIB=$(ROOT)/usr/lib/postscript +TMACDIR=$(ROOT)/usr/lib/tmac + +COMMONDIR=common +CURRENTDIR=. + +CFLGS=-O +LDFLGS=-s + +DKHOST=FALSE +DKSTREAMS=FALSE +ROUNDPAGE=TRUE + +# +# $(TARGETS) is the default list of things built by make. Pick dpost or +# dpost.utf but not both! +# + +TARGETS=buildtables\ + common\ + cropmarks\ + devLatin1\ + devpost\ + download\ + dpost.utf\ + grabit\ + hardcopy\ + mpictures\ + picpack\ + postbgi\ + postdaisy\ + postdmd\ + postgif\ + postio\ + postmd\ + postprint\ + postreverse\ + posttek\ + printfont\ + psencoding\ + psfiles\ + trofftable + +ACTION=all + +all : $(TARGETS) + +clean clobber : + @$(MAKE) -e -f $(MAKEFILE) MAKE=$(MAKE) ACTION=$@ $(TARGETS) + +install changes : + @SYSTEM='$(SYSTEM)'; export SYSTEM; \ + VERSION='$(VERSION)'; export VERSION; \ + GROUP='$(GROUP)'; export GROUP; \ + OWNER='$(OWNER)'; export OWNER; \ + FONTDIR='$(FONTDIR)'; export FONTDIR; \ + HOSTDIR='$(HOSTDIR)'; export HOSTDIR; \ + MAN1DIR='$(MAN1DIR)'; export MAN1DIR; \ + POSTBIN='$(POSTBIN)'; export POSTBIN; \ + POSTLIB='$(POSTLIB)'; export POSTLIB; \ + TMACDIR='$(TMACDIR)'; export TMACDIR; \ + ROUNDPAGE='$(ROUNDPAGE)'; export ROUNDPAGE; \ + $(MAKE) -e -f $(MAKEFILE) MAKE=$(MAKE) ACTION=$@ $(TARGETS) + +$(TARGETS) :: + @TARGETS=; unset TARGETS; \ + HFILES=; unset HFILES; \ + OFILES=; unset OFILES; \ + CFLAGS=; unset CFLAGS; \ + LDFLAGS=; unset LDFLAGS; \ + YFLAGS=; unset YFLAGS; \ + SYSTEM='$(SYSTEM)'; export SYSTEM; \ + VERSION='$(VERSION)'; export VERSION; \ + CFLGS='$(CFLGS)'; export CFLGS; \ + LDFLGS='$(LDFLGS)'; export LDFLGS; \ + COMMONDIR='../$(COMMONDIR)'; export COMMONDIR; \ + DKHOST='$(DKHOST)'; export DKHOST; \ + DKSTREAMS='$(DKSTREAMS)'; export DKSTREAMS; \ + if [ -d $@ -a -f $@/$@.mk ]; then \ + cd $@; \ + echo "---- Making $(ACTION) in directory $(CURRENTDIR)/$@ ----"; \ + $(MAKE) -e -f $@.mk MAKE=$(MAKE) $(ACTION); \ + echo; \ + fi + diff --git a/sys/src/cmd/postscript/posttek/README b/sys/src/cmd/postscript/posttek/README new file mode 100755 index 000000000..f46380669 --- /dev/null +++ b/sys/src/cmd/postscript/posttek/README @@ -0,0 +1,4 @@ + +Tektronix 4014 to PostScript translator. Much of the code was +borrowed from the 5620 Tektronix emulator. + diff --git a/sys/src/cmd/postscript/posttek/mkfile b/sys/src/cmd/postscript/posttek/mkfile new file mode 100755 index 000000000..d5549b2d5 --- /dev/null +++ b/sys/src/cmd/postscript/posttek/mkfile @@ -0,0 +1,33 @@ +</$objtype/mkfile + +<../config + +TARG=posttek +OFILES=posttek.$O\ + +COMMONDIR=../common + +HFILES=posttek.h\ + $COMMONDIR/comments.h\ + $COMMONDIR/ext.h\ + $COMMONDIR/gen.h\ + $COMMONDIR/path.h\ + +BIN=$POSTBIN +LIB=$COMMONDIR/com.a$O + +</sys/src/cmd/mkone + +CC=pcc +LD=pcc +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B + +install:V: $POSTLIB/posttek.ps + +$POSTLIB/posttek.ps : posttek.ps + cp $prereq $target + +$LIB: + cd $COMMONDIR + mk install + mk clean diff --git a/sys/src/cmd/postscript/posttek/posttek.c b/sys/src/cmd/postscript/posttek/posttek.c new file mode 100755 index 000000000..a2b1b1fae --- /dev/null +++ b/sys/src/cmd/postscript/posttek/posttek.c @@ -0,0 +1,1199 @@ +/* + * + * posttek - PostScript translator for tektronix 4014 files + * + * A program that can be used to translate tektronix 4014 files into PostScript. + * Most of the code was borrowed from the tektronix 4014 emulator that was written + * for DMDs. Things have been cleaned up some, but there's still plently that + * could be done. + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how the program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects + * to find the current page number on the stack. + * + * v + * + * mark dx1 dy1 ... dxn dyn x y v mark + * + * Draws the vector described by the numbers on the stack. The top two + * numbers are the starting point. The rest are relative displacements + * from the preceeding point. Must make sure we don't put too much on + * the stack! + * + * t + * + * x y string t - + * + * Prints the string that's on the top of the stack starting at point + * (x, y). + * + * p + * + * x y p - + * + * Marks the point (x, y) with a circle whose radius varies with the + * current intensity setting. + * + * i + * + * percent focus i - + * + * Changes the size of the circle used to mark individual points to + * percent of maximum for focused mode (focus=1) or defocused mode + * (focus=0). The implementation leaves much to be desired! + * + * l + * + * mark array l mark + * + * Set the line drawing mode according to the description given in array. + * The arrays that describe the different line styles are declared in + * STYLES (file posttek.h). The array really belongs in the prologue! + * + * w + * + * n w - + * + * Adjusts the line width for vector drawing. Used to select normal (n=0) + * or defocused (n=1) mode. + * + * f + * + * size f - + * + * Changes the size of the font that's used to print characters in alpha + * mode. size is the tektronix character width and is used to choose an + * appropriate point size in the current font. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * The default line width is zero, which forces lines to be one pixel wide. That + * works well on 'write to black' engines but won't be right for 'write to white' + * engines. The line width can be changed using the -w option, or you can change + * the initialization of linewidth in the prologue. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <fcntl.h> + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable definitions */ +#include "posttek.h" /* control codes and other definitions */ + +char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI"; + +char *prologue = POSTTEK; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +int charheight[] = CHARHEIGHT; /* height */ +int charwidth[] = CHARWIDTH; /* and width arrays for tek characters */ +int tekfont = TEKFONT; /* index into charheight[] and charwidth[] */ + +char intensity[] = INTENSITY; /* special point intensity array */ +char *styles[] = STYLES; /* description of line styles */ +int linestyle = 0; /* index into styles[] */ +int linetype = 0; /* 0 for normal, 1 for defocused */ + +int dispmode = ALPHA; /* current tektronix state */ +int points = 0; /* points making up the current vector */ +int characters = 0; /* characters waiting to be printed */ +int pen = UP; /* just for point plotting */ +int margin = 0; /* left edge - ALPHA state */ + +Point cursor; /* should be current cursor position */ + +Fontmap fontmap[] = FONTMAP; /* for translating font names */ +char *fontname = "Courier"; /* use this PostScript font */ + +int page = 0; /* page we're working on */ +int printed = 0; /* printed this many pages */ + +FILE *fp_in; /* read from this file */ +FILE *fp_out = stdout; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A simple program that can be used to translate tektronix 4014 files into + * PostScript. Most of the code was taken from the DMD tektronix 4014 emulator, + * although things have been cleaned up some. + * + */ + + argv = agv; /* so everyone can use them */ + argc = agc; + + prog_name = argv[0]; /* just for error messages */ + + init_signals(); /* sets up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* handle the command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* nothing could be wrong */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Make sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* value returned by getopt() */ + +/* + * + * Reads and processes the command line options. Added the -P option so arbitrary + * PostScript code can be passed through. Expect it could be useful for changing + * definitions in the prologue for which options have not been defined. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s store\n", optarg); + break; + + case 'f': /* use this PostScript font */ + fontname = get_font(optarg); + fprintf(stdout, "/font /%s def\n", fontname); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'w': /* line width */ + fprintf(stdout, "/linewidth %s def\n", optarg); + break; + + case 'x': /* shift horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* PostScript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't know the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +char *get_font(name) + + char *name; /* name the user asked for */ + +{ + + int i; /* for looking through fontmap[] */ + +/* + * + * Called from options() to map a user's font name into a legal PostScript name. + * If the lookup fails *name is returned to the caller. That should let you choose + * any PostScript font. + * + */ + + for ( i = 0; fontmap[i].name != NULL; i++ ) + if ( strcmp(name, fontmap[i].name) == 0 ) + return(fontmap[i].val); + + return(name); + +} /* End of get_font */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line arguments are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + if ( argc < 1 ) + statemachine(fp_in = stdin); + else { /* at least one argument is left */ + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + statemachine(fp_in); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + } /* End else */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with all the input files, so mark the end of the pages with a TRAILER + * comment, make sure the last page prints, and add things like the PAGES comment + * that can only be determined after all the input files have been read. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct provided it's not NULL. Accounting + * is requested using the -A or -J options. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +statemachine(fp) + + FILE *fp; /* used to set fp_in */ + +{ + +/* + * + * Controls the translation of the next input file. Tektronix states (dispmode) + * are typically changed in control() and esc(). + * + */ + + redirect(-1); /* get ready for the first page */ + formfeed(); + dispmode = RESET; + + while ( 1 ) + switch ( dispmode ) { + case RESET: + reset(); + break; + + case ALPHA: + alpha(); + break; + + case GIN: + gin(); + break; + + case GRAPH: + graph(); + break; + + case POINT: + case SPECIALPOINT: + point(); + break; + + case INCREMENTAL: + incremental(); + break; + + case EXIT: + formfeed(); + return; + } /* End switch */ + +} /* End of statemachine */ + +/*****************************************************************************/ + +reset() + +{ + +/* + * + * Called to reset things, typically only at the beginning of each input file. + * + */ + + tekfont = -1; + home(); + setfont(TEKFONT); + setmode(ALPHA); + +} /* End of reset */ + +/*****************************************************************************/ + +alpha() + +{ + + int c; /* next character */ + int x, y; /* cursor will be here when we're done */ + +/* + * + * Takes care of printing characters in the current font. + * + */ + + if ( (c = nextchar()) == OUTMODED ) + return; + + if ( (c < 040) && ((c = control(c)) <= 0) ) + return; + + x = cursor.x; /* where the cursor is right now */ + y = cursor.y; + + switch ( c ) { + case DEL: + return; + + case BS: + if ((x -= charwidth[tekfont]) < margin) + x = TEKXMAX - charwidth[tekfont]; + break; + + case NL: + y -= charheight[tekfont]; + break; + + case CR: + x = margin; + break; + + case VT: + if ((y += charheight[tekfont]) >= TEKYMAX) + y = 0; + break; + + case HT: + case ' ': + default: + if ( characters++ == 0 ) + fprintf(fp_out, "%d %d (", cursor.x, cursor.y); + switch ( c ) { + case '(': + case ')': + case '\\': + putc('\\', fp_out); + + default: + putc(c, fp_out); + } /* End switch */ + x += charwidth[tekfont]; + move(x, y); + break; + } /* End switch */ + + if (x >= TEKXMAX) { + x = margin; + y -= charheight[tekfont]; + } /* End if */ + + if (y < 0) { + y = TEKYMAX - charheight[tekfont]; + x -= margin; + margin = (TEKXMAX/2) - margin; + if ((x += margin) > TEKXMAX) + x -= margin; + } /* End if */ + + if ( y != cursor.y || x != cursor.x ) + text(); + + move(x, y); + +} /* End of alpha */ + +/*****************************************************************************/ + +graph() + +{ + + int c; /* next character */ + int b; /* for figuring out loy */ + int x, y; /* next point in the vector */ + static int hix, hiy; /* upper */ + static int lox, loy; /* and lower part of the address */ + static int extra; /* for extended addressing */ + +/* + * + * Handles things when we're in GRAPH, POINT, or SPECIALPOINT mode. + * + */ + + if ((c = nextchar()) < 040) { + control(c); + return; + } /* End if */ + + if ((c & 0140) == 040) { /* new hiy */ + hiy = c & 037; + do + if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) + return; + while (c == 0); + } /* End if */ + + if ((c & 0140) == 0140) { /* new loy */ + b = c & 037; + do + if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) + return; + while (c == 0); + if ((c & 0140) == 0140) { /* no, it was extra */ + extra = b; + loy = c & 037; + do + if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) + return; + while (c == 0); + } else loy = b; + } /* End if */ + + if ((c & 0140) == 040) { /* new hix */ + hix = c & 037; + do + if (((c = nextchar()) < 040) && ((c = control(c)) == OUTMODED)) + return; + while (c == 0); + } /* End if */ + + lox = c & 037; /* this should be lox */ + if (extra & 020) + margin = TEKXMAX/2; + + x = (hix<<7) | (lox<<2) | (extra & 03); + y = (hiy<<7) | (loy<<2) | ((extra & 014)>>2); + + if ( points > 100 ) { /* don't put too much on the stack */ + draw(); + points = 1; + } /* End if */ + + if ( points++ ) + fprintf(fp_out, "%d %d\n", cursor.x - x, cursor.y - y); + + move(x, y); /* adjust the cursor */ + +} /* End of graph */ + +/*****************************************************************************/ + +point() + +{ + + int c; /* next input character */ + +/* + * + * Special point mode permits gray scaling by varying the size of the stored + * point, which is controlled by an intensity character that preceeds each point + * address. + * + */ + + if ( dispmode == SPECIALPOINT ) { + if ( (c = nextchar()) < 040 || c > 0175 ) + return(control(c)); + + fprintf(fp_out, "%d %d i\n", intensity[c - ' '], c & 0100); + } /* End if */ + + graph(); + draw(); + +} /* End of point */ + +/*****************************************************************************/ + +incremental() + +{ + + int c; /* for the next few characters */ + int x, y; /* cursor position when we're done */ + +/* + * + * Handles incremental plot mode. It's entered after the RS control code and is + * used to mark points relative to our current position. It's typically followed + * by one or two bytes that set the pen state and are used to increment the + * current position. + * + */ + + if ( (c = nextchar()) == OUTMODED ) + return; + + if ( (c < 040) && ((c = control(c)) <= 0) ) + return; + + x = cursor.x; /* where we are right now */ + y = cursor.y; + + if ( c & 060 ) + pen = ( c & 040 ) ? UP : DOWN; + + if ( c & 04 ) y++; + if ( c & 010 ) y--; + if ( c & 01 ) x++; + if ( c & 02 ) x--; + + move(x, y); + + if ( pen == DOWN ) { + points = 1; + draw(); + } /* End if */ + +} /* End of incremental */ + +/*****************************************************************************/ + +gin() + +{ + +/* + * + * All we really have to do for GIN mode is make sure it's properly ended. + * + */ + + control(nextchar()); + +} /* End of gin */ + +/*****************************************************************************/ + +control(c) + + int c; /* check this control character */ + +{ + +/* + * + * Checks character c and does special things, like mode changes, that depend + * not only on the character, but also on the current state. If the mode changed + * becuase of c, OUTMODED is returned to the caller. In all other cases the + * return value is c or 0, if c doesn't make sense in the current mode. + * + */ + + switch ( c ) { + case BEL: + return(0); + + case BS: + case HT: + case VT: + return(dispmode == ALPHA ? c : 0); + + case CR: + if ( dispmode != ALPHA ) { + setmode(ALPHA); + ungetc(c, fp_in); + return(OUTMODED); + } else return(c); + + case FS: + if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) { + setmode(POINT); + return(OUTMODED); + } /* End if */ + return(0); + + case GS: + if ( (dispmode == ALPHA) || (dispmode == GRAPH) ) { + setmode(GRAPH); + return(OUTMODED); + } /* End if */ + return(0); + + case NL: + ungetc(CR, fp_in); + return(dispmode == ALPHA ? c : 0); + + case RS: + if ( dispmode != GIN ) { + setmode(INCREMENTAL); + return(OUTMODED); + } /* End if */ + return(0); + + case US: + if ( dispmode == ALPHA ) + return(0); + setmode(ALPHA); + return(OUTMODED); + + case ESC: + return(esc()); + + case OUTMODED: + return(c); + + default: + return(c < 040 ? 0 : c); + } /* End switch */ + +} /* End of control */ + +/*****************************************************************************/ + +esc() + +{ + + int c; /* next input character */ + int ignore; /* skip it if nonzero */ + +/* + * + * Handles tektronix escape code. Called from control() whenever an ESC character + * is found in the input file. + * + */ + + do { + c = nextchar(); + ignore = 0; + switch ( c ) { + case CAN: + return(0); + + case CR: + ignore = 1; + break; + + case ENQ: + setmode(ALPHA); + return(OUTMODED); + + case ETB: + return(0); + + case FF: + formfeed(); + setmode(ALPHA); + return(OUTMODED); + + case FS: + if ( (dispmode == INCREMENTAL) || ( dispmode == GIN) ) + return(0); + setmode(SPECIALPOINT); + return(OUTMODED); + + case SI: + case SO: + return(0); + + case SUB: + setmode(GIN); + return(OUTMODED); + + case OUTMODED: + return(OUTMODED); + + case '8': + case '9': + case ':': + case ';': + setfont(c - '8'); + return(0); + + default: + if ( c == '?' && dispmode == GRAPH ) + return(DEL); + if ( (c<'`') || (c>'w') ) + break; + c -= '`'; + if ( (c & 010) != linetype ) + fprintf(fp_out, "%d w\n", (linetype = (c & 010))/010); + if ( ((c + 1) & 7) >= 6 ) + break; + if ( (c + 1) & 7 ) + if ( (c & 7) != linestyle ) { + linestyle = c & 7; + setmode(dispmode); + fprintf(fp_out, "%s l\n", styles[linestyle]); + } /* End if */ + return(0); + } /* End switch */ + + } while (ignore); + + return(0); + +} /* End of esc */ + +/*****************************************************************************/ + +move(x, y) + + int x, y; /* move the cursor here */ + +{ + +/* + * + * Moves the cursor to the point (x, y). + * + */ + + cursor.x = x; + cursor.y = y; + +} /* End of move */ + +/*****************************************************************************/ + +setmode(mode) + + int mode; /* this should be the new mode */ + +{ + +/* + * + * Makes sure the current mode is properly ended and then sets dispmode to mode. + * + */ + + switch ( dispmode ) { + case ALPHA: + text(); + break; + + case GRAPH: + draw(); + break; + + case INCREMENTAL: + pen = UP; + break; + } /* End switch */ + + dispmode = mode; + +} /* End of setmode */ + +/*****************************************************************************/ + +home() + +{ + +/* + * + * Makes sure the cursor is positioned at the upper left corner of the page. + * + */ + + margin = 0; + move(0, TEKYMAX); + +} /* End of home */ + +/*****************************************************************************/ + +setfont(newfont) + + int newfont; /* use this font next */ + +{ + +/* + * + * Generates the call to the procedure that's responsible for changing the + * tektronix font (really just the size). + * + */ + + if ( newfont != tekfont ) { + setmode(dispmode); + fprintf(fp_out, "%d f\n", charwidth[newfont]); + } /* End if */ + + tekfont = newfont; + +} /* End of setfont */ + +/*****************************************************************************/ + +text() + +{ + +/* + * + * Makes sure any text we've put on the stack is printed. + * + */ + + if ( dispmode == ALPHA && characters > 0 ) + fprintf(fp_out, ") t\n"); + + characters = 0; + +} /* End of text */ + +/*****************************************************************************/ + +draw() + +{ + +/* + * + * Called whenever we need to draw a vector or plot a point. Nothing will be + * done if points is 0 or if it's 1 and we're in GRAPH mode. + * + */ + + if ( points > 1 ) /* it's a vector */ + fprintf(fp_out, "%d %d v\n", cursor.x, cursor.y); + else if ( points == 1 && dispmode != GRAPH ) + fprintf(fp_out, "%d %d p\n", cursor.x, cursor.y); + + points = 0; + +} /* End of draw */ + +/*****************************************************************************/ + +formfeed() + +{ + +/* + * + * Usually called when we've finished the last page and want to get ready for the + * next one. Also used at the beginning and end of each input file, so we have to + * be careful about exactly what's done. + * + */ + + setmode(dispmode); /* end any outstanding text or graphics */ + + if ( fp_out == stdout ) /* count the last page */ + printed++; + + fprintf(fp_out, "cleartomark\n"); + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + + if ( ungetc(getc(fp_in), fp_in) == EOF ) + redirect(-1); + else redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d pagesetup\n", printed+1); + fprintf(fp_out, "%d f\n", charwidth[tekfont]); + fprintf(fp_out, "%s l\n", styles[linestyle]); + + home(); + +} /* End of formfeed */ + +/*****************************************************************************/ + +nextchar() + +{ + + int ch; /* next input character */ + +/* + * + * Reads the next character from the current input file and returns it to the + * caller. When we're finished with the file dispmode is set to EXIT and OUTMODED + * is returned to the caller. + * + */ + + if ( (ch = getc(fp_in)) == EOF ) { + setmode(EXIT); + ch = OUTMODED; + } /* End if */ + + return(ch); + +} /* End of nextchar */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/posttek/posttek.h b/sys/src/cmd/postscript/posttek/posttek.h new file mode 100755 index 000000000..99d10133c --- /dev/null +++ b/sys/src/cmd/postscript/posttek/posttek.h @@ -0,0 +1,183 @@ +/* + * + * Tektronix 4014 control codes. + * + */ + +#define NUL '\000' +#define SOH '\001' +#define STX '\002' +#define ETX '\003' +#define EOT '\004' +#define ENQ '\005' +#define ACK '\006' +#define BEL '\007' +#define BS '\010' +#define HT '\011' +#define NL '\012' +#define VT '\013' +#define FF '\014' +#define CR '\015' +#define SO '\016' +#define SI '\017' +#define DLE '\020' +#define DC1 '\021' +#define DC2 '\022' +#define DC3 '\023' +#define DC4 '\024' +#define NAK '\025' +#define SYN '\026' +#define ETB '\027' +#define CAN '\030' +#define EM '\031' +#define SUB '\032' +#define ESC '\033' +#define FS '\034' +#define GS '\035' +#define RS '\036' +#define US '\037' +#define DEL '\177' + +/* + * + * A few definitions used to classify the different tektronix states. OUTMODED + * is returned by control() and esc(), and typically means the state has changed. + * + */ + +#define OUTMODED -1 +#define ALPHA 0 +#define GIN 1 +#define GRAPH 2 +#define POINT 3 +#define SPECIALPOINT 4 +#define INCREMENTAL 5 +#define RESET 6 +#define EXIT 7 + +/* + * + * The pen state, either UP or DOWN, controls whether vectors are drawn. + * + */ + +#define UP 0 +#define DOWN 1 + +/* + * + * Coordinates of the upper right corner of the screen - almost the real screen + * dimensions. + * + */ + +#define TEKXMAX 4096 +#define TEKYMAX 3120 + +/* + * + * The size of the spot in SPECIALPOINT mode is controlled by a non-linear + * function that has a domain that consists of the integers from 040 to 0175. + * The next definition is used to initialize the special point mode intensity + * array that implements the function. Data came from table F-6 in the tektronix + * 4014 manual. + * + */ + +#define INTENSITY \ + \ + { \ + 14, 16, 17, 19, 20, 22, 23, 25, \ + 28, 31, 34, 38, 41, 44, 47, 50, \ + 56, 62, 69, 75, 81, 88, 94,100, \ + 56, 62, 69, 75, 81, 88, 94,100, \ + 0, 1, 1, 1, 1, 1, 1, 2, \ + 2, 2, 2, 2, 3, 3, 3, 3, \ + 4, 4, 4, 5, 5, 5, 6, 6, \ + 7, 8, 9, 10, 11, 12, 12, 13, \ + 14, 16, 17, 19, 20, 22, 23, 25, \ + 28, 31, 34, 38, 41, 44, 47, 50, \ + 56, 62, 69, 75, 81, 88, 94,100, \ + 56, 62, 69, 75, 81, 88, 94,100, \ + } + +/* + * + * The next two definitions give the height and width of characters in the four + * different sizes available on tektronix terminals. TEKFONT is the default index + * into CHARHEIGHT and CHARWIDTH. + * + */ + +#define CHARHEIGHT {88, 82, 53, 48} +#define CHARWIDTH {56, 51, 34, 31} +#define TEKFONT 2 + +/* + * + * The entries defined in STYLES are passed on to the PostScript operator setdash. + * They're used to implement the different tektronix line styles. Belongs in the + * prologue! + * + */ + +#define STYLES \ + \ + { \ + "[]", \ + "[.5 2]", \ + "[.5 2 4 2]", \ + "[4 4]", \ + "[8 4]", \ + "[]" \ + } + +/* + * + * Variables of type Point are used to keep track of the cursor position. + * + */ + +typedef struct { + int x; + int y; +} Point; + +/* + * + * An array of type Fontmap helps convert font names requested by users into + * legitimate PostScript names. The array is initialized using FONTMAP, which must + * end with an entry that has NULL defined as its name field. + * + */ + +typedef struct { + char *name; /* user's font name */ + char *val; /* corresponding PostScript name */ +} Fontmap; + +#define FONTMAP \ + \ + { \ + "R", "Courier", \ + "I", "Courier-Oblique", \ + "B", "Courier-Bold", \ + "CO", "Courier", \ + "CI", "Courier-Oblique", \ + "CB", "Courier-Bold", \ + "CW", "Courier", \ + "PO", "Courier", \ + "courier", "Courier", \ + "cour", "Courier", \ + "co", "Courier", \ + NULL, NULL \ + } + +/* + * + * Some of the non-integer valued functions in posttek.c. + * + */ + +char *get_font(); + diff --git a/sys/src/cmd/postscript/posttek/posttek.ps b/sys/src/cmd/postscript/posttek/posttek.ps new file mode 100755 index 000000000..ee2428ced --- /dev/null +++ b/sys/src/cmd/postscript/posttek/posttek.ps @@ -0,0 +1,106 @@ +% +% Version 3.3.2 prologue for tektronix 4014 files. +% + +/#copies 1 store +/aspectratio 1 def +/fixlinewidth true def +/font /Courier def +/formsperpage 1 def +/landscape true def +/linewidth 0 def +/magnification 1 def +/margin 10 def +/orientation 0 def +/rotation 1 def +/screenheight 3120 def +/screenwidth 4150 def +/spotsize 1 def +/xoffset 0 def +/yoffset 0 def + +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/kshow {kshow} bind def % so later references don't bind + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + + pagedimensions + /scaling + height margin sub screenheight div + width margin sub screenwidth div + min def + xcenter ycenter translate + orientation rotation mul rotate + xoffset inch yoffset inch translate + magnification dup aspectratio mul scale + scaling scaling scale + screenwidth 2 div neg screenheight 2 div neg translate + + tietodevicespace + linewidth scaling div setlinewidth + 1 setlinecap + newpath +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def} bind def + +/tietodevicespace { + fixlinewidth linewidth 0 gt and linewidth 1 lt and { + /moveto { + 2 copy /Y exch def /X exch def + transform round exch round exch itransform + moveto + } bind def + /lineto { + 2 copy /Y exch def /X exch def + transform round exch round exch itransform + lineto + } bind def + /rlineto {Y add exch X add exch lineto} bind def + /v V 0 get bind def + } if +} def + +/V [{moveto counttomark 2 idiv {rlineto} repeat stroke}] def +/v V 0 get bind def +/p {newpath spotsize 0 360 arc fill} bind def + +/l {{scaling div} forall counttomark array astore 0 setdash} bind def +/w {linewidth 0 eq {.3} {linewidth} ifelse mul linewidth add scaling div setlinewidth} bind def +/i {3 mul 4 sub -100 div mul .5 add /spotsize exch def} bind def + +/f {/charwidth exch def font findfont charwidth .6 div scalefont setfont} bind def + +/t { + 3 1 roll moveto + currentpoint { + pop pop + exch charwidth add exch + moveto currentpoint + } 4 -1 roll kshow + pop pop +} bind def + +/done {/lastpage where {pop lastpage} if} def diff --git a/sys/src/cmd/postscript/printfont/mkfile b/sys/src/cmd/postscript/printfont/mkfile new file mode 100755 index 000000000..8ddadb25f --- /dev/null +++ b/sys/src/cmd/postscript/printfont/mkfile @@ -0,0 +1,22 @@ +</$objtype/mkfile + +<../config + +POSTBIN=/rc/bin + +all:V: printfont + +install installall:V: $POSTBIN/printfont $POSTLIB/printfont.ps + +clean nuke:V: + rm -f printfont + +$POSTBIN/printfont: printfont + cp $prereq $target + +$POSTLIB/printfont.ps: printfont.ps + cp $prereq $target + +printfont: printfont.rc + sed 's?^POSTLIB=.*?POSTLIB='$POSTLIB'?' printfont.rc >printfont + chmod 775 printfont diff --git a/sys/src/cmd/postscript/printfont/printfont.ps b/sys/src/cmd/postscript/printfont/printfont.ps new file mode 100755 index 000000000..7a881a4d4 --- /dev/null +++ b/sys/src/cmd/postscript/printfont/printfont.ps @@ -0,0 +1,321 @@ +% +% Formatted font dump. Assumes all fonts include valid FontBBox arrays. +% + +/#copies 1 store +/aspectratio 1 def +/landscape false def +/magnification 1 def +/margin 10 def +/orientation 0 def +/rotation 1 def +/xoffset 0 def +/yoffset 0 def + +/axescount 0 def +/charwidth false def +/graynotdef 0.85 def +/hireslinewidth 0.2 def +/longnames false def +/maxsize 6.0 def +/minsize 4.5 def +/numbercell true def +/radix 16 def +/labelfont /Helvetica def +/labelspace 36 def +/zerocell 0 def + +/roundpage true def +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} def +/min {2 copy gt {exch} if pop} def +/max {2 copy lt {exch} if pop} def + +/LLx {0 get} bind def +/LLy {1 get} bind def +/URx {2 get} bind def +/URy {3 get} bind def +/BBoxHeight {dup URy exch LLy sub} bind def +/BBoxWidth {dup URx exch LLx sub} bind def + +/setup { + /graylevels [1 0 0] def + /scratchstring 512 string def + /Product statusdict begin /product where {pop product}{(Unknown)} ifelse end def + /Resolution 0 72 dtransform dup mul exch dup mul add sqrt cvi def + /Version /version where {pop version}{(???)} ifelse def + + landscape {/orientation 90 orientation add def} if + + pagedimensions + xcenter ycenter translate + orientation rotation mul rotate + width 2 div neg height 2 div translate + xoffset inch yoffset inch neg translate + margin dup neg translate + 0 labelspace .75 mul neg translate + magnification dup aspectratio mul scale + 0 0 transform round exch round exch itransform translate + + currentdict /linewidth known not { + /linewidth Resolution 400 le {0}{hireslinewidth} ifelse def + } if +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + roundpage currentdict /roundpagebbox known and {roundpagebbox} if + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def +} def + +/CharSetup { + /chcode exch def + /chname Encoding chcode get def + /chstring ( ) dup 0 chcode put def + /chknown true def + + graylevels 0 1 put % initial cell fill + graylevels 1 0 put % cell text + graylevels 2 0 put % cell border + + FontDict /CharStrings known { + FontDict /CharStrings get chname known not { + /chknown false def + graylevels 0 0 put + graylevels 1 1 put + } if + } if + + chname /.notdef eq { + /chknown false def + graylevels 0 graynotdef put + graylevels 1 graynotdef put + } if + + /chwid chknown + {FontDict 1 scalefont setfont chstring stringwidth pop} + {0} + ifelse def +} bind def + +/CellSetup { + /gridwidth width margin 2 mul sub def + /gridheight height labelspace sub margin 2 mul sub def + /cellwidth gridwidth radix div def + /cellheight gridheight Entries radix div ceiling div def + + cellwidth cellheight dtransform truncate exch truncate exch idtransform + /cellheight exch def + /cellwidth exch def + + labelfont findfont 1 scalefont setfont + /LabelBBox currentfont /FontBBox get TransformBBox def + + LabelBBox 2 0 Encoding { + scratchstring cvs stringwidth pop + 2 copy lt {exch} if + pop + } forall put + + /CellLabelSize + cellheight .20 mul cellwidth .90 mul LabelBBox BestFit + minsize max + maxsize min + def + zerocell CellOrigin cellheight add neg exch neg exch translate +} bind def + +/FontSetup { + FontName findfont 1 scalefont setfont + /BBox currentfont /FontBBox get TransformBBox def + /PointSize cellheight .5 mul cellwidth .8 mul BBox BestFit def + BBox {PointSize mul} forall BBox astore pop + + /xorigin cellwidth BBox BBoxWidth sub 2 div BBox LLx sub def + /yorigin cellheight BBox BBoxHeight sub 2 div BBox LLy sub def +} bind def + +/BestFit { + /bbox exch def + bbox BBoxWidth div exch + bbox BBoxHeight div min +} bind def + +/TransformBBox { % font bbox to user space + aload pop + currentfont /FontMatrix get dtransform 4 2 roll + currentfont /FontMatrix get dtransform 4 2 roll + 4 array astore % should build user space bbox if all zeros +} bind def + +/CellOrigin { + dup + exch radix mod cellwidth mul + exch radix idiv 1 add neg cellheight mul +} bind def + +/CellOutline { + newpath + CellOrigin moveto + cellwidth 0 rlineto + 0 cellheight rlineto + cellwidth neg 0 rlineto + closepath +} bind def + +/LabelCell { + gsave + chcode CellOrigin translate + linewidth .5 mul setlinewidth + labelfont findfont CellLabelSize scalefont setfont + + numbercell { + cellwidth .025 mul cellheight .05 mul moveto + chcode radix scratchstring cvrs show + } if + + charwidth chknown and { + /wid chwid 0.0005 add scratchstring cvs 0 5 getinterval def + cellwidth wid stringwidth pop 1.10 mul sub cellheight .05 mul moveto + wid show + } if + + longnames chknown not or { + cellwidth .025 mul + cellheight LabelBBox URy CellLabelSize mul sub .05 sub moveto + Encoding chcode get scratchstring cvs show + } if + + axescount 1 ge chknown and { % gsave/grestore if not last + newpath + xorigin yorigin translate + + BBox LLx 0 moveto % baseline + BBox URx 0 lineto stroke + + axescount 2 ge { % vertical through current origin + 0 BBox LLy moveto + 0 BBox URy lineto stroke + } if + + axescount 3 ge { % vertical through next origin + chwid PointSize mul BBox LLy + dtransform round exch round exch idtransform moveto + 0 BBox BBoxHeight rlineto stroke + %chwid PointSize mul BBox URy lineto stroke + } if + } if + grestore +} bind def + +/PlaceChar { + FontName findfont PointSize scalefont setfont + chcode CellOrigin moveto + xorigin yorigin rmoveto + ( ) dup 0 chcode put show +} bind def + +/LabelPage { + labelfont findfont labelspace .75 mul .75 mul 18 min scalefont setfont + 0 labelspace .75 mul .25 mul moveto + FontName scratchstring cvs show + + labelfont findfont labelspace .25 mul .75 mul 9 min scalefont setfont + 0 gridheight neg moveto + 0 labelspace .25 mul .75 mul neg rmoveto + Product show ( Version ) show Version show + ( \() show Resolution scratchstring cvs show (dpi\)) show + + gridwidth gridheight neg moveto + 0 labelspace .25 mul .75 mul neg rmoveto + (size=, ) stringwidth pop neg 0 rmoveto + PointSize cvi scratchstring cvs stringwidth pop neg 0 rmoveto + (gray=, ) stringwidth pop neg 0 rmoveto + graynotdef scratchstring cvs stringwidth pop neg 0 rmoveto + (linewidth=) stringwidth pop neg 0 rmoveto + linewidth scratchstring cvs stringwidth pop neg 0 rmoveto + (size=) show PointSize cvi scratchstring cvs show (, ) show + (gray=) show graynotdef scratchstring cvs show (, ) show + (linewidth=) show linewidth scratchstring cvs show +} bind def + +% +% Formatted dump of the encoded characters in a single font. +% + +/PrintFont { + /saveobj save def + /FontName exch def + /FontDict FontName findfont def + /Encoding FontDict /Encoding get def + /Entries Encoding length def + + CellSetup + FontSetup + LabelPage + zerocell 1 Entries 1 sub { + CharSetup + graylevels 0 get setgray + chcode CellOutline fill + graylevels 1 get setgray + LabelCell + PlaceChar + graylevels 2 get setgray + linewidth setlinewidth + chcode CellOutline stroke + } for + showpage + saveobj restore +} bind def + +% +% Dump of all ROM and disk fonts - in alphabetical order. +% + +/AllFonts { + /AllFontNames FontDirectory maxlength array def + AllFontNames 0 0 put + + FontDirectory {pop AllFontNames Insert} forall + + /filenameforall where { + pop + (fonts/*) + {(fonts/) search pop pop pop AllFontNames Insert} + 200 string + filenameforall + } if + + 1 1 AllFontNames 0 get { + AllFontNames exch get cvn PrintFont + } for +} bind def + +/Insert { % name in a sorted list + /List exch def + /Name exch 128 string cvs def + + /Slot 1 def + List 0 get { + Name List Slot get le {exit} if + /Slot Slot 1 add def + } repeat + + List 0 get -1 Slot { + dup List exch get + List 3 1 roll exch 1 add exch put + } for + List Slot Name put + List 0 List 0 get 1 add put +} bind def + diff --git a/sys/src/cmd/postscript/printfont/printfont.rc b/sys/src/cmd/postscript/printfont/printfont.rc new file mode 100755 index 000000000..266102f9d --- /dev/null +++ b/sys/src/cmd/postscript/printfont/printfont.rc @@ -0,0 +1,105 @@ +#!/bin/rc +# Formatted dump of encoded characters in one or more PostScript fonts. +# Arguments should be PostScript font names or the word all, which dumps +# all ROM and disk based fonts. +# + +POSTLIB=/sys/lib/postscript/prologues +PROLOGUE=$POSTLIB/printfont.ps + +OPTIONS='' +COPYFILE='' +MODE=portrait +FONTENCODING=Default + +NONCONFORMING='%!PS' +ENDPROLOG='%%EndProlog' +BEGINSETUP='%%BeginSetup' +ENDSETUP='%%EndSetup' +TRAILER='%%Trailer' + +SETUP=setup + +while (! ~ $#* 0 && ~ $1 -*) { + switch ($1) { + case -a; shift; OPTIONS=$OPTIONS' /axescount $1 def' + case -a*; OPTIONS=$OPTIONS' /axescount '`{echo $1 | sed s/-a//}' def' + + case -b; shift; OPTIONS=$OPTIONS' /radix '$1' def' + case -b*; OPTIONS=$OPTIONS' /radix '`{echo $1 | sed s/-b//}' def' + + case -c; shift; OPTIONS=$OPTIONS' /#copies '$1' store' + case -c*; OPTIONS=$OPTIONS' /#copies '`{echo $1 | sed s/-c//}' store' + + case -f; shift; OPTIONS=$OPTIONS' /labelfont /'$1' def' + case -f*; OPTIONS=$OPTIONS' /labelfont /'`{echo $1 | sed s/-f//}' def' + + case -g; shift; OPTIONS=$OPTIONS' /graynotdef '$1' def' + case -g*; OPTIONS=$OPTIONS' /graynotdef '`{echo $1 | sed s/-g//}' def' + + case -p; shift; MODE=$1 + case -p*; MODE=`{echo $1 | sed s/-p//} + + case -q; OPTIONS=$OPTIONS' /longnames false def /charwidth false def' + + case -m; shift; OPTIONS=$OPTIONS' /magnification '$1' def' + case -m*; OPTIONS=$OPTIONS' /magnification '`{echo $1 | sed s/-m//}' def' + + case -v; OPTIONS=$OPTIONS' /longnames true def /charwidth true def' + + case -w; shift; OPTIONS=$OPTIONS' /linewidth '$1' def' + case -w*; OPTIONS=$OPTIONS' /linewidth '`{echo $1 | sed s/-w//}' def' + + case -x; shift; OPTIONS=$OPTIONS' /xoffset '$1' def' + case -x*; OPTIONS=$OPTIONS' /xoffset '`{echo $1 | sed s/-x//}' def' + + case -y; shift; OPTIONS=$OPTIONS' /yoffset '$1' def' + case -y*; OPTIONS=$OPTIONS' /yoffset '`{echo $1 | sed s/-y//}' def' + + case -z; shift; OPTIONS=$OPTIONS' /zerocell '$1' def' + case -z*; OPTIONS=$OPTIONS' /zerocell '`{echo $1 | sed s/-z//}' def' + + case -C; shift; COPYFILE=$COPYFILE' '$1 + case -C*; COPYFILE=$COPYFILE' '`{echo $1 | sed s/-C//} + + case -E; shift; FONTENCODING=$1 + case -E*; FONTENCODING=`{echo $1 | sed s/-E//} + + case -L; shift; PROLOGUE=$1 + case -L*; PROLOGUE=`{echo $1 | sed s/-L//} + + case -*; echo $0:' illegal option '$1 >[1=2]; exit 1 + } + shift +} + +switch ($MODE) { +case l*; OPTIONS=$OPTIONS' /landscape true def' +case *; OPTIONS=$OPTIONS' /landscape false def' +} + +echo $NONCONFORMING +cat $PROLOGUE +echo $ENDPROLOG +echo $BEGINSETUP +if (~ $#COPYFILE 0 || ~ $COPYFILE '') COPYFILE=/dev/null +cat $COPYFILE +echo $OPTIONS + +switch ($FONTENCODING) { +case /*; cat $FONTENCODING +case ?*; cat $POSTLIB^/$FONTENCODING^.enc >[2]/dev/null +} + +echo $SETUP +echo $ENDSETUP + +for (i) { + switch ($i) { + case all; echo AllFonts + case /*; echo $i' PrintFont' + case ?*; echo /$i' PrintFont' + } +} + +echo $TRAILER diff --git a/sys/src/cmd/postscript/psencoding/Latin1.enc b/sys/src/cmd/postscript/psencoding/Latin1.enc new file mode 100755 index 000000000..1e6e60b14 --- /dev/null +++ b/sys/src/cmd/postscript/psencoding/Latin1.enc @@ -0,0 +1,299 @@ +% +% Encoding vector and redefinition of findfont for the ISO Latin1 standard. +% The 18 characters missing from ROM based fonts on older printers are noted +% below. +% + +/ISOLatin1Encoding [ + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /space + /exclam + /quotedbl + /numbersign + /dollar + /percent + /ampersand + /quoteright + /parenleft + /parenright + /asterisk + /plus + /comma + /minus + /period + /slash + /zero + /one + /two + /three + /four + /five + /six + /seven + /eight + /nine + /colon + /semicolon + /less + /equal + /greater + /question + /at + /A + /B + /C + /D + /E + /F + /G + /H + /I + /J + /K + /L + /M + /N + /O + /P + /Q + /R + /S + /T + /U + /V + /W + /X + /Y + /Z + /bracketleft + /backslash + /bracketright + /asciicircum + /underscore + /quoteleft + /a + /b + /c + /d + /e + /f + /g + /h + /i + /j + /k + /l + /m + /n + /o + /p + /q + /r + /s + /t + /u + /v + /w + /x + /y + /z + /braceleft + /bar + /braceright + /asciitilde + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /dotlessi + /grave + /acute + /circumflex + /tilde + /macron + /breve + /dotaccent + /dieresis + /.notdef + /ring + /cedilla + /.notdef + /hungarumlaut + /ogonek + /caron + /space + /exclamdown + /cent + /sterling + /currency + /yen + /brokenbar % missing + /section + /dieresis + /copyright + /ordfeminine + /guillemotleft + /logicalnot + /hyphen + /registered + /macron + /degree % missing + /plusminus % missing + /twosuperior % missing + /threesuperior % missing + /acute + /mu % missing + /paragraph + /periodcentered + /cedilla + /onesuperior % missing + /ordmasculine + /guillemotright + /onequarter % missing + /onehalf % missing + /threequarters % missing + /questiondown + /Agrave + /Aacute + /Acircumflex + /Atilde + /Adieresis + /Aring + /AE + /Ccedilla + /Egrave + /Eacute + /Ecircumflex + /Edieresis + /Igrave + /Iacute + /Icircumflex + /Idieresis + /Eth % missing + /Ntilde + /Ograve + /Oacute + /Ocircumflex + /Otilde + /Odieresis + /multiply % missing + /Oslash + /Ugrave + /Uacute + /Ucircumflex + /Udieresis + /Yacute % missing + /Thorn % missing + /germandbls + /agrave + /aacute + /acircumflex + /atilde + /adieresis + /aring + /ae + /ccedilla + /egrave + /eacute + /ecircumflex + /edieresis + /igrave + /iacute + /icircumflex + /idieresis + /eth % missing + /ntilde + /ograve + /oacute + /ocircumflex + /otilde + /odieresis + /divide % missing + /oslash + /ugrave + /uacute + /ucircumflex + /udieresis + /yacute % missing + /thorn % missing + /ydieresis +] def + +/NewFontDirectory FontDirectory maxlength dict def + +% +% Apparently no guarantee findfont is defined in systemdict so the obvious +% +% systemdict /findfont get exec +% +% can generate an error. So far the only exception is a VT600 (version 48.0). +% + +userdict /@RealFindfont known not { + userdict begin + /@RealFindfont systemdict begin /findfont load end def + end +} if + +/findfont { + dup NewFontDirectory exch known not { + dup + %dup systemdict /findfont get exec % not always in systemdict + dup userdict /@RealFindfont get exec + dup /Encoding get StandardEncoding eq { + dup length dict begin + {1 index /FID ne {def}{pop pop} ifelse} forall + /Encoding ISOLatin1Encoding def + currentdict + end + /DummyFontName exch definefont + } if + NewFontDirectory 3 1 roll put + } if + NewFontDirectory exch get +} bind def + diff --git a/sys/src/cmd/postscript/psencoding/UTF.enc b/sys/src/cmd/postscript/psencoding/UTF.enc new file mode 100755 index 000000000..234764e34 --- /dev/null +++ b/sys/src/cmd/postscript/psencoding/UTF.enc @@ -0,0 +1,332 @@ +% +% Encoding vector, operator and procedure redefinitions for Plan 9 UTF +% encoding. Prologues are expected to take steps to ensure operator +% redefinitions given here are actually used. Current implementation +% assumes UTF byte streams that represent ASCII or Latin1 text. +% + +/UTFLatin1Encoding [ + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /space + /exclam + /quotedbl + /numbersign + /dollar + /percent + /ampersand + /quoteright + /parenleft + /parenright + /asterisk + /plus + /comma + /minus + /period + /slash + /zero + /one + /two + /three + /four + /five + /six + /seven + /eight + /nine + /colon + /semicolon + /less + /equal + /greater + /question + /at + /A + /B + /C + /D + /E + /F + /G + /H + /I + /J + /K + /L + /M + /N + /O + /P + /Q + /R + /S + /T + /U + /V + /W + /X + /Y + /Z + /bracketleft + /backslash + /bracketright + /asciicircum + /underscore + /quoteleft + /a + /b + /c + /d + /e + /f + /g + /h + /i + /j + /k + /l + /m + /n + /o + /p + /q + /r + /s + /t + /u + /v + /w + /x + /y + /z + /braceleft + /bar + /braceright + /asciitilde + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /dotlessi + /grave + /acute + /circumflex + /tilde + /macron + /breve + /dotaccent + /dieresis + /.notdef + /ring + /cedilla + /.notdef + /hungarumlaut + /ogonek + /caron + /.notdef % was space + /exclamdown + /cent + /sterling + /currency + /yen + /brokenbar + /section + /dieresis + /copyright + /ordfeminine + /guillemotleft + /logicalnot + /hyphen + /registered + /macron + /degree + /plusminus + /twosuperior + /threesuperior + /acute + /mu + /paragraph + /periodcentered + /cedilla + /onesuperior + /ordmasculine + /guillemotright + /onequarter + /onehalf + /threequarters + /questiondown + /Agrave + /Aacute + /Acircumflex + /Atilde + /Adieresis + /Aring + /AE + /Ccedilla + /Egrave + /Eacute + /Ecircumflex + /Edieresis + /Igrave + /Iacute + /Icircumflex + /Idieresis + /Eth + /Ntilde + /Ograve + /Oacute + /Ocircumflex + /Otilde + /Odieresis + /multiply + /Oslash + /Ugrave + /Uacute + /Ucircumflex + /Udieresis + /Yacute + /Thorn + /germandbls + /agrave + /aacute + /acircumflex + /atilde + /adieresis + /aring + /ae + /ccedilla + /egrave + /eacute + /ecircumflex + /edieresis + /igrave + /iacute + /icircumflex + /idieresis + /eth + /ntilde + /ograve + /oacute + /ocircumflex + /otilde + /odieresis + /divide + /oslash + /ugrave + /uacute + /ucircumflex + /udieresis + /yacute + /thorn + /ydieresis +] def + +/NewFontDirectory FontDirectory maxlength dict def + +% +% Apparently no guarantee findfont is defined in systemdict so the obvious +% +% systemdict /findfont get exec +% +% can generate an error. So far the only exception is a VT600 (version 48.0). +% + +userdict /@RealFindfont known not { + userdict begin + /@RealFindfont systemdict begin /findfont load end def + end +} if + +/findfont { + dup NewFontDirectory exch known not { + dup + %dup systemdict /findfont get exec % not always in systemdict + dup userdict /@RealFindfont get exec + dup /Encoding get StandardEncoding eq { + dup length 1 add dict begin + {1 index /FID ne {def}{pop pop} ifelse} forall + /Encoding UTFLatin1Encoding def + /Metrics 1 dict def + Metrics /.notdef 0 put + currentdict + end + /DummyFontName exch definefont + } if + NewFontDirectory 3 1 roll put + } if + NewFontDirectory exch get +} bind def + +% +% Assume A0, except for A0A0 which is replaced by 20A0, can be ignored. +% Works with ASCII or Latin1 because A0 has been re-encoded as a zero +% width non-printing character. +% + +/UTFstring { + dup { + (\240\240) search { + pop + 0 16#20 put + }{pop exit} ifelse + } loop +} bind def + +/ashow {mark 4 1 roll UTFstring //ashow cvx exec cleartomark} bind def +/awidthshow {mark 7 1 roll UTFstring //awidthshow cvx exec cleartomark} bind def +/show {mark exch UTFstring //show cvx exec cleartomark} bind def +/stringwidth {UTFstring //stringwidth cvx exec} bind def +/widthshow {mark 5 1 roll UTFstring //widthshow cvx exec cleartomark} bind def + +% +% kshow is harder - stack can't change because of the procedure. +% + +/kshow dup load type /operatortype eq + {{UTFstring kshow} bind} + {{UTFstring //kshow cvx exec} bind} +ifelse def + diff --git a/sys/src/cmd/postscript/psencoding/mkfile b/sys/src/cmd/postscript/psencoding/mkfile new file mode 100755 index 000000000..eaceebdb1 --- /dev/null +++ b/sys/src/cmd/postscript/psencoding/mkfile @@ -0,0 +1,22 @@ +</$objtype/mkfile + +<../config + +POSTBIN=$ROOT/rc/bin/postscript + +all:V: psencoding + +install installall:V: $POSTBIN/psencoding $POSTLIB/Latin1.enc $POSTLIB/UTF.enc + +clean nuke:V: + rm -f psencoding + +$POSTBIN/psencoding: psencoding + cp $prereq $target + +$POSTLIB/%.enc: %.enc + cp $prereq $target + +psencoding: psencoding.rc + sed 's?^POSTLIB=.*?POSTLIB='$POSTLIB'?' psencoding.rc >psencoding + chmod 775 psencoding diff --git a/sys/src/cmd/postscript/psencoding/psencoding.rc b/sys/src/cmd/postscript/psencoding/psencoding.rc new file mode 100755 index 000000000..c0b6aeff9 --- /dev/null +++ b/sys/src/cmd/postscript/psencoding/psencoding.rc @@ -0,0 +1,39 @@ +#!/bin/rc +# Trivial script for checking and setting the default PostScript font +# encoding. Changing the default assumes you can write in $POSTLIB. +# Available font encodings are files in $POSTLIB that end in .enc. +# The default is $POSTLIB/Default.enc. +# + +POSTLIB=/sys/lib/postscript/prologues +DEFAULT=Default.enc +CURRENTDEFAULT=Standard + +if (~ $#* 0) { + cd $POSTLIB + for (i in *.enc) { + if (test -f $i -a $i '!=' $DEFAULT) { + NAME=`{echo $i | sed s/\\.enc//} + if (cmp $i $DEFAULT >/dev/null >[2]/dev/null) { + CURRENTDEFAULT=$NAME + } + echo $NAME + } + } + echo Standard + echo Default'='$CURRENTDEFAULT +} +if not { + switch ($1) { + case Default + ; + case Standard + rm -f $POSTLIB/$DEFAULT + case * + if (test -f $POSTLIB/$1.enc) { + rm -f $POSTLIB/$DEFAULT + cp $POSTLIB/$1.enc $POSTLIB/$DEFAULT + } + if not echo unrecognized encoding name $1 >[1=2] + } +} diff --git a/sys/src/cmd/postscript/psfiles/Nroundpage.ps b/sys/src/cmd/postscript/psfiles/Nroundpage.ps new file mode 100755 index 000000000..44a67a6d7 --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/Nroundpage.ps @@ -0,0 +1,11 @@ +% +% A version of roundpage.ps that assumes a symmetric clipping path. Thanks +% to Matthijs Melchior for the suggestion. +% + +/roundpagebbox { + pagebbox dup 0 get pagebbox 2 get add 2 exch put + pagebbox dup 1 get pagebbox 3 get add 3 exch put + pagebbox 0 0 put + pagebbox 1 0 put +} bind def diff --git a/sys/src/cmd/postscript/psfiles/README b/sys/src/cmd/postscript/psfiles/README new file mode 100755 index 000000000..c1a70140f --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/README @@ -0,0 +1,11 @@ +PostScript files that go in $(POSTLIB). Several, like forms.ps, are +used by most translators supplied in this package. Most PostScript +files only used by a single translator (e.g. the prologue) have been +been moved into the appropriate source directory. Files that end in +.enc support alternate character sets (e.g. ISO Latin 1 alphabet). +The implementation is left open, but typically redefines findfont. +That approach works because findfont is a procedure rather than an +operator, so it's not affected by bind. Also can't depend on having +a systemdict definition for findfont. It's in userdict on Version +48.0 VT600s. + diff --git a/sys/src/cmd/postscript/psfiles/aps.ps b/sys/src/cmd/postscript/psfiles/aps.ps new file mode 100755 index 000000000..9ba0d3095 --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/aps.ps @@ -0,0 +1,127 @@ +% +% Tune things up so Linotronic output looks more like the APS-5. Pull this file +% into dpost output using the -C option. To get the best looking output run dpost +% with the -e2 option and use special font files that look like the APS tables but +% have character codes (ie. the fourth column in the width tables) appropriate for +% PostScript fonts. Widths in these tables must be for APS fonts! +% +% Start with fat versions of the stroked Courier and Courier-Oblique fonts - from +% Johnathan Shopiro. +% + +/newdict /Courier findfont length dict def +/Courier findfont { + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +newdict /StrokeWidth 65 put +/Courier newdict definefont pop + +/newdict /Courier-Oblique findfont length dict def +/Courier-Oblique findfont { + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +newdict /StrokeWidth 65 put +/Courier-Oblique newdict definefont pop + +% +% Scaled down versions of the Helvetica font family. +% + +/newdict /Helvetica findfont length dict def +/Helvetica findfont { + 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Helvetica newdict definefont pop + +/newdict /Helvetica-Oblique findfont length dict def +/Helvetica-Oblique findfont { + 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Helvetica-Oblique newdict definefont pop + +/newdict /Helvetica-Bold findfont length dict def +/Helvetica-Bold findfont { + 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Helvetica-Bold newdict definefont pop + +/newdict /Helvetica-BoldOblique findfont length dict def +/Helvetica-BoldOblique findfont { + 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Helvetica-BoldOblique newdict definefont pop + +% +% Scaled up versions of the Times font family. +% + +/newdict /Times-Roman findfont length dict def +/Times-Roman findfont { + 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Times-Roman newdict definefont pop + +/newdict /Times-Italic findfont length dict def +/Times-Italic findfont { + 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Times-Italic newdict definefont pop + +/newdict /Times-Bold findfont length dict def +/Times-Bold findfont { + 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Times-Bold newdict definefont pop + +/newdict /Times-BoldItalic findfont length dict def +/Times-BoldItalic findfont { + 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if + + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +/Times-BoldItalic newdict definefont pop + diff --git a/sys/src/cmd/postscript/psfiles/banner.ps b/sys/src/cmd/postscript/psfiles/banner.ps new file mode 100755 index 000000000..d5637416e --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/banner.ps @@ -0,0 +1,40 @@ +% +% Simple program to print a banner page +% + +/banner { + /saveobj save def + erasepage initgraphics + + /#copies 1 def + /inch {72 mul} bind def + /pagebbox [clippath pathbbox newpath] def + + /font /Helvetica def + /size 20 def + /height pagebbox 3 get def + /width pagebbox 2 get .09 mul def + + .92 setgray + pagebbox 0 get pagebbox 1 get moveto + width 0 rlineto 0 height rlineto width neg 0 rlineto closepath eofill + pagebbox 2 get pagebbox 1 get moveto + width neg 0 rlineto 0 height rlineto width 0 rlineto closepath eofill + 0 setgray + + font findfont size scalefont setfont + /linesp size size .15 mul add neg def + /tab (Destination) stringwidth pop 1.5 mul def + /nextline {0 0 moveto show tab 0 moveto show 0 linesp translate} def + + pagebbox 0 get 1.5 width mul add pagebbox 3 get 2.0 width mul sub translate + (Bin) nextline + (Name) nextline + (Owner) nextline + (File) nextline + (Account) nextline + (Destination) nextline + (Spooldate) nextline + showpage + saveobj restore +} bind def diff --git a/sys/src/cmd/postscript/psfiles/baseline.ps b/sys/src/cmd/postscript/psfiles/baseline.ps new file mode 100755 index 000000000..470047c9a --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/baseline.ps @@ -0,0 +1,156 @@ +% +% Stuff used to draw or set text along a baseline specified by parametric equations +% for x and y. +% + +/left -1 def +/center 0 def +/right 1 def + +/baselinedict 50 dict def + +/newbaseline { + baselinedict begin + /g' exch bind def + /f' exch bind def + /g exch bind def + /f exch bind def + + counttomark 2 eq {/hoffset exch def} if + /res exch def + + /t 0 def + /s 0 def + /voffset false def + cleartomark + end +} bind def + +/drawfunnytext { + baselinedict begin + /t exch def + /mode exch def + /str exch def + + mode left eq { + /leftstring emptystring def + /rightstring str def + } if + + mode right eq { + /leftstring str reversestring def + /rightstring emptystring def + } if + + mode center eq { + str splitstring + /rightstring exch def + /leftstring exch reversestring def + } if + + gsave currentpoint translate leftstring left t baselineshow grestore + gsave currentpoint translate rightstring right t baselineshow grestore + + /t 0 def + /s 0 def + /voffset false def + cleartomark + end +} bind def + +/setfunnytext { + baselinedict begin + /vpos exch def + /hpos exch def + /str exch def + + voffset vpos ne { + /voffset vpos def + /t 0 def + /s hoffset def + } if + + gsave + hoffset voffset translate + 0 0 moveto + /ds hpos s sub def + /dt ds t f' dup mul t g' dup mul add sqrt res mul div def + /s s ds add def + /t t dt add def + str right t baselineshow + grestore + end +} bind def + +baselinedict begin + +/f {} bind def +/g {pop 0} bind def +/f' {pop 1} bind def +/g' {pop 0} bind def + +/s 0 def +/t 0 def +/res 72 def + +/onecharstring ( ) def +/emptystring () def + +/baselineshow { + /t exch def + /mode exch def + /str exch def + + gsave + t f res mul t g res mul translate + 0 0 moveto + t g' t f' atan rotate + { + mode right eq {pop} if + grestore gsave + onecharstring 0 3 -1 roll put onecharstring stringwidth pop + /ds exch mode mul def + /dt ds t f' dup mul t g' dup mul add sqrt res mul div def + /t t dt add def + /s s ds add def + t f res mul t g res mul translate + 0 0 moveto + t g' t f' atan rotate + mode left eq {pop} if + } str kshow + grestore +} bind def + +/reversestring { + /str1 exch def + + /str2 str1 length string def + /i 0 def + /n str1 length 1 sub def + + { + str1 n get str2 exch i exch put + /i i 1 add def + /n n 1 sub def + n 0 lt {exit} if + } loop + str2 +} bind def + +/splitstring { + /str1 exch def + + /len str1 stringwidth pop def + /s 0 def + /n 0 def + str1 length { + str1 n get onecharstring exch 0 exch put + /s onecharstring stringwidth pop s add def + s len 2 div ge {exit} if + /n n 1 add def + } repeat + str1 0 n 1 add getinterval + str1 n str1 length n sub getinterval +} bind def + +end diff --git a/sys/src/cmd/postscript/psfiles/color.ps b/sys/src/cmd/postscript/psfiles/color.ps new file mode 100755 index 000000000..e304cc3a3 --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/color.ps @@ -0,0 +1,65 @@ +% +% Color and reverse video support for dpost. A call made to setcolor with two +% arguments implies reverse video printing. +% + +/rgb {setrgbcolor} bind def +/hsb {sethsbcolor} bind def + +/colordict 50 dict dup begin + /red { 1 0 0 } def + /green { 0 1 0 } def + /blue { 0 0 1 } def + /cyan { 0 1 1 } def + /magenta { 1 0 1 } def + /yellow { 1 1 0 } def + /white { 1 1 1 } def + /black { 0 0 0 } def +end def + +/setcolor { + counttomark 1 eq { + dup colordict exch known not {pop /black} if + colordict exch get exec setrgbcolor + } if + counttomark 2 eq { + /backcolor exch def + /textcolor exch def + colordict backcolor known not colordict textcolor known not or { + /backcolor colordict /black get def + /textcolor colordict /white get def + } if + /backcolor colordict backcolor get def + /textcolor colordict textcolor get def + /dY1 0 def + /dY2 0 def + textcolor exec setrgbcolor + } if +} bind def + +/drawrvbox { + /x2 exch def + /x1 exch def + + currentpoint dup + /y1 exch def + /y2 exch def pop + + dY1 0 eq dY2 0 eq and { + currentfont /FontBBox get aload pop + currentfont /FontMatrix get dtransform /dY2 exch def pop + currentfont /FontMatrix get dtransform /dY1 exch def pop + } if + + /y1 y1 dY1 add def + /y2 y2 dY2 add def + + backcolor exec setrgbcolor + newpath + x1 y1 moveto + x2 y1 lineto + x2 y2 lineto + x1 y2 lineto + closepath fill + textcolor exec setrgbcolor +} bind def diff --git a/sys/src/cmd/postscript/psfiles/fatcourier.ps b/sys/src/cmd/postscript/psfiles/fatcourier.ps new file mode 100755 index 000000000..11d718814 --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/fatcourier.ps @@ -0,0 +1,26 @@ +% +% Fat versions of the stroked Courier and Courier-Oblique - from Johnathan Shopiro. +% Can be selectively pulled in using the -C option that's available with all the +% PostScript translators or permanently added to any of the prologues. Helps on +% Linotronic typesetters, where Courier and Courier-Oblique are too light! +% + +/newdict /Courier findfont length 1 add dict def +/Courier findfont { + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +newdict /StrokeWidth 60 put +/Courier newdict definefont pop + +/newdict /Courier-Oblique findfont length 1 add dict def +/Courier-Oblique findfont { + 1 index /FID ne + {newdict 3 1 roll put} + {pop pop} + ifelse +} forall +newdict /StrokeWidth 60 put +/Courier-Oblique newdict definefont pop diff --git a/sys/src/cmd/postscript/psfiles/forms.ps b/sys/src/cmd/postscript/psfiles/forms.ps new file mode 100755 index 000000000..a96fcdaef --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/forms.ps @@ -0,0 +1,213 @@ +% +% Procedures that let you print any number of pages on each sheet of paper. It's +% far from perfect and won't handle everything (eg. it's not recursive), but should +% be good enough for now. Assumes the default page coordinate system has been set +% up before setupforms is called. lastpage makes certain the last page is printed, +% and should be called immediately after the %%Trailer comment. +% +% Three lines of code needed for page image clipping have been commented out for +% now. It works, but can really slow things down on some versions of PostScript. +% Uncomment them if you want to clip pages. +% + +/setupforms { + /formsperpage exch def + + /currentform 0 def + /slop 5 def + /min {2 copy gt {exch} if pop} def + +% +% Save the current environment so the real showpage can be restored when we're all +% done. Occasionally helps when a banner page is included with the job. +% + + /saveobj save def + +% +% Number of rows and columns we'll need - may exchange them later. +% + + /columns formsperpage sqrt ceiling cvi def + /rows formsperpage columns div ceiling cvi def + +% +% Slop leaves a little room around the edge so page images can be outlined and have +% the borders show up. Distance is in default coordinates, so we need to figure out +% how it maps into user coordinates. +% + + 6 array defaultmatrix + 6 array currentmatrix + 6 array invertmatrix + 6 array concatmatrix + /tempmatrix exch def + + 0 slop tempmatrix dtransform dup mul exch dup mul add sqrt + /slop exch def + +% +% Determine how big the image area is, using the clipping path bounding box minus +% a little and leave the coordinates of the lower left corner of the clipping path +% on the stack. Also temporarily set the size of each page (ie. formheight and +% formwidth) from the clipping path - just in case old software uses this stuff. +% Only works for coordinate systems that have been rotated by a multiple of 90 +% degrees. +% + + newpath clippath pathbbox + 2 index sub dup /formheight exch def slop 2 mul sub /pageheight exch def + 2 index sub dup /formwidth exch def slop 2 mul sub /pagewidth exch def + +% +% New translators all store the size of each page in default coordinates in the +% pagebbox array and it can be different than the size determined by the clipping +% path. If we can find pagebbox use it to set the real dimensions of each page. +% Leaves the coordinates of the lower left corner on the stack, (either from +% pagebbox or clippath) so four numbers are there when we're done. +% + + userdict /gotpagebbox known userdict /pagebbox known and { + newpath + pagebbox 0 get pagebbox 1 get tempmatrix transform moveto + pagebbox 0 get pagebbox 3 get tempmatrix transform lineto + pagebbox 2 get pagebbox 3 get tempmatrix transform lineto + pagebbox 2 get pagebbox 1 get tempmatrix transform lineto + closepath pathbbox + 2 index sub /formheight exch def + 2 index sub /formwidth exch def + } {2 copy} ifelse + +% +% Top two numbers are the displacement from the job's origin to the lower left +% corner of each page image when we finish setting up the new coordinate system. +% + + /ycorner exch def + /xcorner exch def + +% +% The two numbers left on the stack are the coordinates of the lower left corner +% of the clipping path. Go there and then up a bit so page images can be outlined. +% + + translate + slop slop translate + +% +% If the page is wider than high we may be able to do better if we exchange rows +% and columns. Won't make a difference in the current orientation or if rows and +% columns are the same. +% + + pagewidth pageheight gt { + rows columns /rows exch def /columns exch def + } if + +% +% Find the orientation and scaling that makes things as large as possible. More +% than what's really needed. First calculation essentially finds the minimum of +% 1/rows and 1/columns. +% + + pagewidth formwidth columns mul div pageheight formheight rows mul div min + pageheight formwidth columns mul div pagewidth formheight rows mul div min + + 2 copy lt { + rotation 1 eq { + landscape { + 0 pageheight translate + -90 rotate + }{ + pagewidth 0 translate + 90 rotate + } ifelse + }{ + landscape { + pagewidth 0 translate + 90 rotate + }{ + 0 pageheight translate + -90 rotate + } ifelse + } ifelse + pagewidth pageheight /pagewidth exch def /pageheight exch def + exch + } if + +% +% Second number from the top is the best choice. Scale so everything will fit on +% the current page, go back to the original origin, and then get ready for the +% first page - which goes in the upper left corner. +% + + pop dup dup scale + xcorner neg ycorner neg translate + 0 rows 1 sub formheight mul translate + +% +% Try to center everything on the page - scaling we used is on top of the stack. +% + + dup pagewidth exch div formwidth columns mul sub 2 div + exch pageheight exch div formheight rows mul sub 2 div translate + +% +% Redefine showpage. +% + + /!PreForms~showpage~ /showpage load def % save current showpage + + /showpage { + saveobj restore +% initclip + formsperpage 1 gt { + gsave .1 setlinewidth outlineform stroke grestore + } if + formwidth 0 translate + /currentform currentform 1 add def + currentform columns mod 0 eq { + columns formwidth mul neg formheight neg translate + } if + currentform formsperpage mod 0 eq { + gsave !PreForms~showpage~ grestore + currentform columns mod formwidth mul neg + formsperpage columns idiv formheight mul translate + /currentform 0 def + } if +% outlineform clip newpath + /saveobj save def + } bind def + + /outlineform { + newpath + xcorner ycorner moveto + formwidth 0 rlineto + 0 formheight rlineto + formwidth neg 0 rlineto + closepath + } bind def + + /lastpage { + formsperpage 1 gt { + currentform 0 ne { + /saveobj save def + 0 1 formsperpage currentform sub formsperpage mod { + pop showpage + } for + saveobj restore + } if + saveobj restore + saveobj restore + } if + } def + +% +% Clip the first page image and save the environment we just set up, including +% the redefined showpage. +% + +% outlineform clip + newpath + /saveobj save def +} def diff --git a/sys/src/cmd/postscript/psfiles/mkfile b/sys/src/cmd/postscript/psfiles/mkfile new file mode 100755 index 000000000..ee75ec5ac --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/mkfile @@ -0,0 +1,12 @@ +</$objtype/mkfile + +<../config + +all:VQ: + ; + +install installall:V: + cp *.ps ps.* $POSTLIB + +clean nuke:VQ: + ; diff --git a/sys/src/cmd/postscript/psfiles/ps.requests b/sys/src/cmd/postscript/psfiles/ps.requests new file mode 100755 index 000000000..59e2a571d --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/ps.requests @@ -0,0 +1,16 @@ +% +% Keywords begin with an @ in the first column. The value follows on the next +% line and includes everything up to next keyword line, except for comments +% which are lines that begin with % in the first column. +% + +@manualfeed + statusdict begin + /manualfeedtimeout 300 def + /manualfeed true def + end + +@ledgertray + statusdict begin + ledgertray + end diff --git a/sys/src/cmd/postscript/psfiles/roundpage.ps b/sys/src/cmd/postscript/psfiles/roundpage.ps new file mode 100755 index 000000000..68d2d443a --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/roundpage.ps @@ -0,0 +1,30 @@ +% +% Tries to round clipping path dimensions, as stored in array pagebbox, so they +% match one of the known sizes in the papersizes array. Lower left coordinates +% are always set to 0. +% + +/roundpagebbox { + 7 dict begin + /papersizes [8.5 inch 11 inch 14 inch 17 inch] def + + /mappapersize { + /val exch def + /slop .5 inch def + /diff slop def + /j 0 def + 0 1 papersizes length 1 sub { + /i exch def + papersizes i get val sub abs + dup diff le {/diff exch def /j i def} {pop} ifelse + } for + diff slop lt {papersizes j get} {val} ifelse + } def + + pagebbox 0 0 put + pagebbox 1 0 put + pagebbox dup 2 get mappapersize 2 exch put + pagebbox dup 3 get mappapersize 3 exch put + end +} bind def + diff --git a/sys/src/cmd/postscript/psfiles/shade.ps b/sys/src/cmd/postscript/psfiles/shade.ps new file mode 100755 index 000000000..47e316798 --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/shade.ps @@ -0,0 +1,52 @@ +% +% Shading support - primarily for ASCII file translators. +% + +/grays [0.98 0.9 0.75 0.6] def + +/setshade { + /level exch def + level 0 le { + /textgray 0 def + /backgray 1 def + }{ + /backgray level grays length gt + {/textgray 1 def 0} + {/textgray 0 def grays level 1 sub get} + ifelse def + } ifelse + textgray setgray + /dY1 0 def + /dY2 0 def +} bind def + +/drawrvbox { + /x2 exch charwidth mul def + /x1 exch charwidth mul def + + x1 x2 lt { + dup % expects y on top + /y1 exch linespace mul def + /y2 y1 def + + dY1 0 eq dY2 0 eq and { + currentfont /FontBBox get aload pop + 160 sub + currentfont /FontMatrix get dtransform /dY2 exch def pop + 100 add + currentfont /FontMatrix get dtransform /dY1 exch def pop + } if + + /y1 y1 dY1 add def + /y2 y2 dY2 add def + + backgray setgray + newpath + x1 y1 moveto + x2 y1 lineto + x2 y2 lineto + x1 y2 lineto + closepath fill + } if + textgray setgray +} bind def diff --git a/sys/src/cmd/postscript/psfiles/unbind.ps b/sys/src/cmd/postscript/psfiles/unbind.ps new file mode 100755 index 000000000..98e6283e6 --- /dev/null +++ b/sys/src/cmd/postscript/psfiles/unbind.ps @@ -0,0 +1,28 @@ +% +% Unbind the operators in an executable array or packedarray. Leaves the +% unbound array or the original object on the stack. +% + +/unbind { + 0 index xcheck + 1 index type /arraytype eq + 2 index type /packedarraytype eq or and { + dup length array copy cvx + dup 0 exch { + dup type /operatortype eq { + ( ) cvs cvn cvx + } if + + 0 index xcheck + 1 index type /arraytype eq + 2 index type /packedarraytype eq or and { + unbind + } if + + 3 copy put pop + 1 add + } forall + pop + } if +} def + diff --git a/sys/src/cmd/postscript/tcpostio/dial.c b/sys/src/cmd/postscript/tcpostio/dial.c new file mode 100755 index 000000000..da885d9b6 --- /dev/null +++ b/sys/src/cmd/postscript/tcpostio/dial.c @@ -0,0 +1,109 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/time.h> + +#define DIALTIMEOUT 30 + +/* This is a dummy routine for non Plan9 systems. + * No attempt has been made to be clever, it's just + * supposed to work in this program. + */ +int dial_debug = 0; + +int +dial(char *dest, char *local, char *dir, int *cfdp) { + int sockconn, lport; + struct hostent *hp; /* Pointer to host info */ + struct sockaddr_in sin; /* Socket address, Internet style */ + struct servent *sp = 0; + char *tdest, *netname, *hostname, *servname; + int sock_type; +#ifndef plan9 +#define USED(x) if(x); else + int sockoption, sockoptsize; +#endif + + USED(dir); + USED(cfdp); + if ((tdest = malloc(strlen(dest)+1)) == NULL) { + if (dial_debug) fprintf(stderr, "dial: could not allocate memory\n"); + return(-1); + } + strcpy(tdest, dest); + + if ((netname = strtok(tdest, "!")) == NULL) { + fprintf(stderr, "dial: no network name\n"); + return(-1); + } + if (strcmp(netname, "tcp") == 0) { + sock_type = SOCK_STREAM; + } else if (strcmp(netname, "udp") == 0) { + sock_type = SOCK_DGRAM; + } else { + fprintf(stderr, "dial: network protocol name `%s' is invalid; must be `tcp' or `udp'\n", netname); + return(-1); + } + if ((hostname = strtok(0, "!")) == NULL) { + fprintf(stderr, "dial: no host name or number\n"); + return(-1); + } + if ((servname = strtok(0, "!")) == NULL) { + fprintf(stderr, "dial: no service name or number\n"); + return(-1); + } + hp = gethostbyname(hostname); + if (hp == (struct hostent *)NULL) { + if (dial_debug) fprintf(stderr, "host `%s' unknown by local host\n", hostname); + return(-1); + } + if (!isdigit(servname[0])) + sp = getservbyname(servname, netname); + sin.sin_addr.s_addr = *(unsigned long*)hp->h_addr; + sin.sin_port = htons((sp==0)?atoi(servname):sp->s_port); + sin.sin_family = AF_INET; + if (local == NULL) { + if ((sockconn = socket(AF_INET, sock_type, 0)) < 0) { + if (dial_debug) perror("dial:socket():"); + return(-1); + } + if (dial_debug) fprintf(stderr, "socket FD=%d\n", sockconn); + } else { + lport = atoi(local); + if ((lport < 512) || (lport >= 1024)) { + fprintf(stderr, "dial:invalid local port %d\n", lport); + return(-1); + } + if ((sockconn = rresvport(&lport)) < 0) { + if (dial_debug) perror("dial:rresvport():"); + return(-1); + } + } + if (dial_debug) { + fprintf(stderr, "sin size=%d\n", sizeof(sin)); + } + alarm(DIALTIMEOUT); + if ((connect(sockconn, (struct sockaddr *) &sin, sizeof(sin)) < 0)) { + if (dial_debug) perror("dial:connect():"); + return(-1); + } + alarm(0); +#ifndef plan9 + sockoptsize = sizeof(sockoption); + if (getsockopt(sockconn, SOL_SOCKET, SO_KEEPALIVE, &sockoption, &sockoptsize) < 0) { + if (dial_debug) perror("dial:getsockopt():"); + return(-1); + } + if (sockoptsize == sizeof(sockoption) && !sockoption) { + if (setsockopt(sockconn, SOL_SOCKET, SO_KEEPALIVE, &sockoption, sockoptsize) < 0) { + if (dial_debug) perror("dial:getsockopt():"); + return(-1); + } + } +#endif + return(sockconn); +} diff --git a/sys/src/cmd/postscript/tcpostio/mkfile b/sys/src/cmd/postscript/tcpostio/mkfile new file mode 100755 index 000000000..539f5907d --- /dev/null +++ b/sys/src/cmd/postscript/tcpostio/mkfile @@ -0,0 +1,16 @@ +</$objtype/mkfile + +<../config + +TARG=tcpostio +OFILES= tcpostio.$O\ + dial.$O\ + +BIN=$POSTBIN + +</sys/src/cmd/mkone +CC=pcc +CFLAGS=-Bw -c -D_BSD_EXTENSION -D_NET_EXTENSION -Dplan9 + +syms:V: + vc $CFLAGS -a tcpostio.c > syms diff --git a/sys/src/cmd/postscript/tcpostio/tcpostio.c b/sys/src/cmd/postscript/tcpostio/tcpostio.c new file mode 100755 index 000000000..4f0fdc007 --- /dev/null +++ b/sys/src/cmd/postscript/tcpostio/tcpostio.c @@ -0,0 +1,534 @@ +#include <stdio.h> +#include <stdlib.h> + +#ifdef plan9 +#include <bsd.h> +#endif + +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> + +#include <sys/socket.h> + +extern int dial_debug; +extern int dial(char*, char*, char*, int*); + + +/* debug = 0 for no debugging */ +/* debug = 1 for readprinter debugging */ +/* debug = 2 for sendprinter debugging */ +/* debug = 3 for full debugging, its hard to read the messages */ + +int debug = 0; +#define READTIMEOUT 300 +#define RCVSELTIMEOUT 30 +#define SNDSELTIMEOUT 300 + +void +rdtmout(void) { + fprintf(stderr, "read timeout occurred, check printer\n"); +} + +int +getline(int fd, char *buf, int len) { + char *bp, c; + int i = 0, n; + + bp = buf; + while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) { + alarm(0); + if (*bp == '\r') continue; + i += n; + + c = *bp++; + if (c == '\n' || c == '\004' || i >= len-1) + break; + } + alarm(0); + if (n < 0) + return(n); + *bp = '\0'; + return(i); +} + +typedef struct { + char *state; /* printer's current status */ + int val; /* value returned by getstatus() */ +} Status; + +/* printer states */ +#define INITIALIZING 0 +#define IDLE 1 +#define BUSY 2 +#define WAITING 3 +#define PRINTING 4 +#define PRINTERERROR 5 +#define ERROR 6 +#define FLUSHING 7 +#define UNKNOWN 8 + +/* protocol requests and program states */ +#define START 'S' +unsigned char Start[] = { START }; +#define ID_LE 'L' +unsigned char Id_le[] = { ID_LE }; +#define REQ_STAT 'T' +unsigned char Req_stat[] = { REQ_STAT }; +#define SEND_DATA 'D' +unsigned char Send_data[] = { SEND_DATA }; +#define SENT_DATA 'A' +unsigned char Sent_data[] = { SENT_DATA }; +#define WAIT_FOR_EOJ 'W' +unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ }; +#define END_OF_JOB 'E' +unsigned char End_of_job[] = { END_OF_JOB }; +#define FATAL_ERROR 'F' +unsigned char Fatal_error[] = { FATAL_ERROR }; +#define WAIT_FOR_IDLE 'I' +unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE }; +#define OVER_AND_OUT 'O' +unsigned char Over_and_out[] = { OVER_AND_OUT }; + +Status statuslist[] = { + "initializing", INITIALIZING, + "idle", IDLE, + "busy", BUSY, + "waiting", WAITING, + "printing", PRINTING, + "printererror", PRINTERERROR, + "Error", ERROR, + "flushing", FLUSHING, + NULL, UNKNOWN +}; + + +/* find returns a pointer to the location of string str2 in string str1, + * if it exists. Otherwise, it points to the end of str1. + */ +char * +find(char *str1, char *str2) { + char *s1, *s2; + + for (; *str1!='\0'; str1++) { + for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ; + if ( *s2 == '\0' ) + break; + } + + return(str1); +} + +#define MESGSIZE 16384 +int blocksize = 1920; /* 19200/10, with 1 sec delay between transfers + * this keeps the queues from building up. + */ +char mesg[MESGSIZE]; /* exactly what came back on ttyi */ + +int +parsmesg(char *buf) { + static char sbuf[MESGSIZE]; + char *s; /* start of printer messsage in mesg[] */ + char *e; /* end of printer message in mesg[] */ + char *key, *val; /* keyword/value strings in sbuf[] */ + char *p; /* for converting to lower case etc. */ + int i; /* where *key was found in statuslist[] */ + + if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') { + strcpy(sbuf, s+3); /* don't change mesg[] */ + sbuf[e-(s+3)] = '\0'; /* ignore the trailing " ]%" */ + + for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :")) { + if (strcmp(key, "Error") == 0) + return(ERROR); + if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0) + key = val; + + for (; *key == ' '; key++) ; /* skip any leading spaces */ + for (p = key; *p; p++) /* convert to lower case */ + if (*p == ':') { + *p = '\0'; + break; + } else if (isupper(*p)) *p = tolower(*p); + + for (i=0; statuslist[i].state != NULL; i++) { + if (strcmp(statuslist[i].state, key) == 0) + return(statuslist[i].val); + } + } + } + return(UNKNOWN); +} + +char buf[MESGSIZE]; +fd_set readfds, writefds, exceptfds; +struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 }; +struct timeval sndtimeout = { SNDSELTIMEOUT, 0 }; + +int +readprinter(int printerfd, int pipefd) +{ + unsigned char proto; + int progstate = START; + int print_wait_msg = 0; + int tocount = 0; + int c, printstat, lastprintstat, n, nfds; + + + nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1; + printstat = 0; + signal(SIGALRM, rdtmout); + do { + +reselect: + /* ask sending process to request printer status */ + if (write(pipefd, Req_stat, 1) != 1) { + fprintf(stderr, "request status failed\n"); + progstate = FATAL_ERROR; + continue; + } + FD_ZERO(&readfds); /* lets be anal */ + FD_SET(printerfd, &readfds); + FD_SET(pipefd, &readfds); + FD_ZERO(&exceptfds); + FD_SET(printerfd, &exceptfds); + FD_SET(pipefd, &exceptfds); + n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout); + if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n); + if (n == 0) { + /* a timeout occurred */ + if (++tocount > 4) { + fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n"); + tocount = 0; + } + goto reselect; + } + if (n > 0 && FD_ISSET(printerfd, &exceptfds)) { + /* printer problem */ + fprintf(stderr, "printer exception\n"); + if (write(pipefd, Fatal_error, 1) != 1) { + fprintf(stderr, "'fatal error' write to pipe failed\n"); + } + progstate = FATAL_ERROR; + continue; + } + if (n > 0 && FD_ISSET(pipefd, &exceptfds)) { + /* pipe problem */ + fprintf(stderr, "pipe exception\n"); + progstate = FATAL_ERROR; + continue; + } + if (n > 0 && FD_ISSET(pipefd, &readfds)) { + /* protocol pipe wants to be read */ + if (debug&0x1) fprintf(stderr, "pipe wants to be read\n"); + if (read(pipefd, &proto, 1) != 1) { + fprintf(stderr, "read protocol pipe failed\n"); + progstate = FATAL_ERROR; + continue; + } + if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto); + /* change state? */ + switch (proto) { + case SENT_DATA: + break; + case WAIT_FOR_EOJ: + if (!print_wait_msg) { + print_wait_msg = 1; + fprintf(stderr, "waiting for end of job\n"); + } + progstate = proto; + break; + default: + fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto); + break; + } + n--; + } + if (n > 0 && FD_ISSET(printerfd, &readfds)) { + /* printer wants to be read */ + if (debug&0x1) fprintf(stderr, "printer wants to be read\n"); + if ((c=getline(printerfd, buf, MESGSIZE)) < 0) { + fprintf(stderr, "read printer failed\n"); + progstate = FATAL_ERROR; + continue; + } + if (debug&0x1) fprintf(stderr, "%s\n", buf); + if (c==1 && *buf == '\004') { + if (progstate == WAIT_FOR_EOJ) { + if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate); + fprintf(stderr, "%%[ status: endofjob ]%%\n"); +/* progstate = WAIT_FOR_IDLE; */ + progstate = OVER_AND_OUT; + if (write(pipefd, Over_and_out, 1) != 1) { + fprintf(stderr, "'fatal error' write to pipe failed\n"); + } + continue; + } else { + if (printstat == ERROR) { + progstate = FATAL_ERROR; + continue; + } + if (progstate != START && progstate != WAIT_FOR_IDLE) + fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate); + + } + continue; + } + + /* figure out if it was a status line */ + lastprintstat = printstat; + printstat = parsmesg(buf); + if (printstat == UNKNOWN || printstat == ERROR + || lastprintstat != printstat) { + /* print whatever it is that was read */ + fprintf(stderr, buf); + fflush(stderr); + if (printstat == UNKNOWN) { + printstat = lastprintstat; + continue; + } + } + switch (printstat) { + case UNKNOWN: + continue; /* shouldn't get here */ + case FLUSHING: + case ERROR: + progstate = FATAL_ERROR; + /* ask sending process to die */ + if (write(pipefd, Fatal_error, 1) != 1) { + fprintf(stderr, "Fatal_error mesg write to pipe failed\n"); + } + continue; + case INITIALIZING: + case PRINTERERROR: + sleep(1); + break; + case IDLE: + if (progstate == WAIT_FOR_IDLE) { + progstate = OVER_AND_OUT; + if (write(pipefd, Over_and_out, 1) != 1) { + fprintf(stderr, "'fatal error' write to pipe failed\n"); + } + continue; + } + progstate = SEND_DATA; + + goto dowait; + case BUSY: + case WAITING: + default: + sleep(1); +dowait: + switch (progstate) { + case WAIT_FOR_IDLE: + case WAIT_FOR_EOJ: + case START: + sleep(5); + break; + + case SEND_DATA: + if (write(pipefd, Send_data, 1) != 1) { + fprintf(stderr, "send data write to pipe failed\n"); + progstate = FATAL_ERROR; + continue; + } + break; + default: + fprintf(stderr, "unexpected program state %c\n", progstate); + exit(1); + } + break; + } + n--; + } + if (n > 0) { + fprintf(stderr, "more fds selected than requested!\n"); + exit(1); + }; + } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT)); + + if (progstate == FATAL_ERROR) + return(1); + else + return(0); +} + +int +sendfile(int infd, int printerfd, int pipefd) +{ + unsigned char proto; + int progstate = START; + int i, n, nfds; + int bytesread, bytesent = 0; + + nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1; + + if (write(printerfd, "\004", 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } + do { + FD_ZERO(&readfds); /* lets be anal */ + FD_SET(pipefd, &readfds); + n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout); + if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n); + if (n > 0 && FD_ISSET(pipefd, &readfds)) { + /* protocol pipe wants to be read */ + if (read(pipefd, &proto, 1) != 1) { + fprintf(stderr, "read protocol pipe failed\n"); + return(1); + } + /* change state? */ + if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto); + switch (proto) { + case OVER_AND_OUT: + case END_OF_JOB: + progstate = proto; + break; + case SEND_DATA: + bytesread = 0; + do { + i = read(infd, &buf[bytesread], blocksize-bytesread); + if (debug&02) fprintf(stderr, "read %d bytes\n", i); + if (i > 0) + bytesread += i; + } while((i > 0) && (bytesread < blocksize)); + if (i < 0) { + fprintf(stderr, "input file read error\n"); + progstate = FATAL_ERROR; + break; /* from switch */ + } + if (bytesread > 0) { + if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread); + if (write(printerfd, buf, bytesread)!=bytesread) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else if (write(pipefd, Sent_data, 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else { + bytesent += bytesread; + } + fprintf(stderr, "%d sent\n", bytesent); + fflush(stderr); + + /* we have reached the end of the input file */ + } + if (i == 0) { + if (progstate != WAIT_FOR_EOJ) { + if (write(printerfd, "\004", 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else if (write(pipefd, Wait_for_eoj, 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } else { + progstate = WAIT_FOR_EOJ; + } + } + } + break; + case REQ_STAT: + if (write(printerfd, "\024", 1)!=1) { + fprintf(stderr, "write to printer failed\n"); + progstate = FATAL_ERROR; + } + if (debug&02) fprintf(stderr, "^T"); + break; + case FATAL_ERROR: + progstate = FATAL_ERROR; + } + } else if (n < 0) { + perror("sendfile:select:"); + progstate = FATAL_ERROR; + } else if (n == 0) { + sleep(1); + fprintf(stderr, "sendfile timeout\n"); + progstate = FATAL_ERROR; + } + } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT)); + if (write(printerfd, "\004", 1)!=1) { + perror("sendfile:write:"); + progstate = FATAL_ERROR; + } + + if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent); + if (progstate == FATAL_ERROR) + return(1); + else + return(0); +} + +void main(int argc, char *argv[]) { + int c, usgflg=0, infd, printerfd; + int cpid; + int pipefd[2]; + char *dialstr; + unsigned long rprv, sprv; + + dialstr = 0; + + while ((c = getopt(argc, argv, "b:d:")) != -1) + switch (c) { + case 'b': + blocksize = atoi(optarg)/10; + if (blocksize > MESGSIZE || blocksize < 1) + blocksize = MESGSIZE; + break; + case 'd': + debug = atoi(optarg); + dial_debug = debug; + break; + case '?': + fprintf(stderr, "unknown option %c\n", c); + usgflg++; + } + if (optind < argc) + dialstr = argv[optind++]; + else { + usgflg++; + } + if (usgflg) { + fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n", argv[0]); + exit (2); + } + if (optind < argc) { + infd = open(argv[optind], 0); + if (infd < 0) { + fprintf(stderr, "cannot open %s\n", argv[optind]); + exit(1); + } + optind++; + } else + infd = 0; + + if (debug & 02) fprintf(stderr, "blocksize=%d\n", blocksize); + if (debug) fprintf(stderr, "dialing address=%s\n", dialstr); + printerfd = dial(dialstr, 0, 0, 0); + if (printerfd < 0) exit(1); + + fprintf(stderr, "printer startup\n"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) { + perror("socketpair"); + exit(1); + } + switch(cpid = fork()){ + case -1: + perror("fork error"); + exit(1); + case 0: + close(pipefd[1]); + sprv = sendfile(infd, printerfd, pipefd[0]); /* child - to printer */ + if (debug) fprintf(stderr, "to remote - exiting\n"); + exit(sprv); + default: + close(pipefd[0]); + rprv = readprinter(printerfd, pipefd[1]); /* parent - from printer */ + if (debug) fprintf(stderr, "from remote - exiting\n"); + while(wait(&sprv) != cpid); + exit(rprv|sprv); + } +} diff --git a/sys/src/cmd/postscript/tests/postbgi1 b/sys/src/cmd/postscript/tests/postbgi1 Binary files differnew file mode 100755 index 000000000..da04a506a --- /dev/null +++ b/sys/src/cmd/postscript/tests/postbgi1 diff --git a/sys/src/cmd/postscript/tests/postdaisy1 b/sys/src/cmd/postscript/tests/postdaisy1 Binary files differnew file mode 100755 index 000000000..6f228a880 --- /dev/null +++ b/sys/src/cmd/postscript/tests/postdaisy1 diff --git a/sys/src/cmd/postscript/tests/postdmd1 b/sys/src/cmd/postscript/tests/postdmd1 Binary files differnew file mode 100755 index 000000000..bc8ea6461 --- /dev/null +++ b/sys/src/cmd/postscript/tests/postdmd1 diff --git a/sys/src/cmd/postscript/tests/postgif1 b/sys/src/cmd/postscript/tests/postgif1 Binary files differnew file mode 100755 index 000000000..916014e2c --- /dev/null +++ b/sys/src/cmd/postscript/tests/postgif1 diff --git a/sys/src/cmd/postscript/tests/postmd1 b/sys/src/cmd/postscript/tests/postmd1 new file mode 100755 index 000000000..5318760e0 --- /dev/null +++ b/sys/src/cmd/postscript/tests/postmd1 @@ -0,0 +1,552 @@ + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + -.5602721e+08 .1143984e+09 -.6207247e+08 .0000000e+00 .0000000e+00 + -.1149580e+09 .2301959e+09 -.1138958e+09 .0000000e+00 .0000000e+00 + -.5853962e+08 .1144553e+09 -.5355661e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2468074e+08 .1401407e+07 .2608215e+08 .0000000e+00 .0000000e+00 + -.5473053e+06 -.2402412e+07 -.1855106e+07 .0000000e+00 .0000000e+00 + .2522804e+08 .1001005e+07 -.2422704e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 -.5219836e+08 .1123168e+09 -.6715163e+08 .0000000e+00 + .0000000e+00 -.1138958e+09 .2284693e+09 -.1110422e+09 .0000000e+00 + .0000000e+00 -.6060955e+08 .1126212e+09 -.4850979e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.2391785e+08 .3480520e+07 .2739837e+08 .0000000e+00 + .0000000e+00 -.1855106e+07 -.5966605e+07 -.4111499e+07 .0000000e+00 + .0000000e+00 .2577296e+08 .2486086e+07 -.2328688e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 -.4569685e+08 .1058615e+09 -.8114649e+08 + .0000000e+00 .0000000e+00 -.1110422e+09 .2277521e+09 -.1023531e+09 + .0000000e+00 .0000000e+00 -.6383463e+08 .1075339e+09 -.3707416e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.2260163e+08 .8226099e+07 .3082772e+08 + .0000000e+00 .0000000e+00 -.4111499e+07 -.1410188e+08 -.9990385e+07 + .0000000e+00 .0000000e+00 .2671312e+08 .5875785e+07 -.2083734e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.5644212e+08 .1144553e+09 -.6060955e+08 .0000000e+00 .0000000e+00 + -.1149657e+09 .2301010e+09 -.1139830e+09 .0000000e+00 .0000000e+00 + -.5811705e+08 .1144933e+09 -.5493231e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2477196e+08 .1001005e+07 .2577296e+08 .0000000e+00 .0000000e+00 + -.3648702e+06 -.1601608e+07 -.1236738e+07 .0000000e+00 .0000000e+00 + .2513683e+08 .6006029e+06 -.2453622e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.5355661e+08 .1126212e+09 -.6383463e+08 .0000000e+00 + .0000000e+00 -.1139830e+09 .2279620e+09 -.1114623e+09 .0000000e+00 + .0000000e+00 -.5916407e+08 .1128241e+09 -.5140673e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.2422704e+08 .2486086e+07 .2671312e+08 .0000000e+00 + .0000000e+00 -.1236738e+07 -.3977737e+07 -.2740999e+07 .0000000e+00 + .0000000e+00 .2546378e+08 .1491651e+07 -.2397213e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.4850979e+08 .1075339e+09 -.7261747e+08 + .0000000e+00 .0000000e+00 -.1114623e+09 .2249648e+09 -.1047203e+09 + .0000000e+00 .0000000e+00 -.6060164e+08 .1086488e+09 -.4323591e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.2328688e+08 .5875785e+07 .2916266e+08 + .0000000e+00 .0000000e+00 -.2740999e+07 -.9401256e+07 -.6660257e+07 + .0000000e+00 .0000000e+00 .2602787e+08 .3525471e+07 -.2250240e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.5685856e+08 .1144933e+09 -.5916407e+08 .0000000e+00 .0000000e+00 + -.1149703e+09 .2300441e+09 -.1140353e+09 .0000000e+00 .0000000e+00 + -.5769602e+08 .1145123e+09 -.5632545e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2486317e+08 .6006029e+06 .2546378e+08 .0000000e+00 .0000000e+00 + -.1824351e+06 -.8008039e+06 -.6183688e+06 .0000000e+00 .0000000e+00 + .2504561e+08 .2002010e+06 -.2484541e+08 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.5493231e+08 .1128241e+09 -.6060164e+08 .0000000e+00 + .0000000e+00 -.1140353e+09 .2276577e+09 -.1117143e+09 .0000000e+00 + .0000000e+00 -.5773604e+08 .1129256e+09 -.5438769e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.2453622e+08 .1491651e+07 .2602787e+08 .0000000e+00 + .0000000e+00 -.6183688e+06 -.1988868e+07 -.1370500e+07 .0000000e+00 + .0000000e+00 .2515459e+08 .4972171e+06 -.2465738e+08 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.5140673e+08 .1086488e+09 -.6456189e+08 + .0000000e+00 .0000000e+00 -.1117143e+09 .2232924e+09 -.1061407e+09 + .0000000e+00 .0000000e+00 -.5745266e+08 .1092063e+09 -.4987112e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.2397213e+08 .3525471e+07 .2749760e+08 + .0000000e+00 .0000000e+00 -.1370500e+07 -.4700628e+07 -.3330128e+07 + .0000000e+00 .0000000e+00 .2534262e+08 .1175157e+07 -.2416747e+08 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + -.2468074e+08 .2531926e+08 .0000000e+00 .0000000e+00 .0000000e+00 + -.5473053e+06 -.5473053e+06 .0000000e+00 .0000000e+00 .0000000e+00 + .2522804e+08 -.2477196e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.1087220e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .2174439e+08 .2174439e+08 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.1087220e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + -.2468074e+08 .1401407e+07 .2608215e+08 .0000000e+00 .0000000e+00 + -.5473053e+06 -.2402412e+07 -.1855106e+07 .0000000e+00 .0000000e+00 + .2522804e+08 .1001005e+07 -.2422704e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.2183162e+08 -.1095942e+08 .0000000e+00 .0000000e+00 + .2174439e+08 .4366323e+08 .2191884e+08 .0000000e+00 .0000000e+00 + -.1087220e+08 -.2183162e+08 -.1095942e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 -.2391785e+08 .3480520e+07 .2739837e+08 .0000000e+00 + .0000000e+00 -.1855106e+07 -.5966605e+07 -.4111499e+07 .0000000e+00 + .0000000e+00 .2577296e+08 .2486086e+07 -.2328688e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.1095942e+08 -.2213817e+08 -.1117875e+08 .0000000e+00 + .0000000e+00 .2191884e+08 .4427633e+08 .2235749e+08 .0000000e+00 + .0000000e+00 -.1095942e+08 -.2213817e+08 -.1117875e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 -.2260163e+08 .8226099e+07 .3082772e+08 + .0000000e+00 .0000000e+00 -.4111499e+07 -.1410188e+08 -.9990385e+07 + .0000000e+00 .0000000e+00 .2671312e+08 .5875785e+07 -.2083734e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.1117875e+08 -.2289026e+08 -.1171152e+08 + .0000000e+00 .0000000e+00 .2235749e+08 .4578053e+08 .2342304e+08 + .0000000e+00 .0000000e+00 -.1117875e+08 -.2289026e+08 -.1171152e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2477196e+08 .2522804e+08 .0000000e+00 .0000000e+00 .0000000e+00 + -.3648702e+06 -.3648702e+06 .0000000e+00 .0000000e+00 .0000000e+00 + .2513683e+08 -.2486317e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.1087220e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .2174439e+08 .2174439e+08 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.1087220e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2477196e+08 .1001005e+07 .2577296e+08 .0000000e+00 .0000000e+00 + -.3648702e+06 -.1601608e+07 -.1236738e+07 .0000000e+00 .0000000e+00 + .2513683e+08 .6006029e+06 -.2453622e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.2183162e+08 -.1095942e+08 .0000000e+00 .0000000e+00 + .2174439e+08 .4366323e+08 .2191884e+08 .0000000e+00 .0000000e+00 + -.1087220e+08 -.2183162e+08 -.1095942e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.2422704e+08 .2486086e+07 .2671312e+08 .0000000e+00 + .0000000e+00 -.1236738e+07 -.3977737e+07 -.2740999e+07 .0000000e+00 + .0000000e+00 .2546378e+08 .1491651e+07 -.2397213e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.1095942e+08 -.2213817e+08 -.1117875e+08 .0000000e+00 + .0000000e+00 .2191884e+08 .4427633e+08 .2235749e+08 .0000000e+00 + .0000000e+00 -.1095942e+08 -.2213817e+08 -.1117875e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.2328688e+08 .5875785e+07 .2916266e+08 + .0000000e+00 .0000000e+00 -.2740999e+07 -.9401256e+07 -.6660257e+07 + .0000000e+00 .0000000e+00 .2602787e+08 .3525471e+07 -.2250240e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.1117875e+08 -.2289026e+08 -.1171152e+08 + .0000000e+00 .0000000e+00 .2235749e+08 .4578053e+08 .2342304e+08 + .0000000e+00 .0000000e+00 -.1117875e+08 -.2289026e+08 -.1171152e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2486317e+08 .2513683e+08 .0000000e+00 .0000000e+00 .0000000e+00 + -.1824351e+06 -.1824351e+06 .0000000e+00 .0000000e+00 .0000000e+00 + .2504561e+08 -.2495439e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.1087220e+08 .0000000e+00 .0000000e+00 .0000000e+00 + .2174439e+08 .2174439e+08 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.1087220e+08 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.2486317e+08 .6006029e+06 .2546378e+08 .0000000e+00 .0000000e+00 + -.1824351e+06 -.8008039e+06 -.6183688e+06 .0000000e+00 .0000000e+00 + .2504561e+08 .2002010e+06 -.2484541e+08 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + -.1087220e+08 -.2183162e+08 -.1095942e+08 .0000000e+00 .0000000e+00 + .2174439e+08 .4366323e+08 .2191884e+08 .0000000e+00 .0000000e+00 + -.1087220e+08 -.2183162e+08 -.1095942e+08 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.2453622e+08 .1491651e+07 .2602787e+08 .0000000e+00 + .0000000e+00 -.6183688e+06 -.1988868e+07 -.1370500e+07 .0000000e+00 + .0000000e+00 .2515459e+08 .4972171e+06 -.2465738e+08 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 -.1095942e+08 -.2213817e+08 -.1117875e+08 .0000000e+00 + .0000000e+00 .2191884e+08 .4427633e+08 .2235749e+08 .0000000e+00 + .0000000e+00 -.1095942e+08 -.2213817e+08 -.1117875e+08 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.2397213e+08 .3525471e+07 .2749760e+08 + .0000000e+00 .0000000e+00 -.1370500e+07 -.4700628e+07 -.3330128e+07 + .0000000e+00 .0000000e+00 .2534262e+08 .1175157e+07 -.2416747e+08 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 -.1117875e+08 -.2289026e+08 -.1171152e+08 + .0000000e+00 .0000000e+00 .2235749e+08 .4578053e+08 .2342304e+08 + .0000000e+00 .0000000e+00 -.1117875e+08 -.2289026e+08 -.1171152e+08 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 .0000000e+00 + + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 + .0000000e+00 .0000000e+00 .0000000e+00 .0000000e+00 .1000000e+01 + + + diff --git a/sys/src/cmd/postscript/tests/postplot1 b/sys/src/cmd/postscript/tests/postplot1 Binary files differnew file mode 100755 index 000000000..edd2a504c --- /dev/null +++ b/sys/src/cmd/postscript/tests/postplot1 diff --git a/sys/src/cmd/postscript/tests/postprint1 b/sys/src/cmd/postscript/tests/postprint1 new file mode 100755 index 000000000..686040f98 --- /dev/null +++ b/sys/src/cmd/postscript/tests/postprint1 @@ -0,0 +1,13 @@ + +An Ascii test file for + postprint. Probably + + + + +should have more than one line, and +a few blank ones too. + + + +That's it. diff --git a/sys/src/cmd/postscript/tests/posttek1 b/sys/src/cmd/postscript/tests/posttek1 Binary files differnew file mode 100755 index 000000000..d45e68d1f --- /dev/null +++ b/sys/src/cmd/postscript/tests/posttek1 diff --git a/sys/src/cmd/postscript/tests/runtests b/sys/src/cmd/postscript/tests/runtests new file mode 100755 index 000000000..0c349b943 --- /dev/null +++ b/sys/src/cmd/postscript/tests/runtests @@ -0,0 +1,72 @@ +# +# Runs the test files that you'll find in this directory. You may want to change +# the definitions of PRINT and BINDIR. The default definition of BINDIR assumes +# the translators are installed in /usr/lbin/postscript, while PRINT just writes +# everything to stdout. Unrecognized options (ie. options other than -P and -B) +# are passed along to the translator. +# +# For example, if postio is installed in /usr/lbin/postscript, the following runs +# the dmd bitmap translator on the test file ./postdmd1 and sends the output to +# the printer attached to /dev/tty01. +# +# runtests -P'/usr/lbin/postscript/postio -l /dev/tty01' -pland postdmd +# + +OPTIONS= +PRINT=cat +BINDIR=/usr/lbin/postscript + +for i do + case $i in + -P*) PRINT=`echo $i | sed s/-P//`;; + + -B*) BINDIR=`echo $i | sed s/-B//`;; + + -*) OPTIONS="$OPTIONS $i";; + + *) break;; + esac + shift +done + +for i do + for j in ${i}*; do + if [ ! -r "$j" ]; then + break + fi + case $j in + dpost*) + $BINDIR/dpost $OPTIONS $j | $PRINT;; + + postbgi*) + $BINDIR/postbgi $OPTIONS $j | $PRINT;; + + posttek*) + $BINDIR/posttek $OPTIONS $j | $PRINT;; + + postdmd*) + $BINDIR/postdmd $OPTIONS $j | $PRINT;; + + postmd*) + $BINDIR/postmd $OPTIONS $j | $PRINT;; + + postdaisy*) + $BINDIR/postdaisy $OPTIONS $j | $PRINT;; + + postprint*) + $BINDIR/postprint $OPTIONS $j | $PRINT;; + + postplot*) + $BINDIR/postplot $OPTIONS $j | $PRINT;; + + postgif*) + $BINDIR/postgif $OPTIONS $j | $PRINT;; + + troff*) + pic $j | tbl | eqn | troff -mm -Tpost | $BINDIR/dpost $OPTIONS | $PRINT;; + + man*) + troff -man -Tpost $j | $BINDIR/dpost $OPTIONS | $PRINT;; + esac + done +done diff --git a/sys/src/cmd/postscript/tests/troff1 b/sys/src/cmd/postscript/tests/troff1 new file mode 100755 index 000000000..0f92ce9b9 --- /dev/null +++ b/sys/src/cmd/postscript/tests/troff1 @@ -0,0 +1,18 @@ +.EQ +delim $$ +.EN +.TS +doublebox; +c c +l l. +Name Definition +.sp +.vs +2p +Gamma $GAMMA (z) = int sub 0 sup inf t sup {z-1} e sup -t dt$ +Sine $sin (x) = 1 over 2i ( e sup ix - e sup -ix )$ +Error $ roman erf (z) = 2 over sqrt pi int sub 0 sup z e sup {-t sup 2} dt$ +Bessel $ J sub 0 (z) = 1 over pi int sub 0 sup pi cos ( z sin theta ) d theta $ +Zeta $ zeta (s) = sum from k=1 to inf k sup -s ~~( Re~s > 1)$ +.vs -2p +.sp 2 +.TE diff --git a/sys/src/cmd/postscript/text2post/mkfile b/sys/src/cmd/postscript/text2post/mkfile new file mode 100755 index 000000000..65adb4c38 --- /dev/null +++ b/sys/src/cmd/postscript/text2post/mkfile @@ -0,0 +1,22 @@ +</$objtype/mkfile + +<../config + +COMMONDIR=../common + +TARG=text2post + +OFILES=text2post.$O\ + +HFILES=$COMMONDIR/comments.h\ + $COMMONDIR/path.h\ + +BIN=$POSTBIN +</sys/src/cmd/mkone + +CFLAGS=-D'PROGRAMVERSION="0.1"' -D'DOROUND=1' -I$COMMONDIR + +install:V: $POSTLIB/pjw.char.ps + +$POSTLIB/pjw.char.ps: pjw.char.ps + cp $prereq $target diff --git a/sys/src/cmd/postscript/text2post/pjw.char.ps b/sys/src/cmd/postscript/text2post/pjw.char.ps new file mode 100755 index 000000000..553086189 --- /dev/null +++ b/sys/src/cmd/postscript/text2post/pjw.char.ps @@ -0,0 +1,142 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 1 -1 199 258 +%%Creator: MetaPost +%%CreationDate: 1994.06.28:1046 +/pjw1 { +37 211 moveto +37 206 lineto +41 206 lineto +43 212 lineto +44 212 46 212 46 210 curveto +41 198 35 186 35 174 curveto +50 174 66 175 81 173 curveto +81 171 lineto +61 171 lineto +61 170 lineto +86 170 lineto +88 168 89 166 90 164 curveto +101 164 111 169 122 172 curveto +139 172 lineto +125 194 115 219 93 233 curveto +87 234 80 236 74 235 curveto +64 229 54 224 46 217 curveto +45 217 44 217 44 218 curveto +61 242 lineto +67 248 72 258 82 258 curveto +94 257 107 256 119 254 curveto +134 247 147 239 161 231 curveto +180 231 lineto +180 226 174 228 171 226 curveto +178 220 185 214 192 207 curveto +189 207 187 207 187 205 curveto +190 205 193 204 196 203 curveto +198 193 202 181 193 181 curveto +193 177 198 175 198 171 curveto +196 171 194 171 194 169 curveto +195 165 196 161 198 157 curveto +194 147 193 135 184 130 curveto +180 130 lineto +169 107 lineto +171 103 176 104 180 104 curveto +180 93 176 81 166 76 curveto +162 76 157 77 155 80 curveto +153 80 152 80 151 80 curveto +151 71 lineto +155 71 lineto +155 68 153 65 152 63 curveto +145 62 lineto +141 47 144 31 144 15 curveto +141 0 lineto +124 0 107 -1 90 1 curveto +72 36 lineto +86 48 105 49 122 54 curveto +122 54 lineto +110 61 97 65 84 69 curveto +81 71 78 73 78 76 curveto +86 77 93 77 101 77 curveto +106 79 113 79 113 84 curveto +95 86 77 87 59 89 curveto +59 92 61 95 64 95 curveto +69 88 80 92 89 92 curveto +95 92 104 90 104 96 curveto +93 97 lineto +87 103 82 109 77 115 curveto +89 116 101 117 113 118 curveto +99 154 lineto +90 154 87 144 82 138 curveto +77 132 73 124 66 120 curveto +63 120 59 119 59 122 curveto +62 123 66 123 66 126 curveto +58 126 50 127 42 128 curveto +34 137 lineto +34 140 34 144 31 144 curveto +30 135 31 125 31 116 curveto +25 116 22 122 19 127 curveto +16 131 15 136 12 139 curveto +5 139 15 127 9 127 curveto +3 133 3 142 1 150 curveto +1 158 6 166 9 173 curveto +18 186 25 199 35 211 curveto +closepath +} bind def + +/pjw2 { +27 112 moveto +40 75 lineto +40 74 38 73 37 73 curveto +25 87 lineto +17 112 lineto +closepath +43 154 moveto +43 167 lineto +41 167 38 167 39 169 curveto +57 171 lineto +74 167 lineto +74 166 73 165 72 165 curveto +64 164 56 162 49 158 curveto +48 154 45 149 49 149 curveto +51 151 53 152 55 154 curveto +87 153 lineto +87 144 80 136 74 129 curveto +64 128 53 126 43 129 curveto +37 135 lineto +37 138 36 141 36 145 curveto +40 145 lineto +41 148 42 151 43 154 curveto closepath +108 145 moveto +119 145 130 143 141 140 curveto +146 134 155 129 149 126 curveto +138 124 126 123 116 129 curveto +113 134 108 139 108 145 curveto +closepath +114 96 moveto +116 103 118 110 121 117 curveto +128 117 134 112 139 107 curveto +139 101 137 96 132 93 curveto +closepath +134 162 moveto +115 162 lineto +115 162 115 163 115 164 curveto +134 164 lineto +closepath +117 73 moveto +115 78 121 81 125 85 curveto +129 85 lineto +130 83 131 81 131 79 curveto +128 74 lineto +124 74 121 73 117 73 curveto closepath +141 119 moveto +134 119 126 117 126 123 curveto +131 123 136 122 141 121 curveto +closepath +} bind def + +/pw { +%% pop +gsave +pointsize .0022 mul dup scale +currentpoint translate + pjw1 pjw2 eofill +grestore +6 0 rmoveto +} bind def diff --git a/sys/src/cmd/postscript/text2post/text2post.c b/sys/src/cmd/postscript/text2post/text2post.c new file mode 100755 index 000000000..9f547f4d3 --- /dev/null +++ b/sys/src/cmd/postscript/text2post/text2post.c @@ -0,0 +1,565 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <bio.h> +#include <comments.h> +#include <path.h> + +#define UNKNOWNCHAR "/sys/lib/postscript/prologues/pjw.char.ps" + +char *optnames = "a:c:f:l:m:n:o:p:s:t:x:y:P:"; + +Biobuf *bstdin, *bstdout, *bstderr; +Biobufhdr *Bstdin, *Bstdout, *Bstderr; +int char_no = 0; /* character to be done on a line */ +int line_no = 0; /* line number on a page */ +int page_no = 0; /* page number in a document */ +int in_string; /* Boolean, to know whether or not we are inside a Postscript string */ +int spaces = 0; +int tabs = 0; +int pages_printed; +double aspectratio = 1.0; +int copies = 1; +double magnification = 1.0; +int landscape = 0; +int formsperpage = 1; +int linesperpage = 66; +int pointsize = 10; +double xoffset = .25; +double yoffset = .25; +char *passthrough = 0; +static int pplistmaxsize=0; + +unsigned char *pplist=0; /* bitmap list for storing pages to print */ + +struct strtab { + int size; + char *str; + int used; +}; + +struct strtab charcode[256] = { + {4, "\\000"}, {4, "\\001"}, {4, "\\002"}, {4, "\\003"}, + {4, "\\004"}, {4, "\\005"}, {4, "\\006"}, {4, "\\007"}, + {4, "\\010"}, {4, "\\011"}, {4, "\\012"}, {4, "\\013"}, + {4, "\\014"}, {4, "\\015"}, {4, "\\016"}, {4, "\\017"}, + {4, "\\020"}, {4, "\\021"}, {4, "\\022"}, {4, "\\023"}, + {4, "\\024"}, {4, "\\025"}, {4, "\\026"}, {4, "\\027"}, + {4, "\\030"}, {4, "\\031"}, {4, "\\032"}, {4, "\\033"}, + {4, "\\034"}, {4, "\\035"}, {4, "\\036"}, {4, "\\037"}, + {1, " "}, {1, "!"}, {1, "\""}, {1, "#"}, + {1, "$"}, {1, "%"}, {1, "&"}, {1, "'"}, + {2, "\\("}, {2, "\\)"}, {1, "*"}, {1, "+"}, + {1, ","}, {1, "-"}, {1, "."}, {1, "/"}, + {1, "0"}, {1, "1"}, {1, "2"}, {1, "3"}, + {1, "4"}, {1, "5"}, {1, "6"}, {1, "7"}, + {1, "8"}, {1, "9"}, {1, ":"}, {1, ";"}, + {1, "<"}, {1, "="}, {1, ">"}, {1, "?"}, + {1, "@"}, {1, "A"}, {1, "B"}, {1, "C"}, + {1, "D"}, {1, "E"}, {1, "F"}, {1, "G"}, + {1, "H"}, {1, "I"}, {1, "J"}, {1, "K"}, + {1, "L"}, {1, "M"}, {1, "N"}, {1, "O"}, + {1, "P"}, {1, "Q"}, {1, "R"}, {1, "S"}, + {1, "T"}, {1, "U"}, {1, "V"}, {1, "W"}, + {1, "X"}, {1, "Y"}, {1, "Z"}, {1, "["}, + {2, "\\\\"}, {1, "]"}, {1, "^"}, {1, "_"}, + {1, "`"}, {1, "a"}, {1, "b"}, {1, "c"}, + {1, "d"}, {1, "e"}, {1, "f"}, {1, "g"}, + {1, "h"}, {1, "i"}, {1, "j"}, {1, "k"}, + {1, "l"}, {1, "m"}, {1, "n"}, {1, "o"}, + {1, "p"}, {1, "q"}, {1, "r"}, {1, "s"}, + {1, "t"}, {1, "u"}, {1, "v"}, {1, "w"}, + {1, "x"}, {1, "y"}, {1, "z"}, {1, "{"}, + {1, "|"}, {1, "}"}, {1, "~"}, {4, "\\177"}, + {4, "\\200"}, {4, "\\201"}, {4, "\\202"}, {4, "\\203"}, + {4, "\\204"}, {4, "\\205"}, {4, "\\206"}, {4, "\\207"}, + {4, "\\210"}, {4, "\\211"}, {4, "\\212"}, {4, "\\213"}, + {4, "\\214"}, {4, "\\215"}, {4, "\\216"}, {4, "\\217"}, + {4, "\\220"}, {4, "\\221"}, {4, "\\222"}, {4, "\\223"}, + {4, "\\224"}, {4, "\\225"}, {4, "\\226"}, {4, "\\227"}, + {4, "\\230"}, {4, "\\231"}, {4, "\\232"}, {4, "\\233"}, + {4, "\\234"}, {4, "\\235"}, {4, "\\236"}, {4, "\\237"}, + {4, "\\240"}, {4, "\\241"}, {4, "\\242"}, {4, "\\243"}, + {4, "\\244"}, {4, "\\245"}, {4, "\\246"}, {4, "\\247"}, + {4, "\\250"}, {4, "\\251"}, {4, "\\252"}, {4, "\\253"}, + {4, "\\254"}, {4, "\\255"}, {4, "\\256"}, {4, "\\257"}, + {4, "\\260"}, {4, "\\261"}, {4, "\\262"}, {4, "\\263"}, + {4, "\\264"}, {4, "\\265"}, {4, "\\266"}, {4, "\\267"}, + {4, "\\270"}, {4, "\\271"}, {4, "\\272"}, {4, "\\273"}, + {4, "\\274"}, {4, "\\275"}, {4, "\\276"}, {4, "\\277"}, + {4, "\\300"}, {4, "\\301"}, {4, "\\302"}, {4, "\\303"}, + {4, "\\304"}, {4, "\\305"}, {4, "\\306"}, {4, "\\307"}, + {4, "\\310"}, {4, "\\311"}, {4, "\\312"}, {4, "\\313"}, + {4, "\\314"}, {4, "\\315"}, {4, "\\316"}, {4, "\\317"}, + {4, "\\320"}, {4, "\\321"}, {4, "\\322"}, {4, "\\323"}, + {4, "\\324"}, {4, "\\325"}, {4, "\\326"}, {4, "\\327"}, + {4, "\\330"}, {4, "\\331"}, {4, "\\332"}, {4, "\\333"}, + {4, "\\334"}, {4, "\\335"}, {4, "\\336"}, {4, "\\337"}, + {4, "\\340"}, {4, "\\341"}, {4, "\\342"}, {4, "\\343"}, + {4, "\\344"}, {4, "\\345"}, {4, "\\346"}, {4, "\\347"}, + {4, "\\350"}, {4, "\\351"}, {4, "\\352"}, {4, "\\353"}, + {4, "\\354"}, {4, "\\355"}, {4, "\\356"}, {4, "\\357"}, + {4, "\\360"}, {4, "\\361"}, {4, "\\362"}, {4, "\\363"}, + {4, "\\364"}, {4, "\\365"}, {4, "\\366"}, {4, "\\367"}, + {4, "\\370"}, {4, "\\371"}, {4, "\\372"}, {4, "\\373"}, + {4, "\\374"}, {4, "\\375"}, {4, "\\376"}, {4, "\\377"} +}; + +#define FONTABSIZE 0x27 + +struct strtab fontname[FONTABSIZE] = { + {19, "LucidaSansUnicode00", 0}, + {19, "LucidaSansUnicode01", 0}, + {19, "LucidaSansUnicode02", 0}, + {19, "LucidaSansUnicode03", 0}, + {19, "LucidaSansUnicode04", 0}, + {19, "LucidaSansUnicode05", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {0, "", 0}, + {19, "LucidaSansUnicode20", 0}, + {19, "LucidaSansUnicode21", 0}, + {19, "LucidaSansUnicode22", 0}, + {0, "", 0}, + {19, "LucidaSansUnicode24", 0}, + {19, "LucidaSansUnicode25", 0}, + {7, "Courier", 0} +}; + +/* This was taken from postprint */ + +int +cat(char *filename) { + Biobuf *bfile; + Biobufhdr *Bfile; + int n; + static char buf[Bsize]; + + bstdin = Bopen(filename, 0); + if (bstdin == 0) { + return(1); + } + Bstdin = &(bstdin->Biobufhdr); + if ((bfile = Bopen(filename, OREAD)) == 0) { + return(1); + } + Bfile = &(bfile->Biobufhdr); + while ((n=Bread(Bfile, buf, Bsize)) > 0) { + if (Bwrite(Bstdout, buf, n) != n) { + return(1); + } + } + if (n != 0) { + return(1); + } + return(0); +} + +void +prologues(void) { + char *ts; + int tabstop; + + Bprint(Bstdout, "%s", CONFORMING); + Bprint(Bstdout, "%s %s\n", VERSION, PROGRAMVERSION); + Bprint(Bstdout, "%s %s\n", DOCUMENTFONTS, ATEND); + Bprint(Bstdout, "%s %s\n", PAGES, ATEND); + Bprint(Bstdout, "%s", ENDCOMMENTS); + + if (cat(POSTPRINT)) { + Bprint(Bstderr, "can't read %s", POSTPRINT); + exits("prologue"); + } + + if (DOROUND) + cat(ROUNDPAGE); + + tabstop = 0; + ts = getenv("tabstop"); + if(ts != nil) + tabstop = strtol(ts, nil, 0); + if(tabstop == 0) + tabstop = 8; + Bprint(Bstdout, "/f {findfont pointsize scalefont setfont} bind def\n"); + Bprint(Bstdout, "/tabwidth /Courier f ("); + while(tabstop--) + Bputc(Bstdout, 'n'); + Bprint(Bstdout, ") stringwidth pop def\n"); + Bprint(Bstdout, "/tab {tabwidth 0 ne {currentpoint 3 1 roll exch tabwidth mul add tabwidth\n"); + Bprint(Bstdout, "\tdiv truncate tabwidth mul exch moveto} if} bind def\n"); + Bprint(Bstdout, "/spacewidth /%s f ( ) stringwidth pop def\n", fontname[0].str); + Bprint(Bstdout, "/sp {spacewidth mul 0 rmoveto} bind def\n"); + Bprint(Bstdout, "%s", ENDPROLOG); + Bprint(Bstdout, "%s", BEGINSETUP); + Bprint(Bstdout, "mark\n"); + + if (formsperpage > 1) { + Bprint(Bstdout, "%s %d\n", FORMSPERPAGE, formsperpage); + Bprint(Bstdout, "/formsperpage %d def\n", formsperpage); + } + if (aspectratio != 1) Bprint(Bstdout, "/aspectratio %g def\n", aspectratio); + if (copies != 1) Bprint(Bstdout, "/#copies %d store\n", copies); + if (landscape) Bprint(Bstdout, "/landscape true def\n"); + if (magnification != 1) Bprint(Bstdout, "/magnification %s def\n", magnification); + if (pointsize != 10) Bprint(Bstdout, "/pointsize %d def\n", pointsize); + if (xoffset != .25) Bprint(Bstdout, "/xoffset %g def\n", xoffset); + if (yoffset != .25) Bprint(Bstdout, "/yoffset %g def\n", yoffset); + cat(ENCODINGDIR"/Latin1.enc"); + if (passthrough != 0) Bprint(Bstdout, "%s\n", passthrough); + Bprint(Bstdout, "setup\n"); + if (formsperpage > 1) { + cat(FORMFILE); + Bprint(Bstdout, "%d setupforms \n", formsperpage); + } + if (cat(UNKNOWNCHAR)) + Bprint(Bstderr, "cannot open %s\n", UNKNOWNCHAR); + Bprint(Bstdout, "%s", ENDSETUP); +} + +int +pageon(void) { + if (pplist == 0 && page_no != 0) return(1); /* no page list, print all pages */ + if (page_no/8 < pplistmaxsize && (pplist[page_no/8] & 1<<(page_no%8))) + return(1); + else + return(0); +} + +void +startpage(void) { + ++char_no; + ++line_no; + ++page_no; + if (pageon()) { + ++pages_printed; + Bprint(Bstdout, "%s %d %d\n", PAGE, page_no, pages_printed); + Bprint(Bstdout, "/saveobj save def\n"); + Bprint(Bstdout, "mark\n"); + Bprint(Bstdout, "%d pagesetup\n", pages_printed); + } +} + +void +endpage(void) { + line_no = 0; + char_no = 0; + if (pageon()) { + Bprint(Bstdout, "cleartomark\n"); + Bprint(Bstdout, "showpage\n"); + Bprint(Bstdout, "saveobj restore\n"); + Bprint(Bstdout, "%s %d %d\n", ENDPAGE, page_no, pages_printed); + } +} + +void +startstring(void) { + if (!in_string) { + if (pageon()) Bprint(Bstdout, "("); + in_string = 1; + } +} + +void +endstring(void) { + if (in_string) { + if (pageon()) Bprint(Bstdout, ") show "); + in_string = 0; + } +} + +void +prspace(void) { + if (spaces) { + endstring(); + if (pageon()) Bprint(Bstdout, "%d sp ", spaces); + spaces = 0; + } +} + +void +prtab(void) { + if (tabs) { + endstring(); + if (pageon()) Bprint(Bstdout, "%d tab ", tabs); + tabs = 0; + } +} + +void +txt2post(void) { + int lastfont = -1; + int lastchar = -1; + int thisfont, thischar; + long r; + + in_string = 0; + char_no = 0; + line_no = 0; + page_no = 0; + spaces = 0; + fontname[0].used++; + while ((r=Bgetrune(Bstdin)) >= 0) { + thischar = r & 0xff; + thisfont = (r>>8) & 0xff; + + if (line_no == 0 && char_no == 0) + startpage(); + + if (line_no == 1 && char_no == 1) { + if (pageon()) Bprint(Bstdout, " /%s f\n", fontname[thisfont].str); + lastfont = thisfont; + } + + switch (r) { + case ' ': + prtab(); + if (lastfont > 0) { + spaces++; + continue; + } + break; + case '\n': + case '\f': + startstring(); + if (pageon()) Bprint(Bstdout, ")l\n"); + char_no = 1; + in_string = 0; + spaces = 0; + tabs = 0; + if (++line_no > linesperpage || r == '\f') { + endpage(); + } + lastchar = -1; + continue; + case '\t': + prspace(); + tabs++; + char_no++; + lastchar = -1; + continue; + case '\b': + /* just toss out backspaces for now */ + if (lastchar != -1) { + endstring(); + if (pageon()) Bprint(Bstdout, "(%s) stringwidth pop neg 0 rmoveto ", charcode[lastchar].str); + } + char_no++; + lastchar = -1; + continue; + } + + /* do something if font is out of table range */ + if (thisfont>=FONTABSIZE || fontname[thisfont].size == 0) { + prspace(); + prtab(); + endstring(); + Bprint(Bstdout, "pw "); + char_no++; + lastchar = -1; + continue; + } + + if (thisfont != lastfont) { + endstring(); + if (pageon()) { + Bprint(Bstdout, "/%s f\n", fontname[thisfont].str); + } + fontname[thisfont].used++; + } + prspace(); + prtab(); + startstring(); + if (pageon()) Bprint(Bstdout, "%s", charcode[thischar].str); +/* if (pageon()) Bprint(Bstdout, "%2.2x", thischar); /* try hex strings*/ + char_no++; + lastchar = thischar; + lastfont = thisfont; + } + if (line_no != 0 || char_no != 0) { + if (char_no != 1) { + Bprint(Bstderr, "premature EOF: newline appended\n"); + startstring(); + if (pageon()) Bprint(Bstdout, ")l\n"); + } + endpage(); + } +} + +void +pagelist(char *list) { + char c; + int n, m; + int state, start, end; + + if (list == 0) return; + state = 1; + while ((c=*list) != '\0') { + n = 0; + while (isdigit(c)) { + n = n * 10 + c - '0'; + c = *++list; + } + switch (state) { + case 1: + start = n; + case 2: + if (n/8+1 > pplistmaxsize) { + pplistmaxsize = n/8+1; + if ((pplist = realloc(pplist, n/8+1)) == 0) { + Bprint(Bstderr, "cannot allocate memory for page list\n"); + exits("malloc"); + } + } + for (m=start; m<=n; m++) + pplist[m/8] |= 1<<(m%8); + break; + } + switch (c) { + case '-': + state = 2; + list++; + break; + case ',': + state = 1; + list++; + break; + case '\0': + break; + } + } +} + +void +finish(void) { + int i; + + Bprint(Bstdout, "%s", TRAILER); + Bprint(Bstdout, "done\n"); + Bprint(Bstdout, "%s", DOCUMENTFONTS); + + for (i=0; i<FONTABSIZE; i++) + if (fontname[i].used) + Bprint(Bstdout, " %s", fontname[i].str); + Bprint(Bstdout, "\n"); + + Bprint(Bstdout, "%s %d\n", PAGES, pages_printed); + +} + +main(int argc, char *argv[]) { + int i; + char *t; + Biobuf *input; + + if ((bstderr = (Biobuf *)malloc(sizeof(Biobuf))) == nil) + exits("malloc"); + if (Binit(bstderr, 2, OWRITE) == Beof) + exits("Binit"); + Bstderr = &(bstderr->Biobufhdr); + + if ((bstdout = (Biobuf *)malloc(sizeof(Biobuf))) == nil) + exits("malloc"); + if (Binit(bstdout, 1, OWRITE) == Beof) + exits("Binit"); + Bstdout = &(bstdout->Biobufhdr); + + ARGBEGIN{ + case 'a': /* aspect ratio */ + aspectratio = atof(ARGF()); + break; + case 'c': /* copies */ + copies = atoi(ARGF()); + break; + case 'f': /* primary font, for now */ + t = ARGF(); + fontname[0].str = malloc(strlen(t)+1); + strcpy(fontname[0].str, t); + break; + case 'l': /* lines per page */ + linesperpage = atoi(ARGF()); + break; + case 'm': /* magnification */ + magnification = atof(ARGF()); + break; + case 'n': /* forms per page */ + formsperpage = atoi(ARGF()); + break; + case 'o': /* output page list */ + pagelist(ARGF()); + break; + case 'p': /* landscape or portrait mode */ + if ( ARGF()[0] == 'l' ) + landscape = 1; + else + landscape = 0; + break; + case 's': /* point size */ + pointsize = atoi(ARGF()); + break; + case 'x': /* shift things horizontally */ + xoffset = atof(ARGF()); + break; + + case 'y': /* and vertically on the page */ + yoffset = atof(ARGF()); + break; + case 'P': /* PostScript pass through */ + t = ARGF(); + i = strlen(t) + 1; + passthrough = malloc(i); + if (passthrough == 0) { + Bprint(Bstderr, "cannot allocate memory for argument string\n"); + exits("malloc"); + } + strncpy(passthrough, t, i); + break; + default: /* don't know what to do for ch */ + Bprint(Bstderr, "unknown option %C\n", ARGC()); + break; + }ARGEND; + prologues(); + if (argc <= 0) { + if ((bstdin = (Biobuf *)malloc(sizeof(Biobuf))) == nil) + exits("malloc"); + if (Binit(bstdin, 0, OREAD) == Beof) { + fprint(2, "cannot Binit stdin\n"); + exits("Binit"); + } + Bstdin = &(bstdin->Biobufhdr); + txt2post(); + } + for (i=0; i<argc; i++) { + bstdin = Bopen(argv[i], 0); + if (bstdin == 0) { + fprint(2, "cannot open file %s\n", argv[i]); + continue; + } + Bstdin = &(bstdin->Biobufhdr); + txt2post(); + } + finish(); + exits(""); +} diff --git a/sys/src/cmd/postscript/tr2post/Bgetfield.c b/sys/src/cmd/postscript/tr2post/Bgetfield.c new file mode 100755 index 000000000..e4305c6ea --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/Bgetfield.c @@ -0,0 +1,153 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include "../common/common.h" +#include "tr2post.h" + +int +isspace(Rune r) +{ + return(r==' ' || r=='\t' || r=='\n' || r == '\r' || r=='\f'); +} + +int +Bskipws(Biobufhdr *bp) { + int r; + char c[UTFmax]; + int sindex = 0; + + /* skip over initial white space */ + do { + r = Bgetrune(bp); + if (r == '\n') inputlineno++; + sindex++; + } while (r>=0 && isspace(r)); + if (r<0) { + return(-1); + } else if (!isspace(r)) { + Bungetrune(bp); + --sindex; + } + return(sindex); +} + +int +asc2dig(char c, int base) { + if (c >= '0' && c <= '9') + if (base == 8 && c > '7') return(-1); + else return(c - '0'); + + if (base == 16) + if (c >= 'a' && c <= 'f') return(10 + c - 'a'); + else if (c >= 'A' && c <= 'F') return(10 + c - 'A'); + + return(-1); +} + +/* get a string of type: "d" for decimal integer, "u" for unsigned, + * "s" for string", "c" for char, + * return the number of characters gotten for the field. If nothing + * was gotten and the end of file was reached, a negative value + * from the Bgetrune is returned. + */ + +int +Bgetfield(Biobufhdr *bp, int type, void *thing, int size) { + int r; + Rune R; + char c[UTFmax]; + int sindex = 0, i, j, n = 0; + int negate = 0; + int base = 10; + BOOLEAN bailout = FALSE; + int dig; + unsigned int u = 0; + + /* skip over initial white space */ + if (Bskipws(bp) < 0) + return(-1); + + switch (type) { + case 'd': + while (!bailout && (r = Bgetrune(bp))>=0) { + switch (sindex++) { + case 0: + switch (r) { + case '-': + negate = 1; + continue; + case '+': + continue; + case '0': + base = 8; + continue; + default: + break; + } + break; + case 1: + if ((r == 'x' || r == 'X') && base == 8) { + base = 16; + continue; + } + } + if ((dig = asc2dig(r, base)) == -1) bailout = TRUE; + else n = dig + (n * base); + } + if (r < 0) return(-1); + *(int *)thing = (negate)?-n:n; + Bungetrune(bp); + break; + case 'u': + while (!bailout && (r = Bgetrune(bp))>=0) { + switch (sindex++) { + case 0: + if (*c == '0') { + base = 8; + continue; + } + break; + case 1: + if ((r == 'x' || r == 'X') && base == 8) { + base = 16; + continue; + } + } + if ((dig = asc2dig(r, base)) == -1) bailout = TRUE; + else u = dig + (n * base); + } + *(int *)thing = u; + if (r < 0) return(-1); + Bungetrune(bp); + break; + case 's': + j = 0; + while ((size>j+UTFmax) && (r = Bgetrune(bp))>=0 && !isspace(r)) { + R = r; + i = runetochar(&(((char *)thing)[j]), &R); + j += i; + sindex++; + } + ((char *)thing)[j++] = '\0'; + if (r < 0) return(-1); + Bungetrune(bp); + break; + case 'r': + if ((r = Bgetrune(bp))>=0) { + *(Rune *)thing = r; + sindex++; + return(sindex); + } + if (r <= 0) return(-1); + Bungetrune(bp); + break; + default: + return(-2); + } + if (r < 0 && sindex == 0) + return(r); + else if (bailout && sindex == 1) { + return(0); + } else + return(sindex); +} diff --git a/sys/src/cmd/postscript/tr2post/chartab.c b/sys/src/cmd/postscript/tr2post/chartab.c new file mode 100755 index 000000000..f2baa804a --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/chartab.c @@ -0,0 +1,459 @@ +/* Unicode | PostScript + * start end | offset font name + * 0x0000 0x00ff 0x00 LucidaSansUnicode00 + */ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include "common.h" +#include "tr2post.h" +#include "comments.h" +#include "path.h" + +/* Postscript font names, e.g., `LucidaSansUnicode00' + * names may only be added because reference to the + * names is made by indexing into this table. + */ +static struct pfnament *pfnafontmtab = 0; +static int pfnamcnt = 0; +int curpostfontid = -1; +int curfontsize = -1; +int curtrofffontid = -1; +static int curfontpos = -1; +static int fontheight = 0; +static int fontslant = 0; + +/* This is troffs mounted font table. It is an anachronism resulting + * from the design of the APS typesetter. fontmnt is the + * number of positions available. fontmnt is really 11, but + * should not be limited. + */ +int fontmnt = 0; +char **fontmtab; + +struct troffont *troffontab = 0; + +int troffontcnt = 0; + +void +mountfont(int pos, char *fontname) { + int i; + + if (debug) Bprint(Bstderr, "mountfont(%d, %s)\n", pos, fontname); + if (pos < 0 || pos >= fontmnt) + error(FATAL, "cannot mount a font at position %d,\n can only mount into postions 0-%d\n", + pos, fontmnt-1); + + i = strlen(fontname); + fontmtab[pos] = galloc(fontmtab[pos], i+1, "mountfont():fontmtab"); + strcpy(fontmtab[pos], fontname); + if (curfontpos == pos) curfontpos = -1; +} + +void +settrfont(void) { + if (curfontpos == fontpos) return; + + if (fontmtab[fontpos] == 0) + error(FATAL, "Font at position %d was not initialized, botch!\n", fontpos); + + curtrofffontid = findtfn(fontmtab[fontpos], 1); + if (debug) Bprint(Bstderr, "settrfont()-> curtrofffontid=%d\n", curtrofffontid); + curfontpos = fontpos; + if (curtrofffontid < 0) { + int i; + + error(WARNING, "fontpos=%d\n", fontpos); + for (i=0; i<fontmnt; i++) + if (fontmtab[i] == 0) + error(WARNING, "fontmtab[%d]=0x0\n", i); + else + error(WARNING, "fontmtab[%d]=%s\n", i, fontmtab[i]); + exits("settrfont()"); + } +} + +void +setpsfont(int psftid, int fontsize) { + if (psftid == curpostfontid && fontsize == curfontsize) return; + if (psftid >= pfnamcnt) + error(FATAL, "Postscript font index=%d used but not defined, there are only %d fonts\n", + psftid, pfnamcnt); + + endstring(); + if (pageon()) { + Bprint(Bstdout, "%d /%s f\n", fontsize, pfnafontmtab[psftid].str); + if ( fontheight != 0 || fontslant != 0 ) + Bprint(Bstdout, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : fontsize); + pfnafontmtab[psftid].used = 1; + curpostfontid = psftid; + curfontsize = fontsize; + } +} + +/* find index of PostScript font name in table + * returns -1 if name is not in table + * If insflg is not zero + * and the name is not found in the table, insert it. + */ +int +findpfn(char *fontname, int insflg) { + char *tp; + int i; + + for (i=0; i<pfnamcnt; i++) { + if (strcmp(pfnafontmtab[i].str, fontname) == 0) + return(i); + } + if (insflg) { + tp = galloc(pfnafontmtab, sizeof(struct pfnament)*(pfnamcnt+1), "findpfn():pfnafontmtab"); + if (tp == 0) + return(-2); + pfnafontmtab = (struct pfnament *)tp; + i = strlen(fontname); + pfnafontmtab[pfnamcnt].str = galloc(0, i+1, "findpfn():pfnafontmtab[].str"); + strncpy(pfnafontmtab[pfnamcnt].str, fontname, i); + pfnafontmtab[pfnamcnt].str[i] = '\0'; + pfnafontmtab[pfnamcnt].used = 0; + return(pfnamcnt++); + } + return(-1); +} + +char postroffdirname[] = "/sys/lib/postscript/troff"; /* "/sys/lib/postscript/troff/"; */ +char troffmetricdirname[] = "/sys/lib/troff/font"; /* "/sys/lib/troff/font/devutf/"; */ + +int +readpsfontdesc(char *fontname, int trindex) { + static char *filename = 0; + Biobuf *bfd; + Biobufhdr *Bfd; + int warn = 0, errorflg = 0, line =1, rv; + int start, end, offset; + int startfont, endfont, startchar, endchar, i, pfid; + char psfontnam[128]; + struct troffont *tp; + struct charent *cp[]; + + if (debug) Bprint(Bstderr, "readpsfontdesc(%s,%d)\n", fontname, trindex); + filename=galloc(filename, strlen(postroffdirname)+1+strlen(fontname)+1, "readpsfontdesc: cannot allocate memory\n"); + sprint(filename, "%s/%s", postroffdirname, fontname); + + bfd = Bopen(filename, OREAD); + if (bfd == 0) { + error(WARNING, "cannot open file %s\n", filename); + return(0); + } + Bfd = &(bfd->Biobufhdr); + + do { + offset = 0; + if ((rv=Bgetfield(Bfd, 'd', &start, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal start value\n", filename, line); + } else if (rv < 0) break; + if ((rv=Bgetfield(Bfd, 'd', &end, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal end value\n", filename, line); + } else if (rv < 0) break; + if ((rv=Bgetfield(Bfd, 'd', &offset, 0)) < 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal offset value\n", filename, line); + } + if ((rv=Bgetfield(Bfd, 's', psfontnam, 128)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal fontname value\n", filename, line); + } else if (rv < 0) break; + Brdline(Bfd, '\n'); + if (!errorflg) { + struct psfent *psfentp; + startfont = RUNEGETGROUP(start); + startchar = RUNEGETCHAR(start); + endfont = RUNEGETGROUP(end); + endchar = RUNEGETCHAR(end); + pfid = findpfn(psfontnam, 1); + if (startfont != endfont) { + error(WARNING, "font descriptions must not cross 256 glyph block boundary\n"); + errorflg = 1; + break; + } + tp = &(troffontab[trindex]); + tp->psfmap = galloc(tp->psfmap, ++(tp->psfmapsize)*sizeof(struct psfent), "readpsfontdesc():psfmap"); + psfentp = &(tp->psfmap[tp->psfmapsize-1]); + psfentp->start = start; + psfentp->end = end; + psfentp->offset = offset; + psfentp->psftid = pfid; + if (debug) { + Bprint(Bstderr, "\tpsfmap->start=0x%x\n", start); + Bprint(Bstderr, "\tpsfmap->end=0x%x\n", end); + Bprint(Bstderr, "\tpsfmap->offset=0x%x\n", offset); + Bprint(Bstderr, "\tpsfmap->pfid=0x%x\n", pfid); + } +/* + for (i=startchar; i<=endchar; i++) { + tp->charent[startfont][i].postfontid = pfid; + tp->charent[startfont][i].postcharid = i + offset - startchar; + } + */ + if (debug) { + Bprint(Bstderr, "%x %x ", start, end); + if (offset) Bprint(Bstderr, "%x ", offset); + Bprint(Bstderr, "%s\n", psfontnam); + } + line++; + } + } while(errorflg != 1); + Bterm(Bfd); + return(1); +} + +int +readtroffmetric(char *fontname, int trindex) { + static char *filename = 0; + Biobuf *bfd; + Biobufhdr *Bfd; + int warn = 0, errorflg = 0, line =1, rv; + struct troffont *tp; + struct charent **cp; + char stoken[128], *str; + int ntoken; + Rune troffchar, quote; + int width, flag, charnum, thisfont, thischar; + BOOLEAN specharflag; + + if (debug) Bprint(Bstderr, "readtroffmetric(%s,%d)\n", fontname, trindex); + filename=galloc(filename, strlen(troffmetricdirname)+4+strlen(devname)+1+strlen(fontname)+1, "readtroffmetric():filename"); + sprint(filename, "%s/dev%s/%s", troffmetricdirname, devname, fontname); + + bfd = Bopen(filename, OREAD); + if (bfd == 0) { + error(WARNING, "cannot open file %s\n", filename); + return(0); + } + Bfd = &(bfd->Biobufhdr); + do { + /* deal with the few lines at the beginning of the + * troff font metric files. + */ + if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal token\n", filename, line); + } else if (rv < 0) break; + if (debug) { + Bprint(Bstderr, "%s\n", stoken); + } + + if (strcmp(stoken, "name") == 0) { + if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal token\n", filename, line); + } else if (rv < 0) break; + } else if (strcmp(stoken, "named") == 0) { + Brdline(Bfd, '\n'); + } else if (strcmp(stoken, "fontname") == 0) { + if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal token\n", filename, line); + } else if (rv < 0) break; + } else if (strcmp(stoken, "spacewidth") == 0) { + if ((rv=Bgetfield(Bfd, 'd', &ntoken, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal token\n", filename, line); + } else if (rv < 0) break; + troffontab[trindex].spacewidth = ntoken; + thisfont = RUNEGETGROUP(' '); + thischar = RUNEGETCHAR(' '); + for (cp = &(troffontab[trindex].charent[thisfont][thischar]); *cp != 0; cp = &((*cp)->next)) + if ((*cp)->name) + if (strcmp((*cp)->name, " ") == 0) + break; + + if (*cp == 0) *cp = galloc(0, sizeof(struct charent), "readtroffmetric:charent"); + (*cp)->postfontid = thisfont; + (*cp)->postcharid = thischar; + (*cp)->troffcharwidth = ntoken; + (*cp)->name = galloc(0, 2, "readtroffmetric: char name"); + (*cp)->next = 0; + strcpy((*cp)->name, " "); + } else if (strcmp(stoken, "special") == 0) { + troffontab[trindex].special = TRUE; + } else if (strcmp(stoken, "charset") == 0) { + line++; + break; + } + if (!errorflg) { + line++; + } + } while(!errorflg && rv>=0); + while(!errorflg && rv>=0) { + if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal rune token <0x%x> rv=%d\n", filename, line, troffchar, rv); + } else if (rv < 0) break; + if (utflen(stoken) > 1) specharflag = TRUE; + else specharflag = FALSE; + /* if this character is a quote we have to use the previous characters info */ + if ((rv=Bgetfield(Bfd, 'r', "e, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal width or quote token <0x%x> rv=%d\n", filename, line, quote, rv); + } else if (rv < 0) break; + if (quote == '"') { + /* need some code here */ + + goto flush; + } else { + Bungetrune(Bfd); + } + + if ((rv=Bgetfield(Bfd, 'd', &width, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal width token <0x%x> rv=%d\n", filename, line, troffchar, rv); + } else if (rv < 0) break; + if ((rv=Bgetfield(Bfd, 'd', &flag, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal flag token <0x%x> rv=%d\n", filename, line, troffchar, rv); + } else if (rv < 0) break; + if ((rv=Bgetfield(Bfd, 'd', &charnum, 0)) == 0) { + errorflg = 1; + error(WARNING, "file %s:%d illegal character number token <0x%x> rv=%d\n", filename, line, troffchar, rv); + } else if (rv < 0) break; +flush: + str = Brdline(Bfd, '\n'); + /* stash the crap from the end of the line for debugging */ + if (debug) { + if (str == 0) { + Bprint(Bstderr, "premature EOF\n"); + return(0); + } + str[Blinelen(Bfd)-1] = '\0'; + } + line++; + chartorune(&troffchar, stoken); + if (specharflag) { + if (debug) + Bprint(Bstderr, "%s %d %d 0x%x %s # special\n",stoken, width, flag, charnum, str); + } + if (strcmp(stoken, "---") == 0) { + thisfont = RUNEGETGROUP(charnum); + thischar = RUNEGETCHAR(charnum); + stoken[0] = '\0'; + } else { + thisfont = RUNEGETGROUP(troffchar); + thischar = RUNEGETCHAR(troffchar); + } + for (cp = &(troffontab[trindex].charent[thisfont][thischar]); *cp != 0; cp = &((*cp)->next)) + if ((*cp)->name) { + if (debug) Bprint(Bstderr, "installing <%s>, found <%s>\n", stoken, (*cp)->name); + if (strcmp((*cp)->name, stoken) == 0) + break; + } + if (*cp == 0) *cp = galloc(0, sizeof(struct charent), "readtroffmetric:charent"); + (*cp)->postfontid = RUNEGETGROUP(charnum); + (*cp)->postcharid = RUNEGETCHAR(charnum); + (*cp)->troffcharwidth = width; + (*cp)->name = galloc(0, strlen(stoken)+1, "readtroffmetric: char name"); + (*cp)->next = 0; + strcpy((*cp)->name, stoken); + if (debug) { + if (specharflag) + Bprint(Bstderr, "%s", stoken); + else + Bputrune(Bstderr, troffchar); + Bprint(Bstderr, " %d %d 0x%x %s # psfontid=0x%x pscharid=0x%x thisfont=0x%x thischar=0x%x\n", + width, flag, charnum, str, + (*cp)->postfontid, + (*cp)->postcharid, + thisfont, thischar); + } + } + Bterm(Bfd); + Bflush(Bstderr); + return(1); +} + +/* find index of troff font name in table + * returns -1 if name is not in table + * returns -2 if it cannot allocate memory + * returns -3 if there is a font mapping problem + * If insflg is not zero + * and the name is not found in the table, insert it. + */ +int +findtfn(char *fontname, BOOLEAN insflg) { + struct troffont *tp; + int i, j; + + if (debug) { + if (fontname==0) fprint(2, "findtfn(0x%x,%d)\n", fontname, insflg); + else fprint(2, "findtfn(%s,%d)\n", fontname, insflg); + } + for (i=0; i<troffontcnt; i++) { + if (troffontab[i].trfontid==0) { + error(WARNING, "findtfn:troffontab[%d].trfontid=0x%x, botch!\n", + i, troffontab[i].trfontid); + continue; + } + if (strcmp(troffontab[i].trfontid, fontname) == 0) + return(i); + } + if (insflg) { + tp = (struct troffont *)galloc(troffontab, sizeof(struct troffont)*(troffontcnt+1), "findtfn: struct troffont:"); + if (tp == 0) + return(-2); + troffontab = tp; + tp = &(troffontab[troffontcnt]); + i = strlen(fontname); + tp->trfontid = galloc(0, i+1, "findtfn: trfontid:"); + + /* initialize new troff font entry with name and numeric fields to 0 */ + strncpy(tp->trfontid, fontname, i); + tp->trfontid[i] = '\0'; + tp->special = FALSE; + tp->spacewidth = 0; + tp->psfmapsize = 0; + tp->psfmap = 0; + for (i=0; i<NUMOFONTS; i++) + for (j=0; j<FONTSIZE; j++) + tp->charent[i][j] = 0; + troffontcnt++; + if (!readtroffmetric(fontname, troffontcnt-1)) + return(-3); + if (!readpsfontdesc(fontname, troffontcnt-1)) + return(-3); + return(troffontcnt-1); + } + return(-1); +} + +void +finish(void) { + int i; + + Bprint(Bstdout, "%s", TRAILER); + Bprint(Bstdout, "done\n"); + Bprint(Bstdout, "%s", DOCUMENTFONTS); + + for (i=0; i<pfnamcnt; i++) + if (pfnafontmtab[i].used) + Bprint(Bstdout, " %s", pfnafontmtab[i].str); + Bprint(Bstdout, "\n"); + + Bprint(Bstdout, "%s %d\n", PAGES, pages_printed); + +} + +/* Set slant to n degrees. Disable slanting if n is 0. */ +void +t_slant(int n) { + fontslant = n; + curpostfontid = -1; +} + +/* Set character height to n points. Disabled if n is 0 or the current size. */ + +void +t_charht(int n) { + fontheight = (n == fontsize) ? 0 : n; + curpostfontid = -1; +} diff --git a/sys/src/cmd/postscript/tr2post/conv.c b/sys/src/cmd/postscript/tr2post/conv.c new file mode 100755 index 000000000..ebc1f43d1 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/conv.c @@ -0,0 +1,100 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include "../common/common.h" +#include "tr2post.h" + +void +conv(Biobufhdr *Bp) { + long c, n; + int r; + char special[10]; + int save; + + inputlineno = 1; + if (debug) Bprint(Bstderr, "conv(Biobufhdr *Bp=0x%x)\n", Bp); + while ((r = Bgetrune(Bp)) >= 0) { +/* Bprint(Bstderr, "r=<%c>,0x%x\n", r, r); */ +/* Bflush(Bstderr); */ + switch (r) { + case 's': /* set point size */ + Bgetfield(Bp, 'd', &fontsize, 0); + break; + case 'f': /* set font to postion */ + Bgetfield(Bp, 'd', &fontpos, 0); + save = inputlineno; + settrfont(); + inputlineno = save; /* ugh */ + break; + case 'c': /* print rune */ + r = Bgetrune(Bp); + runeout(r); + break; + case 'C': /* print special character */ + Bgetfield(Bp, 's', special, 10); + specialout(special); + break; + case 'N': /* print character with numeric value from current font */ + Bgetfield(Bp, 'd', &n, 0); + break; + case 'H': /* go to absolute horizontal position */ + Bgetfield(Bp, 'd', &n, 0); + hgoto(n); + break; + case 'V': /* go to absolute vertical position */ + Bgetfield(Bp, 'd', &n, 0); + vgoto(n); + break; + case 'h': /* go to relative horizontal position */ + Bgetfield(Bp, 'd', &n, 0); + hmot(n); + break; + case 'v': /* go to relative vertical position */ + Bgetfield(Bp, 'd', &n, 0); + vmot(n); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* move right nn units, then print character c */ + n = (r - '0') * 10; + r = Bgetrune(Bp); + if (r < 0) + error(FATAL, "EOF or error reading input\n"); + else if (r < '0' || r > '9') + error(FATAL, "integer expected\n"); + n += r - '0'; + r = Bgetrune(Bp); + hmot(n); + runeout(r); + break; + case 'p': /* begin page */ + Bgetfield(Bp, 'd', &n, 0); + endpage(); + startpage(); + break; + case 'n': /* end of line (information only 'b a' follows) */ + Brdline(Bp, '\n'); /* toss rest of line */ + inputlineno++; + break; + case 'w': /* paddable word space (information only) */ + break; + case 'D': /* graphics function */ + draw(Bp); + break; + case 'x': /* device control functions */ + devcntl(Bp); + break; + case '#': /* comment */ + Brdline(Bp, '\n'); /* toss rest of line */ + case '\n': + inputlineno++; + break; + default: + error(WARNING, "unknown troff function <%c>\n", r); + break; + } + } + endpage(); + if (debug) Bprint(Bstderr, "r=0x%x\n", r); + if (debug) Bprint(Bstderr, "leaving conv\n"); +} diff --git a/sys/src/cmd/postscript/tr2post/devcntl.c b/sys/src/cmd/postscript/tr2post/devcntl.c new file mode 100755 index 000000000..2566229e8 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/devcntl.c @@ -0,0 +1,178 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <stdio.h> +#include "../common/common.h" +#include "tr2post.h" + +char devname[20] = { 'u', 't', 'f', '\0' }; +int resolution; +int minx, miny; + +struct sjt { + char *str; + void (*func)(void *); +}; + +/* I won't need this if getfields can replace sscanf + +extern void picture(Biobufhdr *); +extern void notavail(char *); + +void +PSInclude(Biobufhdr *inp) { + char buf[256]; + + Bgetfield(inp, 's', buf, 256); + if(pageon()) { + endstring(); + Bprint(Bstdout, "%s\n", buf); + } +} + +struct sjt specialjumptable[] = { + {"PI", picture}, + {"PictureInclusion", picture}, + {"InlinePicture", NULL}, + {"BeginPath", NULL}, + {"DrawPath", NULL}, + {"BeginObject", NULL}, + {"EndObject", NULL}, + {"NewBaseline", NULL}, + {"DrawText", NULL}, + {"SetText", NULL}, + {"SetColor", NULL}, + {"INFO", NULL}, + {"PS", PSInclude}, + {"Postscript", PSInclude}, + {"ExportPS", notavail("ExportPS")}, + {NULL, NULL} +}; +*/ + +void +devcntl(Biobufhdr *inp) { + + char cmd[50], buf[256], str[MAXTOKENSIZE], *line; + int c, n, linelen; + +/* + * + * Interpret device control commands, ignoring any we don't recognize. The + * "x X ..." commands are a device dependent collection generated by troff's + * \X'...' request. + * + */ + + Bgetfield(inp, 's', cmd, 50); + if (debug) Bprint(Bstderr, "devcntl(cmd=%s)\n", cmd); + switch (cmd[0]) { + case 'f': /* mount font in a position */ + Bgetfield(inp, 'd', &n, 0); + Bgetfield(inp, 's', str, 100); + mountfont(n, str); + break; + + case 'i': /* initialize */ + initialize(); + break; + + case 'p': /* pause */ + break; + + case 'r': /* resolution assumed when prepared */ + Bgetfield(inp, 'd', &resolution, 0); + Bgetfield(inp, 'd', &minx, 0); + Bgetfield(inp, 'd', &miny, 0); + break; + + case 's': /* stop */ + case 't': /* trailer */ + /* flushtext(); */ + break; + + case 'H': /* char height */ + Bgetfield(inp, 'd', &n, 0); + t_charht(n); + break; + + case 'S': /* slant */ + Bgetfield(inp, 'd', &n, 0); + t_slant(n); + break; + + case 'T': /* device name */ + Bgetfield(inp, 's', &devname, 16); + if (debug) Bprint(Bstderr, "devname=%s\n", devname); + break; + + case 'E': /* input encoding - not in troff yet */ + Bgetfield(inp, 's', &str, 100); +/* if ( strcmp(str, "UTF") == 0 ) + reading = UTFENCODING; + else reading = ONEBYTE; + */ + break; + + case 'X': /* copy through - from troff */ + if (Bgetfield(inp, 's', str, MAXTOKENSIZE-1) <= 0) + error(FATAL, "incomplete devcntl line\n"); + if ((line = Brdline(inp, '\n')) == 0) + error(FATAL, "incomplete devcntl line\n"); + strncpy(buf, line, Blinelen(inp)-1); + buf[Blinelen(inp)-1] = '\0'; + Bungetc(inp); + + if (strncmp(str, "PI", sizeof("PI")-1) == 0 || strncmp(str, "PictureInclusion", sizeof("PictureInclusion")-1) == 0) { + picture(inp, str); + } else if (strncmp(str, "InlinePicture", sizeof("InlinePicture")-1) == 0) { + error(FATAL, "InlinePicture not implemented yet.\n"); +/* inlinepic(inp, buf); */ + } else if (strncmp(str, "BeginPath", sizeof("BeginPath")-1) == 0) { + beginpath(buf, FALSE); + } else if (strncmp(str, "DrawPath", sizeof("DrawPath")-1) == 0) { + drawpath(buf, FALSE); + } else if (strncmp(str, "BeginObject", sizeof("BeginObject")-1) == 0) { + beginpath(buf, TRUE); + } else if (strncmp(str, "EndObject", sizeof("EndObject")-1) == 0) { + drawpath(buf, TRUE); + } else if (strncmp(str, "NewBaseline", sizeof("NewBaseline")-1) == 0) { + error(FATAL, "NewBaseline not implemented yet.\n"); +/* newbaseline(buf); */ + } else if (strncmp(str, "DrawText", sizeof("DrawText")-1) == 0) { + error(FATAL, "DrawText not implemented yet.\n"); +/* drawtext(buf); */ + } else if (strncmp(str, "SetText", sizeof("SetText")-1) == 0) { + error(FATAL, "SetText not implemented yet.\n"); +/* settext(buf); */ + } else if (strncmp(str, "SetColor", sizeof("SetColor")-1) == 0) { + error(FATAL, "SetColor not implemented yet.\n"); +/* newcolor(buf); */ +/* setcolor(); */ + } else if (strncmp(str, "INFO", sizeof("INFO")-1) == 0) { + error(FATAL, "INFO not implemented yet.\n"); +/* flushtext(); */ +/* Bprint(outp, "%%INFO%s", buf); */ + } else if (strncmp(str, "PS", sizeof("PS")-1) == 0 || strncmp(str, "PostScript", sizeof("PostScript")-1) == 0) { + if(pageon()) { + endstring(); + Bprint(Bstdout, "%s\n", buf); + } + } else if (strncmp(str, "ExportPS", sizeof("ExportPS")-1) == 0) { /* dangerous!! */ + error(FATAL, "ExportPS not implemented yet.\n"); +/* if (Bfildes(outp) == 1) { */ +/* restore(); */ +/* Bprint(outp, "%s", buf); */ +/* save(); */ +/* } */ + } +/* else + error(WARNING, "Unknown string <%s %s> after x X\n", str, buf); +*/ + + break; + } + while ((c = Bgetc(inp)) != '\n' && c != Beof); + inputlineno++; +} + diff --git a/sys/src/cmd/postscript/tr2post/draw.c b/sys/src/cmd/postscript/tr2post/draw.c new file mode 100755 index 000000000..0cb368ae4 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/draw.c @@ -0,0 +1,342 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include "../common/common.h" +#include "tr2post.h" + +BOOLEAN drawflag = FALSE; +BOOLEAN inpath = FALSE; /* TRUE if we're putting pieces together */ + +void +cover(double x, double y) { +} + +void +drawspline(Biobufhdr *Bp, int flag) { /* flag!=1 connect end points */ + int x[100], y[100]; + int i, N; +/* + * + * Spline drawing routine for Postscript printers. The complicated stuff is + * handled by procedure Ds, which should be defined in the library file. I've + * seen wrong implementations of troff's spline drawing, so fo the record I'll + * write down the parametric equations and the necessary conversions to Bezier + * cubic splines (as used in Postscript). + * + * + * Parametric equation (x coordinate only): + * + * + * (x2 - 2 * x1 + x0) 2 (x0 + x1) + * x = ------------------ * t + (x1 - x0) * t + --------- + * 2 2 + * + * + * The coefficients in the Bezier cubic are, + * + * + * A = 0 + * B = (x2 - 2 * x1 + x0) / 2 + * C = x1 - x0 + * + * + * while the current point is, + * + * current-point = (x0 + x1) / 2 + * + * Using the relationships given in the Postscript manual (page 121) it's easy to + * see that the control points are given by, + * + * + * x0' = (x0 + 5 * x1) / 6 + * x1' = (x2 + 5 * x1) / 6 + * x2' = (x1 + x2) / 2 + * + * + * where the primed variables are the ones used by curveto. The calculations + * shown above are done in procedure Ds using the coordinates set up in both + * the x[] and y[] arrays. + * + * A simple test of whether your spline drawing is correct would be to use cip + * to draw a spline and some tangent lines at appropriate points and then print + * the file. + * + */ + + for (N=2; N<sizeof(x)/sizeof(x[0]); N++) + if (Bgetfield(Bp, 'd', &x[N], 0)<=0 || Bgetfield(Bp, 'd', &y[N], 0)<=0) + break; + + x[0] = x[1] = hpos; + y[0] = y[1] = vpos; + + for (i = 1; i < N; i++) { + x[i+1] += x[i]; + y[i+1] += y[i]; + } + + x[N] = x[N-1]; + y[N] = y[N-1]; + + for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) { + endstring(); + if (pageon()) + Bprint(Bstdout, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]); +/* if (dobbox == TRUE) { /* could be better */ +/* cover((double)(x[i] + x[i+1])/2,(double)-(y[i] + y[i+1])/2); +/* cover((double)x[i+1], (double)-y[i+1]); +/* cover((double)(x[i+1] + x[i+2])/2, (double)-(y[i+1] + y[i+2])/2); +/* } + */ + } + + hpos = x[N]; /* where troff expects to be */ + vpos = y[N]; +} + +void +draw(Biobufhdr *Bp) { + + int r, x1, y1, x2, y2, i; + int d1, d2; + + drawflag = TRUE; + r = Bgetrune(Bp); + switch(r) { + case 'l': + if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'r', &i, 0)<=0) + error(FATAL, "draw line function, destination coordinates not found.\n"); + + endstring(); + if (pageon()) + Bprint(Bstdout, "%d %d %d %d Dl\n", hpos, vpos, hpos+x1, vpos+y1); + hpos += x1; + vpos += y1; + break; + case 'c': + if (Bgetfield(Bp, 'd', &d1, 0)<=0) + error(FATAL, "draw circle function, diameter coordinates not found.\n"); + + endstring(); + if (pageon()) + Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d1); + hpos += d1; + break; + case 'e': + if (Bgetfield(Bp, 'd', &d1, 0)<=0 || Bgetfield(Bp, 'd', &d2, 0)<=0) + error(FATAL, "draw ellipse function, diameter coordinates not found.\n"); + + endstring(); + if (pageon()) + Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d2); + hpos += d1; + break; + case 'a': + if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'd', &x2, 0)<=0 || Bgetfield(Bp, 'd', &y2, 0)<=0) + error(FATAL, "draw arc function, coordinates not found.\n"); + + endstring(); + if (pageon()) + Bprint(Bstdout, "%d %d %d %d %d %d Da\n", hpos, vpos, x1, y1, x2, y2); + hpos += x1 + x2; + vpos += y1 + y2; + break; + case 'q': + drawspline(Bp, 1); + break; + case '~': + drawspline(Bp, 2); + break; + default: + error(FATAL, "unknown draw function <%c>\n", r); + break; + } +} + +void +beginpath(char *buf, int copy) { + +/* + * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used + * to mark the start of a sequence of drawing commands that should be grouped + * together and treated as a single path. By default the drawing procedures in + * *drawfile treat each drawing command as a separate object, and usually start + * with a newpath (just as a precaution) and end with a stroke. The newpath and + * stroke isolate individual drawing commands and make it impossible to deal with + * composite objects. "x X BeginPath" can be used to mark the start of drawing + * commands that should be grouped together and treated as a single object, and + * part of what's done here ensures that the PostScript drawing commands defined + * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath" + * command. At that point the path that's been built up can be manipulated in + * various ways (eg. filled and/or stroked with a different line width). + * + * Color selection is one of the options that's available in parsebuf(), + * so if we get here we add *colorfile to the output file before doing + * anything important. + * + */ + if (inpath == FALSE) { + endstring(); + /* getdraw(); */ + /* getcolor(); */ + Bprint(Bstdout, "gsave\n"); + Bprint(Bstdout, "newpath\n"); + Bprint(Bstdout, "%d %d m\n", hpos, vpos); + Bprint(Bstdout, "/inpath true def\n"); + if ( copy == TRUE ) + Bprint(Bstdout, "%s\n", buf); + inpath = TRUE; + } +} + +static void parsebuf(char*); + +void +drawpath(char *buf, int copy) { + +/* + * + * Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the + * end of the path started by the last "x X BeginPath" command and uses whatever + * has been passed along in *buf to manipulate the path (eg. fill and/or stroke + * the path). Once that's been done the drawing procedures are restored to their + * default behavior in which each drawing command is treated as an isolated path. + * The new version (called after "x X DrawPath") has copy set to FALSE, and calls + * parsebuf() to figure out what goes in the output file. It's a feeble attempt + * to free users and preprocessors (like pic) from having to know PostScript. The + * comments in parsebuf() describe what's handled. + * + * In the early version a path was started with "x X BeginObject" and ended with + * "x X EndObject". In both cases *buf was just copied to the output file, and + * was expected to be legitimate PostScript that manipulated the current path. + * The old escape sequence will be supported for a while (for Ravi), and always + * call this routine with copy set to TRUE. + * + * + */ + + if ( inpath == TRUE ) { + if ( copy == TRUE ) + Bprint(Bstdout, "%s\n", buf); + else + parsebuf(buf); + Bprint(Bstdout, "grestore\n"); + Bprint(Bstdout, "/inpath false def\n"); +/* reset(); */ + inpath = FALSE; + } +} + + +/*****************************************************************************/ + +static void +parsebuf(char *buf) +{ + char *p; /* usually the next token */ + char *q; + int gsavelevel = 0; /* non-zero if we've done a gsave */ + +/* + * + * Simple minded attempt at parsing the string that followed an "x X DrawPath" + * command. Everything not recognized here is simply ignored - there's absolutely + * no error checking and what was originally in buf is clobbered by strtok(). + * A typical *buf might look like, + * + * gray .9 fill stroke + * + * to fill the current path with a gray level of .9 and follow that by stroking the + * outline of the path. Since unrecognized tokens are ignored the last example + * could also be written as, + * + * with gray .9 fill then stroke + * + * The "with" and "then" strings aren't recognized tokens and are simply discarded. + * The "stroke", "fill", and "wfill" force out appropriate PostScript code and are + * followed by a grestore. In otherwords changes to the grahics state (eg. a gray + * level or color) are reset to default values immediately after the stroke, fill, + * or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and + * "wfill" calls fill (ie. the operator that uses the non-zero winding rule). + * + * The tokens that cause temporary changes to the graphics state are "gray" (for + * setting the gray level), "color" (for selecting a known color from the colordict + * dictionary defined in *colorfile), and "line" (for setting the line width). All + * three tokens can be extended since strncmp() makes the comparison. For example + * the strings "line" and "linewidth" accomplish the same thing. Colors are named + * (eg. "red"), but must be appropriately defined in *colorfile. For now all three + * tokens must be followed immediately by their single argument. The gray level + * (ie. the argument that follows "gray") should be a number between 0 and 1, with + * 0 for black and 1 for white. + * + * To pass straight PostScript through enclose the appropriate commands in double + * quotes. Straight PostScript is only bracketed by the outermost gsave/grestore + * pair (ie. the one from the initial "x X BeginPath") although that's probably + * a mistake. Suspect I may have to change the double quote delimiters. + * + */ + + for( ; p != nil ; p = q ) { + if( q = strchr(p, ' ') ) { + *q++ = '\0'; + } + + if ( gsavelevel == 0 ) { + Bprint(Bstdout, "gsave\n"); + gsavelevel++; + } + if ( strcmp(p, "stroke") == 0 ) { + Bprint(Bstdout, "closepath stroke\ngrestore\n"); + gsavelevel--; + } else if ( strcmp(p, "openstroke") == 0 ) { + Bprint(Bstdout, "stroke\ngrestore\n"); + gsavelevel--; + } else if ( strcmp(p, "fill") == 0 ) { + Bprint(Bstdout, "eofill\ngrestore\n"); + gsavelevel--; + } else if ( strcmp(p, "wfill") == 0 ) { + Bprint(Bstdout, "fill\ngrestore\n"); + gsavelevel--; + } else if ( strcmp(p, "sfill") == 0 ) { + Bprint(Bstdout, "eofill\ngrestore\ngsave\nstroke\ngrestore\n"); + gsavelevel--; + } else if ( strncmp(p, "gray", strlen("gray")) == 0 ) { + if( q ) { + p = q; + if ( q = strchr(p, ' ') ) + *q++ = '\0'; + Bprint(Bstdout, "%s setgray\n", p); + } + } else if ( strncmp(p, "color", strlen("color")) == 0 ) { + if( q ) { + p = q; + if ( q = strchr(p, ' ') ) + *q++ = '\0'; + Bprint(Bstdout, "/%s setcolor\n", p); + } + } else if ( strncmp(p, "line", strlen("line")) == 0 ) { + if( q ) { + p = q; + if ( q = strchr(p, ' ') ) + *q++ = '\0'; + Bprint(Bstdout, "%s resolution mul 2 div setlinewidth\n", p); + } + } else if ( strncmp(p, "reverse", strlen("reverse")) == 0 ) + Bprint(Bstdout, "reversepath\n"); + else if ( *p == '"' ) { + for ( ; gsavelevel > 0; gsavelevel-- ) + Bprint(Bstdout, "grestore\n"); + if ( q != nil ) + *--q = ' '; + if ( (q = strchr(p, '"')) != nil ) { + *q++ = '\0'; + Bprint(Bstdout, "%s\n", p); + } + } + } + + for ( ; gsavelevel > 0; gsavelevel-- ) + Bprint(Bstdout, "grestore\n"); + +} diff --git a/sys/src/cmd/postscript/tr2post/mkfile b/sys/src/cmd/postscript/tr2post/mkfile new file mode 100755 index 000000000..57864bf5d --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/mkfile @@ -0,0 +1,35 @@ +</$objtype/mkfile + +<../config + +COMMONDIR=../common + +TARG=tr2post + +OFILES=tr2post.$O\ + chartab.$O\ + Bgetfield.$O\ + conv.$O\ + utils.$O\ + devcntl.$O\ + draw.$O\ + readDESC.$O\ + ps_include.$O\ + pictures.$O\ + common.$O\ + +HFILES=tr2post.h\ + ps_include.h\ + $COMMONDIR/common.h\ + $COMMONDIR/comments.h\ + $COMMONDIR/path.h\ + $COMMONDIR/ext.h\ + +BIN=$POSTBIN + +</sys/src/cmd/mkone + +CFLAGS=-c -D'PROGRAMVERSION="0.1"' -D'DOROUND=1' -I$COMMONDIR -D'PROGRAMNAME="troff, Plan 9 edition"' + +%.$O: $COMMONDIR/%.c + $CC $CFLAGS $COMMONDIR/$stem.c diff --git a/sys/src/cmd/postscript/tr2post/pictures.c b/sys/src/cmd/postscript/tr2post/pictures.c new file mode 100755 index 000000000..806c22544 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/pictures.c @@ -0,0 +1,295 @@ +/* + * + * PostScript picture inclusion routines. Support for managing in-line pictures + * has been added, and works in combination with the simple picpack pre-processor + * that's supplied with this package. An in-line picture begins with a special + * device control command that looks like, + * + * x X InlinPicture name size + * + * where name is the pathname of the original picture file and size is the number + * of bytes in the picture, which begins immediately on the next line. When dpost + * encounters the InlinePicture device control command inlinepic() is called and + * that routine appends the string name and the integer size to a temporary file + * (fp_pic) and then adds the next size bytes read from the current input file to + * file fp_pic. All in-line pictures are saved in fp_pic and located later using + * the name string and picture file size that separate pictures saved in fp_pic. + * + * When a picture request (ie. an "x X PI" command) is encountered picopen() is + * called and it first looks for the picture file in fp_pic. If it's found there + * the entire picture (ie. size bytes) is copied from fp_pic to a new temp file + * and that temp file is used as the picture file. If there's nothing in fp_pic + * or if the lookup failed the original route is taken. + * + * Support for in-line pictures is an attempt to address requirements, expressed + * by several organizations, of being able to store a document as a single file + * (usually troff input) that can then be sent through dpost and ultimately to + * a PostScript printer. The mechanism may help some users, but the are obvious + * disadvantages to this approach, and the original mechanism is the recommended + * approach! Perhaps the most important problem is that troff output, with in-line + * pictures included, doesn't fit the device independent language accepted by + * important post-processors (like proff) and that means you won't be able to + * reliably preview a packed file on your 5620 (or whatever). + * + */ + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <stdio.h> +#include "ext.h" +#include "common.h" +#include "tr2post.h" +/* PostScript file structuring comments */ +#include "comments.h" +/* general purpose definitions */ +/* #include "gen.h" */ +/* just for TEMPDIR definition */ +#include "path.h" +/* external variable declarations */ +/* #include "ext.h" */ + +Biobuf *bfp_pic = NULL; +Biobufhdr *Bfp_pic; +Biobufhdr *picopen(char *); + +#define MAXGETFIELDS 16 +char *fields[MAXGETFIELDS]; +int nfields; + +extern int devres, hpos, vpos; +extern int picflag; + +/*****************************************************************************/ + +void +picture(Biobufhdr *inp, char *buf) { + int poffset; /* page offset */ + int indent; /* indent */ + int length; /* line length */ + int totrap; /* distance to next trap */ + char name[100]; /* picture file and page string */ + char hwo[40], *p; /* height, width and offset strings */ + char flags[20]; /* miscellaneous stuff */ + int page = 1; /* page number pulled from name[] */ + double frame[4]; /* height, width, y, and x offsets from hwo[] */ + char units; /* scale indicator for frame dimensions */ + int whiteout = 0; /* white out the box? */ + int outline = 0; /* draw a box around the picture? */ + int scaleboth = 0; /* scale both dimensions? */ + double adjx = 0.5; /* left-right adjustment */ + double adjy = 0.5; /* top-bottom adjustment */ + double rot = 0; /* rotation in clockwise degrees */ + Biobufhdr *fp_in; /* for *name */ + int i; /* loop index */ + +/* + * + * Called from devcntrl() after an 'x X PI' command is found. The syntax of that + * command is: + * + * x X PI:args + * + * with args separated by colons and given by: + * + * poffset + * indent + * length + * totrap + * file[(page)] + * height[,width[,yoffset[,xoffset]]] + * [flags] + * + * poffset, indent, length, and totrap are given in machine units. height, width, + * and offset refer to the picture frame in inches, unless they're followed by + * the u scale indicator. flags is a string that provides a little bit of control + * over the placement of the picture in the frame. Rotation of the picture, in + * clockwise degrees, is set by the a flag. If it's not followed by an angle + * the current rotation angle is incremented by 90 degrees, otherwise the angle + * is set by the number that immediately follows the a. + * + */ + + if (!picflag) /* skip it */ + return; + endstring(); + + flags[0] = '\0'; /* just to be safe */ + + nfields = getfields(buf, fields, MAXGETFIELDS, 0, ":\n"); + if (nfields < 6) { + error(WARNING, "too few arguments to specify picture"); + return; + } + poffset = atoi(fields[1]); + indent = atoi(fields[2]); + length = atoi(fields[3]); + totrap = atoi(fields[4]); + strncpy(name, fields[5], sizeof(name)); + strncpy(hwo, fields[6], sizeof(hwo)); + if (nfields >= 6) + strncpy(flags, fields[7], sizeof(flags)); + + nfields = getfields(buf, fields, MAXGETFIELDS, 0, "()"); + if (nfields == 2) { + strncpy(name, fields[0], sizeof(name)); + page = atoi(fields[1]); + } + + if ((fp_in = picopen(name)) == NULL) { + error(WARNING, "can't open picture file %s\n", name); + return; + } + + frame[0] = frame[1] = -1; /* default frame height, width */ + frame[2] = frame[3] = 0; /* and y and x offsets */ + + for (i = 0, p = hwo-1; i < 4 && p != NULL; i++, p = strchr(p, ',')) + if (sscanf(++p, "%lf%c", &frame[i], &units) == 2) + if (units == 'i' || units == ',' || units == '\0') + frame[i] *= devres; + + if (frame[0] <= 0) /* check what we got for height */ + frame[0] = totrap; + + if (frame[1] <= 0) /* and width - check too big?? */ + frame[1] = length - indent; + + frame[3] += poffset + indent; /* real x offset */ + + for (i = 0; flags[i]; i++) + switch (flags[i]) { + case 'c': adjx = adjy = 0.5; break; /* move to the center */ + case 'l': adjx = 0; break; /* left */ + case 'r': adjx = 1; break; /* right */ + case 't': adjy = 1; break; /* top */ + case 'b': adjy = 0; break; /* or bottom justify */ + case 'o': outline = 1; break; /* outline the picture */ + case 'w': whiteout = 1; break; /* white out the box */ + case 's': scaleboth = 1; break; /* scale both dimensions */ + case 'a': if ( sscanf(&flags[i+1], "%lf", &rot) != 1 ) + rot += 90; + } + + /* restore(); */ + endstring(); + Bprint(Bstdout, "cleartomark\n"); + Bprint(Bstdout, "saveobj restore\n"); + + ps_include(fp_in, Bstdout, page, whiteout, outline, scaleboth, + frame[3]+frame[1]/2, -vpos-frame[2]-frame[0]/2, frame[1], frame[0], adjx, adjy, -rot); + /* save(); */ + Bprint(Bstdout, "/saveobj save def\n"); + Bprint(Bstdout, "mark\n"); + Bterm(fp_in); + +} + +/* + * + * Responsible for finding and opening the next picture file. If we've accumulated + * any in-line pictures fp_pic won't be NULL and we'll look there first. If *path + * is found in *fp_pic we create another temp file, open it for update, unlink it, + * copy in the picture, seek back to the start of the new temp file, and return + * the file pointer to the caller. If fp_pic is NULL or the lookup fails we just + * open file *path and return the resulting file pointer to the caller. + * + */ +Biobufhdr * +picopen(char *path) { +/* char name[100]; /* pathnames */ +/* long pos; /* current position */ +/* long total; /* and sizes - from *fp_pic */ + Biobuf *bfp; + Biobufhdr *Bfp; /* and pointer for the new temp file */ + + + if ((bfp = Bopen(path, OREAD)) == 0) + error(FATAL, "can't open %s\n", path); + Bfp = &(bfp->Biobufhdr); + return(Bfp); +#ifdef UNDEF + if (Bfp_pic != NULL) { + Bseek(Bfp_pic, 0L, 0); + while (Bgetfield(Bfp_pic, 's', name, 99)>0 + && Bgetfield(Bfp_pic, 'd', &total, 0)>0) { + pos = Bseek(Bfp_pic, 0L, 1); + if (strcmp(path, name) == 0) { + if (tmpnam(pictmpname) == NULL) + error(FATAL, "can't generate temp file name"); + if ( (bfp = Bopen(pictmpname, ORDWR)) == NULL ) + error(FATAL, "can't open %s", pictmpname); + Bfp = &(bfp->Biobufhdr); + piccopy(Bfp_pic, Bfp, total); + Bseek(Bfp, 0L, 0); + return(Bfp); + } + Bseek(Bfp_pic, total+pos, 0); + } + } + if ((bfp = Bopen(path, OREAD)) == 0) + Bfp = 0; + else + Bfp = &(bfp->Biobufhdr); + return(Bfp); +#endif +} + +/* + * + * Adds an in-line picture file to the end of temporary file *Bfp_pic. All pictures + * grabbed from the input file are saved in the same temp file. Each is preceeded + * by a one line header that includes the original picture file pathname and the + * size of the picture in bytes. The in-line picture file is opened for update, + * left open, and unlinked so it disappears when we do. + * + */ +/* *fp; /* current input file */ +/* *buf; /* whatever followed "x X InlinePicture" */ + +#ifdef UNDEF +void +inlinepic(Biobufhdr *Bfp, char *buf) { + char name[100]; /* picture file pathname */ + long total; /* and size - both from *buf */ + + + if (Bfp_pic == NULL ) { + tmpnam(pictmpname); + if ((bfp_pic = Bopen(pictmpname, ORDWR)) == 0) + error(FATAL, "can't open in-line picture file %s", ipictmpname); + unlink(pictmpname); + } + + if ( sscanf(buf, "%s %ld", name, &total) != 2 ) + error(FATAL, "in-line picture error"); + + fseek(Bfp_pic, 0L, 2); + fprintf(Bfp_pic, "%s %ld\n", name, total); + getc(fp); + fflush(fp_pic); + piccopy(fp, fp_pic, total); + ungetc('\n', fp); + +} +#endif + +/* + * + * Copies total bytes from file fp_in to fp_out. Used to append picture files to + * *fp_pic and then copy them to yet another temporary file immediately before + * they're used (in picture()). + * + */ +/* *fp_in; input */ +/* *fp_out; and output file pointers */ +/* total; number of bytes to be copied */ +void +piccopy(Biobufhdr *Bfp_in, Biobufhdr *Bfp_out, long total) { + long i; + + for (i = 0; i < total; i++) + if (Bputc(Bfp_out, Bgetc(Bfp_in)) < 0) + error(FATAL, "error copying in-line picture file"); + Bflush(Bfp_out); +} diff --git a/sys/src/cmd/postscript/tr2post/ps_include.c b/sys/src/cmd/postscript/tr2post/ps_include.c new file mode 100755 index 000000000..27d020a3a --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/ps_include.c @@ -0,0 +1,191 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <stdio.h> +#include "../common/common.h" +#include "ps_include.h" + +extern int curpostfontid; +extern int curfontsize; + +typedef struct {long start, end;} Section; +static char *buf; + +static +copy(Biobufhdr *fin, Biobufhdr *fout, Section *s) { + int cond; + if (s->end <= s->start) + return; + Bseek(fin, s->start, 0); + while (Bseek(fin, 0L, 1) < s->end && (buf=Brdline(fin, '\n')) != NULL){ + /* + * We have to be careful here, because % can legitimately appear + * in Ascii85 encodings, and must not be elided. + * The goal here is to make any DSC comments impotent without + * actually changing the behavior of the Postscript. + * Since stripping ``comments'' breaks Ascii85, we can instead just + * indent comments a space, which turns DSC comments into non-DSC comments + * and has no effect on binary encodings, which are whitespace-blind. + */ + if(buf[0] == '%') + Bputc(fout, ' '); + Bwrite(fout, buf, Blinelen(fin)); + } +} + +/* + * + * Reads a PostScript file (*fin), and uses structuring comments to locate the + * prologue, trailer, global definitions, and the requested page. After the whole + * file is scanned, the special ps_include PostScript definitions are copied to + * *fout, followed by the prologue, global definitions, the requested page, and + * the trailer. Before returning the initial environment (saved in PS_head) is + * restored. + * + * By default we assume the picture is 8.5 by 11 inches, but the BoundingBox + * comment, if found, takes precedence. + * + */ +/* *fin, *fout; /* input and output files */ +/* page_no; /* physical page number from *fin */ +/* whiteout; /* erase picture area */ +/* outline; /* draw a box around it and */ +/* scaleboth; /* scale both dimensions - if not zero */ +/* cx, cy; /* center of the picture and */ +/* sx, sy; /* its size - in current coordinates */ +/* ax, ay; /* left-right, up-down adjustment */ +/* rot; /* rotation - in clockwise degrees */ + +void +ps_include(Biobufhdr *fin, Biobufhdr *fout, int page_no, int whiteout, + int outline, int scaleboth, double cx, double cy, double sx, double sy, + double ax, double ay, double rot) { + char **strp; + int foundpage = 0; /* found the page when non zero */ + int foundpbox = 0; /* found the page bounding box */ + int nglobal = 0; /* number of global defs so far */ + int maxglobal = 0; /* and the number we've got room for */ + Section prolog, page, trailer; /* prologue, page, and trailer offsets */ + Section *global; /* offsets for all global definitions */ + double llx, lly; /* lower left and */ + double urx, ury; /* upper right corners - default coords */ + double w = whiteout != 0; /* mostly for the var() macro */ + double o = outline != 0; + double s = scaleboth != 0; + int i; /* loop index */ + +#define has(word) (strncmp(buf, word, strlen(word)) == 0) +#define grab(n) ((Section *)(nglobal \ + ? realloc((char *)global, n*sizeof(Section)) \ + : calloc(n, sizeof(Section)))) + + llx = lly = 0; /* default BoundingBox - 8.5x11 inches */ + urx = 72 * 8.5; + ury = 72 * 11.0; + + /* section boundaries and bounding box */ + + prolog.start = prolog.end = 0; + page.start = page.end = 0; + trailer.start = 0; + Bseek(fin, 0L, 0); + + while ((buf=Brdline(fin, '\n')) != NULL) { + buf[Blinelen(fin)-1] = '\0'; + if (!has("%%")) + continue; + else if (has("%%Page: ")) { + if (!foundpage) + page.start = Bseek(fin, 0L, 1); + sscanf(buf, "%*s %*s %d", &i); + if (i == page_no) + foundpage = 1; + else if (foundpage && page.end <= page.start) + page.end = Bseek(fin, 0L, 1); + } else if (has("%%EndPage: ")) { + sscanf(buf, "%*s %*s %d", &i); + if (i == page_no) { + foundpage = 1; + page.end = Bseek(fin, 0L, 1); + } + if (!foundpage) + page.start = Bseek(fin, 0L, 1); + } else if (has("%%PageBoundingBox: ")) { + if (i == page_no) { + foundpbox = 1; + sscanf(buf, "%*s %lf %lf %lf %lf", + &llx, &lly, &urx, &ury); + } + } else if (has("%%BoundingBox: ")) { + if (!foundpbox) + sscanf(buf,"%*s %lf %lf %lf %lf", + &llx, &lly, &urx, &ury); + } else if (has("%%EndProlog") || has("%%EndSetup") || has("%%EndDocumentSetup")) + prolog.end = page.start = Bseek(fin, 0L, 1); + else if (has("%%Trailer")) + trailer.start = Bseek(fin, 0L, 1); + else if (has("%%BeginGlobal")) { + if (page.end <= page.start) { + if (nglobal >= maxglobal) { + maxglobal += 20; + global = grab(maxglobal); + } + global[nglobal].start = Bseek(fin, 0L, 1); + } + } else if (has("%%EndGlobal")) + if (page.end <= page.start) + global[nglobal++].end = Bseek(fin, 0L, 1); + } + Bseek(fin, 0L, 2); + if (trailer.start == 0) + trailer.start = Bseek(fin, 0L, 1); + trailer.end = Bseek(fin, 0L, 1); + + if (page.end <= page.start) + page.end = trailer.start; + +/* +fprint(2, "prolog=(%d,%d)\n", prolog.start, prolog.end); +fprint(2, "page=(%d,%d)\n", page.start, page.end); +for(i = 0; i < nglobal; i++) + fprint(2, "global[%d]=(%d,%d)\n", i, global[i].start, global[i].end); +fprint(2, "trailer=(%d,%d)\n", trailer.start, trailer.end); +*/ + + /* all output here */ + for (strp = PS_head; *strp != NULL; strp++) + Bwrite(fout, *strp, strlen(*strp)); + + Bprint(fout, "/llx %g def\n", llx); + Bprint(fout, "/lly %g def\n", lly); + Bprint(fout, "/urx %g def\n", urx); + Bprint(fout, "/ury %g def\n", ury); + Bprint(fout, "/w %g def\n", w); + Bprint(fout, "/o %g def\n", o); + Bprint(fout, "/s %g def\n", s); + Bprint(fout, "/cx %g def\n", cx); + Bprint(fout, "/cy %g def\n", cy); + Bprint(fout, "/sx %g def\n", sx); + Bprint(fout, "/sy %g def\n", sy); + Bprint(fout, "/ax %g def\n", ax); + Bprint(fout, "/ay %g def\n", ay); + Bprint(fout, "/rot %g def\n", rot); + + for (strp = PS_setup; *strp != NULL; strp++) + Bwrite(fout, *strp, strlen(*strp)); + + copy(fin, fout, &prolog); + for(i = 0; i < nglobal; i++) + copy(fin, fout, &global[i]); + copy(fin, fout, &page); + copy(fin, fout, &trailer); + for (strp = PS_tail; *strp != NULL; strp++) + Bwrite(fout, *strp, strlen(*strp)); + + if(nglobal) + free(global); + + /* force the program to reestablish its state */ + curpostfontid = -1; + curfontsize = -1; +} diff --git a/sys/src/cmd/postscript/tr2post/ps_include.h b/sys/src/cmd/postscript/tr2post/ps_include.h new file mode 100755 index 000000000..cef490508 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/ps_include.h @@ -0,0 +1,66 @@ +static char *PS_head[] = { + "%ps_include: begin\n", + "save\n", + "/ed {exch def} def\n", + "{} /showpage ed\n", + "{} /copypage ed\n", + "{} /erasepage ed\n", + "{} /letter ed\n", + "currentdict /findfont known systemdict /findfont known and {\n", + " /findfont systemdict /findfont get def\n", + "} if\n", + "36 dict dup /PS-include-dict-dw ed begin\n", + "/context ed\n", + "count array astore /o-stack ed\n", + "%ps_include: variables begin\n", + 0 +}; + +static char *PS_setup[] = { + "%ps_include: variables end\n", + "{llx lly urx ury} /bbox ed\n", + "{newpath 2 index exch 2 index exch dup 6 index exch\n", + " moveto 3 {lineto} repeat closepath} /boxpath ed\n", + "{dup mul exch dup mul add sqrt} /len ed\n", + "{2 copy gt {exch} if pop} /min ed\n", + "{2 copy lt {exch} if pop} /max ed\n", + "{transform round exch round exch A itransform} /nice ed\n", + "{6 array} /n ed\n", + "n defaultmatrix n currentmatrix n invertmatrix n concatmatrix /A ed\n", + "urx llx sub 0 A dtransform len /Sx ed\n", + "0 ury lly sub A dtransform len /Sy ed\n", + "llx urx add 2 div lly ury add 2 div A transform /Cy ed /Cx ed\n", + "rot dup sin abs /S ed cos abs /C ed\n", + "Sx S mul Sy C mul add /H ed\n", + "Sx C mul Sy S mul add /W ed\n", + "sy H div /Scaley ed\n", + "sx W div /Scalex ed\n", + "s 0 eq {Scalex Scaley min dup /Scalex ed /Scaley ed} if\n", + "sx Scalex W mul sub 0 max ax 0.5 sub mul cx add /cx ed\n", + "sy Scaley H mul sub 0 max ay 0.5 sub mul cy add /cy ed\n", + "urx llx sub 0 A dtransform exch atan rot exch sub /rot ed\n", + "n currentmatrix initgraphics setmatrix\n", + "cx cy translate\n", + "Scalex Scaley scale\n", + "rot rotate\n", + "Cx neg Cy neg translate\n", + "A concat\n", + "bbox boxpath clip newpath\n", + "w 0 ne {gsave bbox boxpath 1 setgray fill grestore} if\n", + "end\n", + "gsave\n", + "%ps_include: inclusion begin\n", + 0 +}; + +static char *PS_tail[] = { + "%ps_include: inclusion end\n", + "grestore\n", + "PS-include-dict-dw begin\n", + "o 0 ne {gsave A defaultmatrix /A ed llx lly nice urx ury nice\n", + " initgraphics 0.1 setlinewidth boxpath stroke grestore} if\n", + "clear o-stack aload pop\n", + "context end restore\n", + "%ps_include: end\n", + 0 +}; diff --git a/sys/src/cmd/postscript/tr2post/readDESC.c b/sys/src/cmd/postscript/tr2post/readDESC.c new file mode 100755 index 000000000..473470d38 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/readDESC.c @@ -0,0 +1,139 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include "common.h" +#include "tr2post.h" +#include "comments.h" +#include "path.h" + +char *printdesclang = 0; +char *encoding = 0; +int devres; +int unitwidth; +int nspechars = 0; +struct charent spechars[MAXSPECHARS]; + +#define NDESCTOKS 9 +static char *desctoks[NDESCTOKS] = { + "PDL", + "Encoding", + "fonts", + "sizes", + "res", + "hor", + "vert", + "unitwidth", + "charset" +}; + +char *spechar[MAXSPECHARS]; + +int +hash(char *s, int l) { + unsigned i; + + for (i=0; *s; s++) + i = i*10 + *s; + return(i % l); +} + +BOOLEAN +readDESC(void) { + char token[MAXTOKENSIZE]; + char *descnameformat = "%s/dev%s/DESC"; + char *descfilename = 0; + Biobuf *bfd; + Biobufhdr *Bfd; + int i, state = -1; + int fontindex = 0; + + if (debug) Bprint(Bstderr, "readDESC()\n"); + descfilename = galloc(descfilename, strlen(descnameformat)+strlen(FONTDIR) + +strlen(devname), "readdesc"); + sprint(descfilename, descnameformat, FONTDIR, devname); + if ((bfd = Bopen(descfilename, OREAD)) == 0) { + error(WARNING, "cannot open file %s\n", descfilename); + return(0); + } + Bfd = &(bfd->Biobufhdr); + + while (Bgetfield(Bfd, 's', token, MAXTOKENSIZE) > 0) { + for (i=0; i<NDESCTOKS; i++) { + if (strcmp(desctoks[i], token) == 0) { + state = i; + break; + } + } + if (i<NDESCTOKS) continue; + switch (state) { + case 0: + printdesclang=galloc(printdesclang, strlen(token)+1, "readdesc:"); + strcpy(printdesclang, token); + if (debug) Bprint(Bstderr, "PDL %s\n", token); + break; + case 1: + encoding=galloc(encoding, strlen(token)+1, "readdesc:"); + strcpy(encoding, token); + if (debug) Bprint(Bstderr, "encoding %s\n", token); + break; + case 2: + if (fontmnt <=0) { + if (!isdigit(*token)) { + error(WARNING, "readdesc: expecting number of fonts in mount table.\n"); + return(FALSE); + } + fontmnt = atoi(token) + 1; + fontmtab = galloc(fontmtab, fontmnt*sizeof(char *), "readdesc:"); + + for (i=0; i<fontmnt; i++) + fontmtab[i] = 0; + fontindex = 0; + } else { + mountfont(++fontindex, token); + findtfn(token, TRUE); + } + break; + case 3: + /* I don't really care about sizes */ + break; + case 4: + /* device resolution in dots per inch */ + if (!isdigit(*token)) { + error(WARNING, "readdesc: expecting device resolution.\n"); + return(FALSE); + } + devres = atoi(token); + if (debug) Bprint(Bstderr, "res %d\n", devres); + break; + case 5: + /* I don't really care about horizontal motion resolution */ + if (debug) Bprint(Bstderr, "ignoring horizontal resolution\n"); + break; + case 6: + /* I don't really care about vertical motion resolution */ + if (debug) Bprint(Bstderr, "ignoring vertical resolution\n"); + break; + case 7: + /* unitwidth is the font size at which the character widths are 1:1 */ + if (!isdigit(*token)) { + error(WARNING, "readdesc: expecting unitwidth.\n"); + return(FALSE); + } + unitwidth = atoi(token); + if (debug) Bprint(Bstderr, "unitwidth %d\n", unitwidth); + break; + case 8: + /* I don't really care about this list of special characters */ + if (debug) Bprint(Bstderr, "ignoring special character <%s>\n", token); + break; + default: + if (*token == '#') + Brdline(Bfd, '\n'); + else + error(WARNING, "unknown token %s in DESC file.\n", token); + break; + } + } + Bterm(Bfd); +} diff --git a/sys/src/cmd/postscript/tr2post/shell.lib b/sys/src/cmd/postscript/tr2post/shell.lib new file mode 100755 index 000000000..d96e65655 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/shell.lib @@ -0,0 +1,1238 @@ +# +# Shell library - for building devutf tables. +# + +RESOLUTION=720 +UNITWIDTH=10 + +OCTALESCAPES=${OCTALESCAPES:-160} # <= code means add \0ddd names +DOWNLOADVECTOR=FALSE # TRUE can mean incomplete tables + +# +# BuiltinTables returns command lines that generate PostScript programs +# for building a typesetter description file and font width tables for +# a relatively standard collection of fonts. Use awk to select a command +# line or modify an existing command to build a width table for a new +# font. +# + +BuiltinTables() { + cat <<-'//End of BuiltinTables' + Proportional R Times-Roman + Proportional I Times-Italic + Proportional B Times-Bold + Proportional BI Times-BoldItalic + Proportional AB AvantGarde-Demi + Proportional AI AvantGarde-BookOblique + Proportional AR AvantGarde-Book + Proportional AX AvantGarde-DemiOblique + Proportional H Helvetica + Proportional HB Helvetica-Bold + Proportional HI Helvetica-Oblique + Proportional HX Helvetica-BoldOblique + Proportional Hb Helvetica-Narrow-Bold + Proportional Hi Helvetica-Narrow-Oblique + Proportional Hr Helvetica-Narrow + Proportional Hx Helvetica-Narrow-BoldOblique + Proportional KB Bookman-Demi + Proportional KI Bookman-LightItalic + Proportional KR Bookman-Light + Proportional KX Bookman-DemiItalic + Proportional NB NewCenturySchlbk-Bold + Proportional NI NewCenturySchlbk-Italic + Proportional NR NewCenturySchlbk-Roman + Proportional NX NewCenturySchlbk-BoldItalic + Proportional PA Palatino-Roman + Proportional PB Palatino-Bold + Proportional PI Palatino-Italic + Proportional PX Palatino-BoldItalic + Proportional ZI ZapfChancery-MediumItalic + FixedWidth C Courier + FixedWidth CB Courier-Bold + FixedWidth CI Courier-Oblique + FixedWidth CO Courier + FixedWidth CW Courier + FixedWidth CX Courier-BoldOblique + Dingbats ZD ZapfDingbats + Greek GR Symbol + Symbol S Symbol + Special S1 Times-Roman + Description DESC --- + //End of BuiltinTables +} + +# +# AllTables prints the complete list of builtin font names. +# + +AllTables() { + BuiltinTables | awk '{print $2}' +} + +# +# Charset functions generate keyword/value pairs (as PostScript objects) +# that describe the character set available in a font. The keyword is a +# PostScript string that represents troff's name for the character. The +# value is usually the literal name (i.e. begins with a /) assigned to +# the character in the PostScript font. The value can also be an integer +# or a PostScript string. An integer value is used as an index in the +# current font's Encoding array. A string value is returned to the host +# unchanged when the entry for the character is constructed. Entries that +# have (") as their value are synonyms for the preceeding character. +# +# The 18 characters missing from ROM resident fonts on older printers are +# flagged with the PostScript comment "% missing". +# + +StandardCharset() { + cat <<-'//End of StandardCharset' + (!) /exclam + (") /quotedbl + (dq) (") % synonym + (#) /numbersign + ($) /dollar + (%) /percent + (&) /ampersand + (') /quoteright + (\() /parenleft + (\)) /parenright + (*) /asterisk + (+) /plus + (,) /comma + (-) /hyphen % changed from minus by request + (.) /period + (/) /slash + (0) /zero + (1) /one + (2) /two + (3) /three + (4) /four + (5) /five + (6) /six + (7) /seven + (8) /eight + (9) /nine + (:) /colon + (;) /semicolon + (<) /less + (=) /equal + (>) /greater + (?) /question + (@) /at + (A) /A + (B) /B + (C) /C + (D) /D + (E) /E + (F) /F + (G) /G + (H) /H + (I) /I + (J) /J + (K) /K + (L) /L + (M) /M + (N) /N + (O) /O + (P) /P + (Q) /Q + (R) /R + (S) /S + (T) /T + (U) /U + (V) /V + (W) /W + (X) /X + (Y) /Y + (Z) /Z + ([) /bracketleft + (\\) /backslash + (bs) (") % synonym + (]) /bracketright + (^) /asciicircum + (_) /underscore + (`) /quoteleft + (a) /a + (b) /b + (c) /c + (d) /d + (e) /e + (f) /f + (g) /g + (h) /h + (i) /i + (j) /j + (k) /k + (l) /l + (m) /m + (n) /n + (o) /o + (p) /p + (q) /q + (r) /r + (s) /s + (t) /t + (u) /u + (v) /v + (w) /w + (x) /x + (y) /y + (z) /z + ({) /braceleft + (|) /bar + (}) /braceright + (~) /asciitilde + (\\`) /grave % devpost character + (ga) (") % synonym + (!!) /exclamdown + (c|) /cent + (ct) (") % devpost synonym + (L-) /sterling + (ps) (") % devpost synonym + (xo) /currency + (cr) (") % devpost synonym + (Y-) /yen + (yn) (") % devpost synonym + (||) /brokenbar % missing + (so) /section + (sc) (") % devpost synonym + ("") /dieresis + (:a) (") % devpost synonym + (co) /copyright + (a_) /ordfeminine + (<<) /guillemotleft + (-,) /logicalnot + (hy) /hyphen + (--) /minus + (ro) /registered + (rg) (") % devpost synonym + (-^) /macron + (-a) (") % devpost synonym + (0^) /degree % missing + (+-) /plusminus % missing + (2^) /twosuperior % missing + (3^) /threesuperior % missing + (\\') /acute + (aa) (") % devpost synonym + (/u) /mu % missing + (P!) /paragraph + (pg) (") % devpost synonym + (.^) /periodcentered + (,,) /cedilla + (,a) (") % devpost synonym + (1^) /onesuperior % missing + (o_) /ordmasculine + (>>) /guillemotright + (14) /onequarter % missing + (12) /onehalf % missing + (34) /threequarters % missing + (??) /questiondown + (A`) /Agrave + (A') /Aacute + (A^) /Acircumflex + (A~) /Atilde + (A") /Adieresis + (A*) /Aring + (AE) /AE + (C,) /Ccedilla + (E`) /Egrave + (E') /Eacute + (E^) /Ecircumflex + (E") /Edieresis + (I`) /Igrave + (I') /Iacute + (I^) /Icircumflex + (I") /Idieresis + (D-) /Eth % missing + (N~) /Ntilde + (O`) /Ograve + (O') /Oacute + (O^) /Ocircumflex + (O~) /Otilde + (O") /Odieresis + (xx) /multiply % missing + (O/) /Oslash + (U`) /Ugrave + (U') /Uacute + (U^) /Ucircumflex + (U") /Udieresis + (Y') /Yacute % missing + (TH) /Thorn % missing + (ss) /germandbls + (a`) /agrave + (a') /aacute + (a^) /acircumflex + (a~) /atilde + (a") /adieresis + (a*) /aring + (ae) /ae + (c,) /ccedilla + (e`) /egrave + (e') /eacute + (e^) /ecircumflex + (e") /edieresis + (i`) /igrave + (i') /iacute + (i^) /icircumflex + (i") /idieresis + (d-) /eth % missing + (n~) /ntilde + (o`) /ograve + (o') /oacute + (o^) /ocircumflex + (o~) /otilde + (o") /odieresis + (-:) /divide % missing + (o/) /oslash + (u`) /ugrave + (u') /uacute + (u^) /ucircumflex + (u") /udieresis + (y') /yacute % missing + (th) /thorn % missing + (y") /ydieresis + (^a) /circumflex % devpost accent + (~a) /tilde % devpost accent + (Ua) /breve % devpost accent + (.a) /dotaccent % devpost accent + (oa) /ring % devpost accent + ("a) /hungarumlaut % devpost accent + (Ca) /ogonek % devpost accent + (va) /caron % devpost accent + //End of StandardCharset +} + +# +# DingbatsCharset guarantees changes in StandardCharset don't show up in ZD. +# + +DingbatsCharset() { + cat <<-'//End of DingbatsCharset' + (!) /exclam + (") /quotedbl + (#) /numbersign + ($) /dollar + (%) /percent + (&) /ampersand + (') /quoteright + (\() /parenleft + (\)) /parenright + (*) /asterisk + (+) /plus + (,) /comma + (-) /minus % also hyphen in devpost + (.) /period + (/) /slash + (0) /zero + (1) /one + (2) /two + (3) /three + (4) /four + (5) /five + (6) /six + (7) /seven + (8) /eight + (9) /nine + (:) /colon + (;) /semicolon + (<) /less + (=) /equal + (>) /greater + (?) /question + (@) /at + (A) /A + (B) /B + (C) /C + (D) /D + (E) /E + (F) /F + (G) /G + (H) /H + (I) /I + (J) /J + (K) /K + (L) /L + (M) /M + (N) /N + (O) /O + (P) /P + (Q) /Q + (R) /R + (S) /S + (T) /T + (U) /U + (V) /V + (W) /W + (X) /X + (Y) /Y + (Z) /Z + ([) /bracketleft + (\\) /backslash + (]) /bracketright + (^) /asciicircum + (_) /underscore + (`) /quoteleft + (a) /a + (b) /b + (c) /c + (d) /d + (e) /e + (f) /f + (g) /g + (h) /h + (i) /i + (j) /j + (k) /k + (l) /l + (m) /m + (n) /n + (o) /o + (p) /p + (q) /q + (r) /r + (s) /s + (t) /t + (u) /u + (v) /v + (w) /w + (x) /x + (y) /y + (z) /z + ({) /braceleft + (|) /bar + (}) /braceright + (~) /asciitilde + (\\`) /grave % devpost character + (!!) /exclamdown + (c|) /cent + (L-) /sterling + (xo) /currency + (Y-) /yen + (||) /brokenbar % missing + (so) /section + ("") /dieresis + (co) /copyright + (a_) /ordfeminine + (<<) /guillemotleft + (-,) /logicalnot + (hy) /hyphen + (ro) /registered + (-^) /macron + (0^) /degree % missing + (+-) /plusminus % missing + (2^) /twosuperior % missing + (3^) /threesuperior % missing + (\\') /acute + (/u) /mu % missing + (P!) /paragraph + (.^) /periodcentered + (,,) /cedilla + (1^) /onesuperior % missing + (o_) /ordmasculine + (>>) /guillemotright + (14) /onequarter % missing + (12) /onehalf % missing + (34) /threequarters % missing + (??) /questiondown + (A`) /Agrave + (A') /Aacute + (A^) /Acircumflex + (A~) /Atilde + (A") /Adieresis + (A*) /Aring + (AE) /AE + (C,) /Ccedilla + (E`) /Egrave + (E') /Eacute + (E^) /Ecircumflex + (E") /Edieresis + (I`) /Igrave + (I') /Iacute + (I^) /Icircumflex + (I") /Idieresis + (D-) /Eth % missing + (N~) /Ntilde + (O`) /Ograve + (O') /Oacute + (O^) /Ocircumflex + (O~) /Otilde + (O") /Odieresis + (xx) /multiply % missing + (O/) /Oslash + (U`) /Ugrave + (U') /Uacute + (U^) /Ucircumflex + (U") /Udieresis + (Y') /Yacute % missing + (TH) /Thorn % missing + (ss) /germandbls + (a`) /agrave + (a') /aacute + (a^) /acircumflex + (a~) /atilde + (a") /adieresis + (a*) /aring + (ae) /ae + (c,) /ccedilla + (e`) /egrave + (e') /eacute + (e^) /ecircumflex + (e") /edieresis + (i`) /igrave + (i') /iacute + (i^) /icircumflex + (i") /idieresis + (d-) /eth % missing + (n~) /ntilde + (o`) /ograve + (o') /oacute + (o^) /ocircumflex + (o~) /otilde + (o") /odieresis + (-:) /divide % missing + (o/) /oslash + (u`) /ugrave + (u') /uacute + (u^) /ucircumflex + (u") /udieresis + (y') /yacute % missing + (th) /thorn % missing + (y") /ydieresis + //End of DingbatsCharset +} + +SymbolCharset() { + cat <<-'//End of SymbolCharset' + (---) /exclam + (fa) /universal + (---) /numbersign + (te) /existential + (---) /percent + (---) /ampersand + (st) /suchthat + (---) /parenleft + (---) /parenright + (**) /asteriskmath + (pl) /plus + (---) /comma + (mi) /minus + (---) /period + (sl) /slash + (---) /zero + (---) /one + (---) /two + (---) /three + (---) /four + (---) /five + (---) /six + (---) /seven + (---) /eight + (---) /nine + (---) /colon + (---) /semicolon + (<) /less + (eq) /equal + (>) /greater + (---) /question + (cg) /congruent + (*A) /Alpha + (\244x) (") + (*B) /Beta + (\244y) (") + (*X) /Chi + (\244\257) (") + (*D) /Delta + (\244{) (") + (*E) /Epsilon + (\244|) (") + (*F) /Phi + (\244\256) (") + (*G) /Gamma + (\244z) (") + (*Y) /Eta + (\244~) (") + (*I) /Iota + (\244\241) (") + (---) /theta1 + (\244\331) (") + (*K) /Kappa + (\244\242) (") + (*L) /Lambda + (\244\243) (") + (*M) /Mu + (\244\244) (") + (*N) /Nu + (\244\245) (") + (*O) /Omicron + (\244\247) (") + (*P) /Pi + (\244\250) (") + (*H) /Theta + (\244\240) (") + (*R) /Rho + (\244\251) (") + (*S) /Sigma + (\244\253) (") + (*T) /Tau + (\244\254) (") + (*U) /Upsilon + (\244\255) (") + (ts) /sigma1 + (\244\312) (") + (*W) /Omega + (\244\261) (") + (*C) /Xi + (\244\246) (") + (*Q) /Psi + (\244\260) (") + (*Z) /Zeta + (\244}) (") + (---) /bracketleft + (tf) /therefore + (---) /bracketright + (pp) /perpendicular + (ul) /underscore + (_) (") % synonym + (rn) /radicalex + (*a) /alpha + (\244\271) (") + (*b) /beta + (\244\272) (") + (*x) /chi + (\244\317) (") + (*d) /delta + (\244\274) (") + (*e) /epsilon + (\244\275) (") + (*f) /phi + (\244\316) (") + (*g) /gamma + (\244\273) (") + (*y) /eta + (\244\277) (") + (*i) /iota + (\244\301) (") + (---) /phi1 + (\244\335) (") + (*k) /kappa + (\244\302) (") + (*l) /lambda + (\244\303) (") + (*m) /mu + (\244\304) (") + (*n) /nu + (\244\305) (") + (*o) /omicron + (\244\307) (") + (*p) /pi + (\244\310) (") + (*h) /theta + (\244\300) (") + (*r) /rho + (\244\311) (") + (*s) /sigma + (\244\313) (") + (*t) /tau + (\244\314) (") + (*u) /upsilon + (\244\315) (") + (---) /omega1 + (\244\336) (") + (*w) /omega + (\244\321) (") + (*c) /xi + (\244\306) (") + (*q) /psi + (\244\320) (") + (*z) /zeta + (\244\276) (") + (---) /braceleft + (or) /bar + (---) /braceright + (ap) /similar + (---) /Upsilon1 + (fm) /minute + (<=) /lessequal + (fr) /fraction % devpost character + (if) /infinity + (fn) /florin % devpost character + (---) /club + (---) /diamond + (---) /heart + (---) /spade + (ab) /arrowboth + (<-) /arrowleft + (ua) /arrowup + (->) /arrowright + (da) /arrowdown + (de) /degree + (+-) /plusminus + (---) /second + (>=) /greaterequal + (mu) /multiply + (pt) /proportional + (pd) /partialdiff + (bu) /bullet + (di) /divide + (!=) /notequal + (==) /equivalence + (~~) /approxequal + (el) /ellipsis + (av) /arrowvertex + (ah) /arrowhorizex + (CR) /carriagereturn + (af) /aleph + (If) /Ifraktur + (Rf) /Rfraktur + (ws) /weierstrass + (Ox) /circlemultiply + (O+) /circleplus + (es) /emptyset + (ca) /intersection + (cu) /union + (sp) /propersuperset + (ip) /reflexsuperset + (!b) /notsubset + (sb) /propersubset + (ib) /reflexsubset + (mo) /element + (!m) /notelement + (an) /angle + (gr) /gradient + (rg) /registerserif + (co) /copyrightserif + (tm) /trademarkserif + (---) /product + (sr) /radical + (c.) /dotmath + (no) /logicalnot + (l&) /logicaland + (l|) /logicalor + (---) /arrowdblboth + (---) /arrowdblleft + (---) /arrowdblup + (---) /arrowdblright + (---) /arrowdbldown + (lz) /lozenge + (b<) /angleleft + (RG) /registersans + (CO) /copyrightsans + (TM) /trademarksans + (---) /summation + (LT) /parenlefttp + (br) /parenleftex + (LX) (") % synonym + (LB) /parenleftbt + (lc) /bracketlefttp + (lx) /bracketleftex + (lf) /bracketleftbt + (lt) /bracelefttp + (lk) /braceleftmid + (lb) /braceleftbt + (bv) /braceex + (|) (") % synonym + (b>) /angleright + (is) /integral + (---) /integraltp + (---) /integralex + (---) /integralbt + (RT) /parenrighttp + (RX) /parenrightex + (RB) /parenrightbt + (rc) /bracketrighttp + (rx) /bracketrightex + (rf) /bracketrightbt + (rt) /bracerighttp + (rk) /bracerightmid + (rb) /bracerightbt + (~=) (55 0 1) % charlib + //End of SymbolCharset +} + +SpecialCharset() { + cat <<-'//End of SpecialCharset' + (ru) /underscore + ('') /quotedblright % devpost character + (``) /quotedblleft % devpost character + (dg) /dagger % devpost character + (dd) /daggerdbl % devpost character + (en) /endash % devpost character + (\\-) (") % synonym + (em) /emdash +% (ff) (60 2 1) % charlib +% (Fi) (84 2 1) % charlib +% (Fl) (84 2 1) % charlib + (14) (75 2 1) % charlib + (12) (75 2 1) % charlib + (34) (75 2 1) % charlib + (bx) (50 2 1) % charlib + (ob) (38 2 1) % charlib + (ci) (75 0 1) % charlib + (sq) (50 2 1) % charlib + (Sl) (50 2 1) % charlib + (L1) (110 1 1) % charlib + (LA) (110 1 1) % charlib + (LV) (110 3 1) % charlib + (LH) (210 1 1) % charlib + (lh) (100 0 1) % charlib + (rh) (100 0 1) % charlib + (lH) (100 0 1) % charlib + (rH) (100 0 1) % charlib + (PC) (220 2 1) % charlib + (DG) (185 2 1) % charlib + //End of SpecialCharset +} + +# +# Latin1 ensures a font uses the ISOLatin1Encoding vector, although only +# text fonts should be re-encoded. Downloading the Encoding vector doesn't +# often make sense. No ISOLatin1Encoding array likely means ROM based fonts +# on your printer are incomplete. Type 1 fonts with a full Latin1 character +# set appeared sometime after Version 50.0. +# + +Latin1() { + if [ "$DOWNLOADVECTOR" = TRUE ]; then + cat <<-'//End of ISOLatin1Encoding' + /ISOLatin1Encoding [ + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /space + /exclam + /quotedbl + /numbersign + /dollar + /percent + /ampersand + /quoteright + /parenleft + /parenright + /asterisk + /plus + /comma + /minus + /period + /slash + /zero + /one + /two + /three + /four + /five + /six + /seven + /eight + /nine + /colon + /semicolon + /less + /equal + /greater + /question + /at + /A + /B + /C + /D + /E + /F + /G + /H + /I + /J + /K + /L + /M + /N + /O + /P + /Q + /R + /S + /T + /U + /V + /W + /X + /Y + /Z + /bracketleft + /backslash + /bracketright + /asciicircum + /underscore + /quoteleft + /a + /b + /c + /d + /e + /f + /g + /h + /i + /j + /k + /l + /m + /n + /o + /p + /q + /r + /s + /t + /u + /v + /w + /x + /y + /z + /braceleft + /bar + /braceright + /asciitilde + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /dotlessi + /grave + /acute + /circumflex + /tilde + /macron + /breve + /dotaccent + /dieresis + /.notdef + /ring + /cedilla + /.notdef + /hungarumlaut + /ogonek + /caron + /space + /exclamdown + /cent + /sterling + /currency + /yen + /brokenbar + /section + /dieresis + /copyright + /ordfeminine + /guillemotleft + /logicalnot + /hyphen + /registered + /macron + /degree + /plusminus + /twosuperior + /threesuperior + /acute + /mu + /paragraph + /periodcentered + /cedilla + /onesuperior + /ordmasculine + /guillemotright + /onequarter + /onehalf + /threequarters + /questiondown + /Agrave + /Aacute + /Acircumflex + /Atilde + /Adieresis + /Aring + /AE + /Ccedilla + /Egrave + /Eacute + /Ecircumflex + /Edieresis + /Igrave + /Iacute + /Icircumflex + /Idieresis + /Eth + /Ntilde + /Ograve + /Oacute + /Ocircumflex + /Otilde + /Odieresis + /multiply + /Oslash + /Ugrave + /Uacute + /Ucircumflex + /Udieresis + /Yacute + /Thorn + /germandbls + /agrave + /aacute + /acircumflex + /atilde + /adieresis + /aring + /ae + /ccedilla + /egrave + /eacute + /ecircumflex + /edieresis + /igrave + /iacute + /icircumflex + /idieresis + /eth + /ntilde + /ograve + /oacute + /ocircumflex + /otilde + /odieresis + /divide + /oslash + /ugrave + /uacute + /ucircumflex + /udieresis + /yacute + /thorn + /ydieresis + ] def + //End of ISOLatin1Encoding + fi + + echo "ISOLatin1Encoding /$1 ReEncode" +} + +# +# Generating functions output PostScript programs that build font width +# tables or a typesetter description file. Send the program to a printer +# and the complete table will come back on the serial port. All write on +# stdout and assume the prologue and other required PostScript files are +# all available. +# + +Proportional() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/octalescapes $OCTALESCAPES def" + echo "/charset [" + # Get <>_ and | from S. Use accents for ascii ^ and ~. + StandardCharset | awk ' + $1 == "(<)" && $2 == "/less" {$1 = "(---)"} + $1 == "(>)" && $2 == "/greater" {$1 = "(---)"} + $1 == "(_)" && $2 == "/underscore" {$1 = "(---)"} + $1 == "(|)" && $2 == "/bar" {$1 = "(---)"} + $1 == "(^)" && $2 == "/asciicircum" { + printf "(^)\t/circumflex\n" + $1 = "(---)" + } + $1 == "(~)" && $2 == "/asciitilde" { + printf "(~)\t/tilde\n" + $1 = "(---)" + } + {printf "%s\t%s\n", $1, $2} + ' + echo "] def" + + Latin1 $2 + echo "/$2 SelectFont" + echo "(opO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(spacewidth ) Print 32 GetWidth Print (\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +FixedWidth() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/octalescapes $OCTALESCAPES def" + echo "/charset [" + StandardCharset + echo "] def" + + Latin1 $2 + echo "/$2 SelectFont" + echo "(opO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(spacewidth ) Print 32 GetWidth Print (\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Dingbats() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/octalescapes $OCTALESCAPES def" + echo "/charset [" + DingbatsCharset | awk '$1 != "(---)" && $2 ~ /^\/[a-zA-Z]/ { + printf "%s\tISOLatin1Encoding %s GetCode\n", $1, $2 + }' + echo "] def" + + echo "/$2 SelectFont" + echo "( ) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Greek() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/charset [" + SymbolCharset | awk ' + BEGIN {hit = -1} + $1 ~ /\(\*[a-zA-Z]\)/ {print; hit = NR} + $2 == "(\")" && hit == NR-1 {print; hit = NR} + ' + echo "] def" + + echo "/$2 SelectFont" + echo "(orO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(spacewidth ) Print 32 GetWidth Print (\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Symbol() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/charset [" + SymbolCharset + echo "] def" + + echo "ChangeMetrics" + echo "/S SelectFont" + echo "(orO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(special\\\\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Special() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/charset [" + SpecialCharset + echo "] def" + + echo "ChangeMetrics" + echo "/S1 SelectFont" + + echo "(# Times-Roman special font\\\\n) Print" + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(special\\\\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +# +# The DESC file doesn't have to be built on a printer. It's only here for +# consistency. +# + +Description() { + echo "/charset [" # awk - so the stack doesn't overflow + StandardCharset | awk '$1 !~ /\(\\[0-9]/ {print $1}' + SymbolCharset | awk '$1 !~ /\(\\[0-9]/ {print $1}' + SpecialCharset | awk '$1 !~ /\(\\[0-9]/ {print $1}' + echo "] def" + + cat <<-//DESC + (#Device Description - utf character set + + PDL PostScript + Encoding Latin1 + + fonts 10 R I B BI CW H HI HB S1 S + sizes 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 40 42 44 46 + 48 50 52 54 56 58 60 64 68 72 78 84 90 96 100 105 110 115 + 120 125 130 135 140 145 150 155 160 0 + res $RESOLUTION + hor 1 + vert 1 + unitwidth $UNITWIDTH + + ) Print + //DESC + echo "(charset\\\\n) Print" + echo "BuildDescCharset" + echo "(\\\\n) Print" +} + diff --git a/sys/src/cmd/postscript/tr2post/tr2post.c b/sys/src/cmd/postscript/tr2post/tr2post.c new file mode 100755 index 000000000..aeb8bbcf2 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/tr2post.c @@ -0,0 +1,219 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <stdio.h> +#include "common.h" +#include "tr2post.h" +#include "comments.h" +#include "path.h" + +int formsperpage = 1; +int picflag = 1; +double aspectratio = 1.0; +int copies = 1; +int landscape = 0; +double magnification = 1.0; +int linesperpage = 66; +int pointsize = 10; +double xoffset = .25; +double yoffset = .25; +char *passthrough = 0; + +Biobuf binp, *bstdout, bstderr; +Biobufhdr *Bstdin, *Bstdout, *Bstderr; +int debug = 0; + +char tmpfilename[MAXTOKENSIZE]; +char copybuf[BUFSIZ]; + + +struct charent **build_char_list = 0; +int build_char_cnt = 0; + +void +prologues(void) { + int i; + char charlibname[MAXTOKENSIZE]; + + Bprint(Bstdout, "%s", CONFORMING); + Bprint(Bstdout, "%s %s\n", VERSION, PROGRAMVERSION); + Bprint(Bstdout, "%s %s\n", CREATOR, PROGRAMNAME); + Bprint(Bstdout, "%s %s\n", DOCUMENTFONTS, ATEND); + Bprint(Bstdout, "%s %s\n", PAGES, ATEND); + Bprint(Bstdout, "%s", ENDCOMMENTS); + + if (cat(DPOST)) { + Bprint(Bstderr, "can't read %s\n", DPOST); + exits("dpost prologue"); + } + + if (drawflag) { + if (cat(DRAW)) { + Bprint(Bstderr, "can't read %s\n", DRAW); + exits("draw prologue"); + } + } + + if (DOROUND) + cat(ROUNDPAGE); + + Bprint(Bstdout, "%s", ENDPROLOG); + Bprint(Bstdout, "%s", BEGINSETUP); + Bprint(Bstdout, "mark\n"); + if (formsperpage > 1) { + Bprint(Bstdout, "%s %d\n", FORMSPERPAGE, formsperpage); + Bprint(Bstdout, "/formsperpage %d def\n", formsperpage); + } + if (aspectratio != 1) Bprint(Bstdout, "/aspectratio %g def\n", aspectratio); + if (copies != 1) Bprint(Bstdout, "/#copies %d store\n", copies); + if (landscape) Bprint(Bstdout, "/landscape true def\n"); + if (magnification != 1) Bprint(Bstdout, "/magnification %g def\n", magnification); + if (pointsize != 10) Bprint(Bstdout, "/pointsize %d def\n", pointsize); + if (xoffset != .25) Bprint(Bstdout, "/xoffset %g def\n", xoffset); + if (yoffset != .25) Bprint(Bstdout, "/yoffset %g def\n", yoffset); + cat(ENCODINGDIR"/Latin1.enc"); + if (passthrough != 0) Bprint(Bstdout, "%s\n", passthrough); + + Bprint(Bstdout, "setup\n"); + if (formsperpage > 1) { + cat(FORMFILE); + Bprint(Bstdout, "%d setupforms \n", formsperpage); + } +/* output Build character info from charlib if necessary. */ + + for (i=0; i<build_char_cnt; i++) { + sprint(charlibname, "%s/%s", CHARLIB, build_char_list[i]->name); + if (cat(charlibname)) + Bprint(Bstderr, "cannot open %s\n", charlibname); + } + + Bprint(Bstdout, "%s", ENDSETUP); +} + +void +cleanup(void) { + remove(tmpfilename); +} + +main(int argc, char *argv[]) { + Biobuf *binp; + Biobufhdr *Binp; + int i, tot, ifd; + char *t; + + programname = argv[0]; + if (Binit(&bstderr, 2, OWRITE) == Beof) { + exits("Binit"); + } + Bstderr = &bstderr.Biobufhdr; + + tmpnam(tmpfilename); + if ((bstdout=Bopen(tmpfilename, OWRITE)) == 0) { + Bprint(Bstderr, "cannot open temporary file %s\n", tmpfilename); + exits("Bopen"); + } + atexit(cleanup); + Bstdout = &bstdout->Biobufhdr; + + ARGBEGIN{ + case 'a': /* aspect ratio */ + aspectratio = atof(ARGF()); + break; + case 'c': /* copies */ + copies = atoi(ARGF()); + break; + case 'd': + debug = 1; + break; + case 'm': /* magnification */ + magnification = atof(ARGF()); + break; + case 'n': /* forms per page */ + formsperpage = atoi(ARGF()); + break; + case 'o': /* output page list */ + pagelist(ARGF()); + break; + case 'p': /* landscape or portrait mode */ + if ( ARGF()[0] == 'l' ) + landscape = 1; + else + landscape = 0; + break; + case 'x': /* shift things horizontally */ + xoffset = atof(ARGF()); + break; + case 'y': /* and vertically on the page */ + yoffset = atof(ARGF()); + break; + case 'P': /* PostScript pass through */ + t = ARGF(); + i = strlen(t) + 1; + passthrough = malloc(i); + if (passthrough == 0) { + Bprint(Bstderr, "cannot allocate memory for argument string\n"); + exits("malloc"); + } + strncpy(passthrough, t, i); + break; + default: /* don't know what to do for ch */ + Bprint(Bstderr, "unknown option %C\n", ARGC()); + break; + }ARGEND; + readDESC(); + if (argc == 0) { + if ((binp = (Biobuf *)malloc(sizeof(Biobuf))) == nil) { + Bprint(Bstderr, "malloc failed.\n"); + exits("malloc"); + } + if (Binit(binp, 0, OREAD) == Beof) { + Bprint(Bstderr, "Binit of <stdin> failed.\n"); + exits("Binit"); + } + Binp = &(binp->Biobufhdr); + if (debug) Bprint(Bstderr, "using standard input\n"); + conv(Binp); + Bterm(Binp); + } + for (i=0; i<argc; i++) { + if ((binp=Bopen(argv[i], OREAD)) == 0) { + Bprint(Bstderr, "cannot open file %s\n", argv[i]); + continue; + } + Binp = &(binp->Biobufhdr); + inputfilename = argv[i]; + conv(Binp); + Bterm(Binp); + } + Bterm(Bstdout); + + if ((ifd=open(tmpfilename, OREAD)) < 0) { + Bprint(Bstderr, "open of %s failed.\n", tmpfilename); + exits("open"); + } + + bstdout = galloc(0, sizeof(Biobuf), "bstdout"); + if (Binit(bstdout, 1, OWRITE) == Beof) { + Bprint(Bstderr, "Binit of <stdout> failed.\n"); + exits("Binit"); + } + Bstdout = &(bstdout->Biobufhdr); + prologues(); + Bflush(Bstdout); + tot = 0; i = 0; + while ((i=read(ifd, copybuf, BUFSIZ)) > 0) { + if (write(1, copybuf, i) != i) { + Bprint(Bstderr, "write error on copying from temp file.\n"); + exits("write"); + } + tot += i; + } + if (debug) Bprint(Bstderr, "copied %d bytes to final output i=%d\n", tot, i); + if (i < 0) { + Bprint(Bstderr, "read error on copying from temp file.\n"); + exits("read"); + } + finish(); + + exits(""); +} diff --git a/sys/src/cmd/postscript/tr2post/tr2post.h b/sys/src/cmd/postscript/tr2post/tr2post.h new file mode 100755 index 000000000..030c6cb7a --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/tr2post.h @@ -0,0 +1,103 @@ +#define MAXSPECHARS 512 +#define MAXTOKENSIZE 128 +#define CHARLIB "/sys/lib/troff/font/devutf/charlib" + +extern int debug; +extern int fontsize; +extern int fontpos; +extern int resolution; /* device resolution, goobies per inch */ +extern int minx; /* minimum x motion */ +extern int miny; /* minimum y motion */ +extern char devname[]; +extern int devres; +extern int unitwidth; +extern char *printdesclang; +extern char *encoding; +extern int fontmnt; +extern char **fontmtab; + +extern int curtrofffontid; /* index into trofftab of current troff font */ +extern int troffontcnt; + +extern BOOLEAN drawflag; + +struct specname { + char *str; + struct specname *next; +}; + +/* character entries for special characters (those pointed + * to by multiple character names, e.g. \(mu for multiply. + */ +struct charent { + char postfontid; /* index into pfnamtab */ + char postcharid; /* e.g., 0x00 */ + short troffcharwidth; + char *name; + struct charent *next; +}; + +extern struct charent **build_char_list; +extern int build_char_cnt; + +struct pfnament { + char *str; + int used; +}; + +/* these entries map troff character code ranges to + * postscript font and character ranges. + */ +struct psfent { + int start; + int end; + int offset; + int psftid; +}; + +struct troffont { + char *trfontid; /* the common troff font name e.g., `R' */ + BOOLEAN special; /* flag says this is a special font. */ + int spacewidth; + int psfmapsize; + struct psfent *psfmap; + struct charent *charent[NUMOFONTS][FONTSIZE]; +}; + +extern struct troffont *troffontab; +extern struct charent spechars[]; + +/** prototypes **/ +void initialize(void); +void mountfont(int, char*); +int findtfn(char *, int); +void runeout(Rune); +void specialout(char *); +long nametorune(char *); +void conv(Biobufhdr *); +void hgoto(int); +void vgoto(int); +void hmot(int); +void vmot(int); +void draw(Biobufhdr *); +void devcntl(Biobufhdr *); +void notavail(char *); +void error(int, char *, ...); +void loadfont(int, char *); +void flushtext(void); +void t_charht(int); +void t_slant(int); +void startstring(void); +void endstring(void); +BOOLEAN pageon(void); +void setpsfont(int, int); +void settrfont(void); +int hash(char *, int); +BOOLEAN readDESC(void); +void finish(void); +void ps_include(Biobufhdr *, Biobufhdr *, int, int, + int, int, double, double, double, double, + double, double, double); +void picture(Biobufhdr *, char *); +void beginpath(char*, int); +void drawpath(char*, int); diff --git a/sys/src/cmd/postscript/tr2post/utfmap b/sys/src/cmd/postscript/tr2post/utfmap new file mode 100755 index 000000000..2f9d6dc37 --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/utfmap @@ -0,0 +1,47 @@ +¡ !! ¢ c$ £ l$ ¤ g$ +¥ y$ ¦ || § SS ¨ "" +© cO ª sa « << ¬ no + -- ® rO ¯ __ ° de +± +- ² s2 ³ s3 ´ '' +µ mi ¶ pg · .. ¸ ,, +¹ s1 º s0 » >> ¼ 14 +½ 12 ¾ 34 ¿ ?? À `A +Á 'A Â ^A Ã ~A Ä "A +Å oA Æ AE Ç ,C È `E +É 'E Ê ^E Ë "E Ì `I +Í 'I Î ^I Ï "I Ð D- +Ñ ~N Ò `O Ó 'O Ô ^O +Õ ~O Ö "O × mu Ø /O +Ù `U Ú 'U Û ^U Ü "U +Ý 'Y Þ |P ß ss à `a +á 'a â ^a ã ~a ä "a +å oa æ ae ç ,c è `e +é 'e ê ^e ë "e ì `i +í 'i î ^i ï "i ð d- +ñ ~n ò `o ó 'o ô ^o +õ ~o ö "o ÷ -: ø /o +ù `u ú 'u û ^u ü "u +ý 'y þ |p ÿ "y α *a +β *b γ *g δ *d ε *e +ζ *z η *y θ *h ι *i +κ *k λ *l *m μ ν *n +ξ *c ο *o π *p ρ *r +ς ts σ *s τ *t υ *u +φ *f χ *x ψ *q ω *w +Α *A Β *B Γ *G Δ *D +Ε *E Ζ *Z Η *Y Θ *H +Ι *I Κ *K Λ *L Μ *M +Ν *N Ξ *C Ο *O Π *P +Ρ *R Σ *S Τ *T Υ *U +Φ *F Χ *X Ψ *Q Ω *W +← <- ↑ ua → -> ↓ da +↔ ab ∀ fa ∃ te ∂ pd +∅ es ∆ *D ∇ gr ∉ !m +∍ st ∗ ** ∙ bu √ sr +∝ pt ∞ if ∠ an ∧ l& +∨ l| ∩ ca ∪ cu ∫ is +∴ tf ≃ ~= ≅ cg ≈ ~~ +≠ != ≡ == ≦ <= ≧ >= +⊂ sb ⊃ sp ⊄ !b ⊆ ib +⊇ ip ⊕ O+ ⊖ O- ⊗ Ox +⊢ tu ⊨ Tu ⋄ lz ⋯ el diff --git a/sys/src/cmd/postscript/tr2post/utils.c b/sys/src/cmd/postscript/tr2post/utils.c new file mode 100755 index 000000000..e9979ff1e --- /dev/null +++ b/sys/src/cmd/postscript/tr2post/utils.c @@ -0,0 +1,264 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include "../common/common.h" +#include "tr2post.h" + +int hpos = 0, vpos = 0; +int fontsize, fontpos; + +#define MAXSTR 128 +int trindex; /* index into trofftab of current troff font */ +static int expecthmot = 0; + +void +initialize(void) { +} + +void +hgoto(int x) { + hpos = x; + if (pageon()) { + endstring(); +/* Bprint(Bstdout, "%d %d m\n", hpos, vpos); */ + } +} + +void +vgoto(int y) { + vpos = y; + if (pageon()) { + endstring(); +/* Bprint(Bstdout, "%d %d m\n", hpos, vpos); */ + } +} + +void +hmot(int x) { + int delta; + + if ((x<expecthmot-1) || (x>expecthmot+1)) { + delta = x - expecthmot; + if (curtrofffontid <0 || curtrofffontid >= troffontcnt) { + Bprint(Bstderr, "troffontcnt=%d curtrofffontid=%d\n", troffontcnt, curtrofffontid); + Bflush(Bstderr); + exits(""); + } + if (delta == troffontab[curtrofffontid].spacewidth*fontsize/10 && isinstring()) { + if (pageon()) runeout(' '); + } else { + if (pageon()) { + endstring(); + /* Bprint(Bstdout, " %d 0 rmoveto ", delta); */ +/* Bprint(Bstdout, " %d %d m ", hpos+x, vpos); */ + if (debug) Bprint(Bstderr, "x=%d expecthmot=%d\n", x, expecthmot); + } + } + } + hpos += x; + expecthmot = 0; +} + +void +vmot(int y) { + endstring(); +/* Bprint(Bstdout, " 0 %d rmoveto ", -y); */ + vpos += y; +} + +struct charent ** +findglyph(int trfid, Rune rune, char *stoken) { + struct charent **cp; + + for (cp = &(troffontab[trfid].charent[RUNEGETGROUP(rune)][RUNEGETCHAR(rune)]); *cp != 0; cp = &((*cp)->next)) { + if ((*cp)->name) { + if (debug) Bprint(Bstderr, "looking for <%s>, have <%s> in font %s\n", stoken, (*cp)->name, troffontab[trfid].trfontid); + if (strcmp((*cp)->name, stoken) == 0) + break; + } + } + return(cp); +} + +/* output glyph. Use first rune to look up character (hash) + * then use stoken UTF string to find correct glyph in linked + * list of glyphs in bucket. + */ +void +glyphout(Rune rune, char *stoken, BOOLEAN specialflag) { + struct charent **cp; + struct troffont *tfp; + struct psfent *psfp; + int i, t; + int fontid; /* this is the troff font table index, not the mounted font table index */ + int mi, fi, wid; + Rune r; + + settrfont(); + + /* check current font for the character, special or not */ + fontid = curtrofffontid; +if (debug) fprint(2, " looking through current font: trying %s\n", troffontab[fontid].trfontid); + cp = findglyph(fontid, rune, stoken); + if (*cp != 0) goto foundit; + + if (specialflag) { + if (expecthmot) hmot(0); + + /* check special fonts for the special character */ + /* cycle through the (troff) mounted fonts starting at the next font */ + for (mi=0; mi<fontmnt; mi++) { + if (troffontab[fontid].trfontid==0) error(WARNING, "glyphout:troffontab[%d].trfontid=0x%x, botch!\n", + fontid, troffontab[fontid].trfontid); + if (fontmtab[mi]==0) { + if (debug) fprint(2, "fontmtab[%d]=0x%x, fontmnt=%d\n", mi, fontmtab[mi], fontmnt); + continue; + } + if (strcmp(troffontab[fontid].trfontid, fontmtab[mi])==0) break; + } + if (mi==fontmnt) error(FATAL, "current troff font is not mounted, botch!\n"); + for (i=(mi+1)%fontmnt; i!=mi; i=(i+1)%fontmnt) { + if (fontmtab[i]==0) { + if (debug) fprint(2, "fontmtab[%d]=0x%x, fontmnt=%d\n", i, fontmtab[i], fontmnt); + continue; + } + fontid = findtfn(fontmtab[i], TRUE); +if (debug) fprint(2, " looking through special fonts: trying %s\n", troffontab[fontid].trfontid); + if (troffontab[fontid].special) { + cp = findglyph(fontid, rune, stoken); + if (*cp != 0) goto foundit; + } + } + + /* check font 1 (if current font is not font 1) for the special character */ + if (mi != 1) { + fontid = findtfn(fontmtab[1], TRUE);; +if (debug) fprint(2, " looking through font at position 1: trying %s\n", troffontab[fontid].trfontid); + cp = findglyph(fontid, rune, stoken); + if (*cp != 0) goto foundit; + } + } + + if (*cp == 0) { + error(WARNING, "cannot find glyph, rune=0x%x stoken=<%s> troff font %s\n", rune, stoken, + troffontab[curtrofffontid].trfontid); + expecthmot = 0; + } + + /* use the peter face in lieu of the character that we couldn't find */ + rune = 'p'; stoken = "pw"; + for (i=(mi+1)%fontmnt; i!=mi; i=(i+1)%fontmnt) { + if (fontmtab[i]==0) { + if (debug) fprint(2, "fontmtab[%d]=0x%x\n", i, fontmtab[i]); + continue; + } + fontid = findtfn(fontmtab[i], TRUE); +if (debug) fprint(2, " looking through special fonts: trying %s\n", troffontab[fontid].trfontid); + if (troffontab[fontid].special) { + cp = findglyph(fontid, rune, stoken); + if (*cp != 0) goto foundit; + } + } + + if (*cp == 0) { + error(WARNING, "cannot find glyph, rune=0x%x stoken=<%s> troff font %s\n", rune, stoken, + troffontab[curtrofffontid].trfontid); + expecthmot = 0; + return; + } + +foundit: + t = (((*cp)->postfontid&0xff)<<8) | ((*cp)->postcharid&0xff); + if (debug) { + Bprint(Bstderr, "runeout(0x%x)<%C> postfontid=0x%x postcharid=0x%x troffcharwidth=%d\n", + rune, rune, (*cp)->postfontid, (*cp)->postcharid, (*cp)->troffcharwidth); + } + + tfp = &(troffontab[fontid]); + for (i=0; i<tfp->psfmapsize; i++) { + psfp = &(tfp->psfmap[i]); + if(t>=psfp->start && t<=psfp->end) break; + } + if (i >= tfp->psfmapsize) + error(FATAL, "character <0x%x> does not have a Postscript font defined.\n", rune); + + setpsfont(psfp->psftid, fontsize); + + if (t == 0x0001) { /* character is in charlib */ + endstring(); + if (pageon()) { + struct charent *tcp; + + Bprint(Bstdout, "%d %d m ", hpos, vpos); + /* if char is unicode character rather than name, clean up for postscript */ + wid = chartorune(&r, (*cp)->name); + if(' '<r && r<0x7F) + Bprint(Bstdout, "%d build_%s\n", (*cp)->troffcharwidth, (*cp)->name); + else{ + if((*cp)->name[wid] != 0) + error(FATAL, "character <%s> badly named\n", (*cp)->name); + Bprint(Bstdout, "%d build_X%.4x\n", (*cp)->troffcharwidth, r); + } + + /* stash charent pointer in a list so that we can print these character definitions + * in the prologue. + */ + for (i=0; i<build_char_cnt; i++) + if (*cp == build_char_list[i]) break; + if (i == build_char_cnt) { + build_char_list = galloc(build_char_list, sizeof(struct charent *) * ++build_char_cnt, + "build_char_list"); + build_char_list[build_char_cnt-1] = *cp; + } + } + expecthmot = (*cp)->troffcharwidth * fontsize / unitwidth; + } else if (isinstring() || rune != ' ') { + startstring(); + if (pageon()) { + if (rune == ' ') + Bprint(Bstdout, " "); + else + Bprint(Bstdout, "%s", charcode[RUNEGETCHAR(t)].str); + } + expecthmot = (*cp)->troffcharwidth * fontsize / unitwidth; + } +} + +/* runeout puts a symbol into a string (queue) to be output. + * It also has to keep track of the current and last symbol + * output to check that the spacing is correct by default + * or needs to be adjusted with a spacing operation. + */ + +void +runeout(Rune rune) { + char stoken[UTFmax+1]; + int i; + + i = runetochar(stoken, &rune); + stoken[i] = '\0'; + glyphout(rune, stoken, TRUE); +} + +void +specialout(char *stoken) { + Rune rune; + int i; + + i = chartorune(&rune, stoken); + glyphout(rune, stoken, TRUE); +} + +void +graphfunc(Biobufhdr *bp) { +} + +long +nametorune(char *name) { + return(0); +} + +void +notavail(char *msg) { + Bprint(Bstderr, "%s is not available at this time.\n", msg); +} diff --git a/sys/src/cmd/postscript/trofftable/mkfile b/sys/src/cmd/postscript/trofftable/mkfile new file mode 100755 index 000000000..38f0720d0 --- /dev/null +++ b/sys/src/cmd/postscript/trofftable/mkfile @@ -0,0 +1,42 @@ +</$objtype/mkfile + +MAKE=mk +MAKEFILE=postscript.mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +FONTDIR=$ROOT/sys/lib/troff/font +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/sys/lib/postscript/bin +POSTLIB=$ROOT/sys/lib/postscript/prologues + + +all :V: trofftable + +install :V: $POSTBIN/rc/trofftable $POSTLIB/trofftable.ps $MAN1DIR/trofftable.1 + +installall :V: install + +clean :V: + rm -f trofftable + +clobber :V: clean + +$POSTBIN/rc/trofftable : trofftable + cp $prereq $target + +$POSTLIB/trofftable.ps : trofftable.ps + cp $prereq $target + +$MAN1DIR/trofftable.1 : trofftable.1 + cp $prereq $target + +trofftable : trofftable.rc + sed \ + -e 's?^FONTDIR=.*?FONTDIR='$FONTDIR'?' \ + -e 's?^POSTBIN=.*?POSTBIN='$POSTBIN'?' \ + -e 's?^POSTLIB=.*?POSTLIB='$POSTLIB'?' \ + trofftable.rc >trofftable + chmod 775 trofftable diff --git a/sys/src/cmd/postscript/trofftable/trofftable.1 b/sys/src/cmd/postscript/trofftable/trofftable.1 new file mode 100755 index 000000000..031e2ed04 --- /dev/null +++ b/sys/src/cmd/postscript/trofftable/trofftable.1 @@ -0,0 +1,164 @@ +.ds dF /usr/lib/font +.ds dQ /usr/lib/postscript +.TH TROFFTABLE 1 "DWB 3.2" +.SH NAME +.B trofftable +\- output a PostScript program that builds a font width table +.SH SYNOPSIS +\*(mBtrofftable\f1 +.OP "" options [] +.OP "" shortname +.OP "" longname [] +.SH DESCRIPTION +.B trofftable +writes a PostScript program on the standard output that builds a +font width table or typesetter description file. +The following +.I options +are understood: +.TP 1.0i +.OP \-t name +Use +.I name +as the template for fonts not in the default set. +Choose +.MW R +for proportionally spaced fonts and +.MW CW +for fixed width fonts. +Try +.MW ZD +(ZapfDingbats) if the font has a non-standard +character set. +The default is +.MR R . +.TP 1.0i +.OP \-C file +Copy +.I file +into each PostScript table program; +.I file +must contain legitimate PostScript. +.TP 1.0i +.OP \-H hostdir +Use +.I hostdir +as the host resident font directory. +A file in +.I hostdir +that matches the name of the troff font is assumed to be a host +resident font program and is included in the PostScript width +table program. +There is no default. +.TP 1.0i +.OP \-L file +Use +.I file +as the PostScript prologue. +.br +The default is +.MW \*(dQ/trofftable.ps +.TP 1.0i +.OP \-S file +Use +.I file +as the shell library file. +Overrides the choice made with the +.OP \-T +option. +.TP 1.0i +.OP \-T name +Set the target device to +.IR name . +Device +.I name +means +.br +.MI \*(dF/dev name /shell.lib +is the shell library file. +There is no default. +.PP +One of +.OP \-T +or +.OP \-S +is required. +If both are given +.OP \-S +wins. +Either +.OP \-H +or +.OP \-C +can be used to include a host resident font. +.PP +The shell library file defines a collection of functions used to +build troff tables. +The default set of tables is the list of names returned by the +.MW AllTables +function. +Changes to the default list can be made by updating the +.MW BuiltinTables +function. +.PP +.I Shortname +is the name of the +.B troff +font and +.I longname +is the name of the PostScript font; +.I longname +can be omitted only if +.I shortname +is a default table name. +PostScript table programs created by +.B trofftable +return data to the host computer using PostScript's +.MW print +operator. +See +.BR hardcopy (1) +if you don't have access to the printer's serial port. +.SH EXAMPLES +Get the PostScript program that builds a width table for font +.MR R : +.EX +trofftable -Tpost R >R.ps +.EE +If a font is not in the default set include the +.B troff +and PostScript font names: +.EX +trofftable -TLatin1 GL Garamond-Light >GL.ps +.EE +A font must be available on the printer when the table is built. +Use +.OP \-H +or +.OP \-C +to include host resident fonts. +.SH WARNINGS +A width table will not build properly if the printer cannot access +the PostScript font. +.PP +The +.OP -TLatin1 +option only works on PostScript printers that support the full +.SM ISO +Latin-1 character set. +The error message from older printers will likely indicate a missing +.MW ISOLatin1Encoding +array. +.SH FILES +.MW \*(dF/dev*/shell.lib +.br +.MW \*(dQ/dpost.ps +.br +.MW \*(dQ/trofftable.ps +.SH SEE ALSO +.BR dpost (1), +.BR hardcopy (1), +.BR postio (1), +.BR troff (1), +.BR buildtables (1), +.BR font (5) diff --git a/sys/src/cmd/postscript/trofftable/trofftable.mk b/sys/src/cmd/postscript/trofftable/trofftable.mk new file mode 100755 index 000000000..d12b1fea5 --- /dev/null +++ b/sys/src/cmd/postscript/trofftable/trofftable.mk @@ -0,0 +1,74 @@ +MAKE=/bin/make +MAKEFILE=trofftable.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +FONTDIR=/usr/lib/font +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript +MAN1DIR=/tmp + +all : trofftable + +install : all + @if [ ! -d $(POSTBIN) ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + @if [ ! -d "$(POSTLIB)" ]; then \ + mkdir $(POSTLIB); \ + chmod 755 $(POSTLIB); \ + chgrp $(GROUP) $(POSTLIB); \ + chown $(OWNER) $(POSTLIB); \ + fi + cp trofftable $(POSTBIN)/trofftable + @chmod 755 $(POSTBIN)/trofftable + @chgrp $(GROUP) $(POSTBIN)/trofftable + @chown $(OWNER) $(POSTBIN)/trofftable + cp trofftable.ps $(POSTLIB)/trofftable.ps + @chmod 644 $(POSTLIB)/trofftable.ps + @chgrp $(GROUP) $(POSTLIB)/trofftable.ps + @chown $(OWNER) $(POSTLIB)/trofftable.ps + cp trofftable.1 $(MAN1DIR)/trofftable.1 + @chmod 644 $(MAN1DIR)/trofftable.1 + @chgrp $(GROUP) $(MAN1DIR)/trofftable.1 + @chown $(OWNER) $(MAN1DIR)/trofftable.1 + +clean : + +clobber : clean + rm -f trofftable + +trofftable : trofftable.sh + sed \ + -e "s'^FONTDIR=.*'FONTDIR=$(FONTDIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + trofftable.sh >trofftable + @chmod 755 trofftable + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^FONTDIR=.*'FONTDIR=$(FONTDIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dF.*'.ds dF $(FONTDIR)'" \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + trofftable.1 >XXX.1; \ + mv XXX.1 trofftable.1 + diff --git a/sys/src/cmd/postscript/trofftable/trofftable.ps b/sys/src/cmd/postscript/trofftable/trofftable.ps new file mode 100755 index 000000000..dcc23200c --- /dev/null +++ b/sys/src/cmd/postscript/trofftable/trofftable.ps @@ -0,0 +1,189 @@ +% +% Prologue for building troff width tables. The gsave/grestore pairs are +% for hardcopy. +% + +/slowdown 25 def +/flagduplicates false def + +/ascenderheight -1 def +/descenderdepth 0 def +/octalescapes 256 def +/startcomments 256 def +/currentfontdict null def +/scratchstring 512 string def + +/Print { + scratchstring cvs print flush + slowdown {1 pop} repeat +} def + +/ReEncode { % vector fontname ReEncode - + dup + findfont dup length dict begin + {1 index /FID ne {def}{pop pop} ifelse} forall + /Encoding 3 -1 roll def + currentdict + end + definefont pop +} bind def + +/SelectFont { % fontname SelectFont - + findfont + dup /PaintType get 0 eq { + /scaling 1 def + unitwidth resolution 72.0 div mul + }{ + /scaling resolution 72 div def + unitwidth + } ifelse + scalefont + /currentfontdict exch def +} def + +/ChangeMetrics {DpostPrologue begin addmetrics end} def + +/NamedInPrologue { + dup + DpostPrologue exch known { + DpostPrologue exch get type /nametype eq { + (named in prologue\n) Print + } if + }{pop} ifelse +} def + +/SetAscender { + /str exch def + + gsave + currentfontdict setfont + newpath + 0 0 moveto + str false charpath flattenpath pathbbox + /descenderdepth 4 -1 roll .5 mul def + exch pop exch pop + + newpath + 0 0 moveto + str 0 1 getinterval false charpath flattenpath pathbbox + 4 1 roll pop pop pop + dup 3 1 roll sub .25 mul add + /ascenderheight exch def + grestore +} def + +/GetAscender { + ascenderheight descenderdepth ge { + gsave + currentfontdict setfont + newpath + 0 0 moveto + ( ) dup 0 4 -1 roll put + false charpath flattenpath pathbbox + exch pop 3 -1 roll pop + ascenderheight gt {2}{0} ifelse + exch descenderdepth lt {1}{0} ifelse + or + grestore + }{0} ifelse +} def + +/GetWidth { + gsave + currentfontdict setfont + ( ) dup 0 4 -1 roll put + stringwidth pop scaling mul round cvi + grestore +} def + +/GetCode { + 256 3 1 roll % last unprintable match + 0 3 -1 roll { + 2 index eq { + dup 127 and 32 ge {exit} if + 3 -1 roll pop + dup 3 1 roll + } if + 1 add + } forall + exch pop + dup 255 gt {pop}{exch pop} ifelse +} def + +/BuildFontCharset { + 0 2 charset length 2 sub { + /i exch def + /chcode -1 def + /chname null def + /key charset i get def + /val charset i 1 add get def + + val type /integertype eq { + /chcode val def + /chname currentfontdict /Encoding get chcode get def + } if + + val type /nametype eq { + /chname val def + /chcode currentfontdict /Encoding get chname GetCode def + } if + + val type /stringtype eq {/chcode 0 def} if + + chcode 0 lt chcode 255 gt or { + chcode 0 lt {(syntaxerror: )}{(undefinedname: )} ifelse + Print key Print (\t) Print val Print (\n) Print + quit + } if + + val type /stringtype eq { + key Print + (\t) Print val Print + (\n) Print + }{ + chcode octalescapes ge key (---) eq and { + (\\0) Print chcode 8 ( ) cvrs Print + }{key Print} ifelse + (\t) Print chcode GetWidth Print + (\t) Print chcode GetAscender Print + (\t) Print chcode Print + chcode startcomments ge { + (\t# ) Print chname Print + } if + (\n) Print + chcode octalescapes ge (---) key ne and { + key (\\0) anchorsearch not { + pop + (\\0) Print chcode 8 ( ) cvrs Print + (\t"\n) Print + }{pop pop} ifelse + } if + } ifelse + } for +} def + +/BuildDescCharset { + /DescDict 512 dict def + /Characters 0 def + + 0 1 charset length 1 sub { + /i exch def + /key charset i get def + + key length 2 eq { + DescDict key cvn known { + flagduplicates { % for debugging + (<<<duplicated character: ) Print + key Print + (>>>\n) Print + } if + }{ + DescDict key cvn 1 put + key Print + /Characters Characters 1 add def + Characters 20 mod 0 eq {(\n)}{( )} ifelse Print + } ifelse + } if + } for +} def + diff --git a/sys/src/cmd/postscript/trofftable/trofftable.rc b/sys/src/cmd/postscript/trofftable/trofftable.rc new file mode 100755 index 000000000..47c56b5bd --- /dev/null +++ b/sys/src/cmd/postscript/trofftable/trofftable.rc @@ -0,0 +1,123 @@ +#!/bin/rc +# Writes a PostScript program on standard output that builds a width +# table or typesetter description file. The program uses PostScript's +# print procedure, which means the table comes back on the printer's +# serial port. Try hardcopy if you don't have access to the port. +# + +POSTLIB=/sys/lib/postscript/prologues +FONTDIR=/sys/lib/troff/font + +PROLOGUE=$POSTLIB/trofftable.ps +DPOSTPROLOGUE=$POSTLIB/dpost.ps + +COPYFILE=() +HOSTFONTDIR=() +DEVICE=() +LIBRARY=() +TEMPLATE=-R + +SLOWDOWN=25 +STARTCOMMENTS=256 + +NONCONFORMING='%!PS' +ENDPROLOG='%%EndProlog' +BEGINSETUP='%%BeginSetup' +ENDSETUP='%%EndSetup' +TRAILER='%%Trailer' + +while (! ~ $#* 0 && ~ $1 -*) { + switch ($1) { + case -C; shift; COPYFILE=$COPYFILE' '$1 + case -C*; COPYFILE=$COPYFILE' '`{echo $1 | sed s/-C//} + + case -F; shift; FONTDIR=$1 + case -F*; FONTDIR=`{echo $1 | sed s/-F//} + + case -H; shift; HOSTFONTDIR=$1 + case -H*; HOSTFONTDIR=`{echo $1 | sed s/-H//} + + case -L; shift; PROLOGUE=$1 + case -L*; PROLOGUE=`{echo $1 | sed s/-L//} + + case -S; shift; LIBRARY=$1 + case -S*; LIBRARY=`{echo $1 | sed s/-S//} + + case -T; shift; DEVICE=$1 + case -T*; DEVICE=`{echo $1 | sed s/-T//} + + case -c; shift; STARTCOMMENTS=$1 + case -c*; STARTCOMMENTS=`{echo $1 | sed s/-c//} + + case -o; shift; OCTALESCAPES=$1 # only for Latin1 tables + case -o*; OCTALESCAPES=`{echo $1 | sed s/-o//} + + case -s; shift; SLOWDOWN=$1 + case -s*; SLOWDOWN=`{echo $1 | sed s/-s//} + + case -t; shift; TEMPLATE=$1 + case -t*; TEMPLATE=`{echo $1 | sed s/-t//} + + case -*; echo $0: illegal option $1 >[1=2]; exit 1 + } + shift +} + +if (! ~ $#DEVICE 0 && ! ~ $#LIBRARY 0) { + echo $0: no device or shell library >[1=2] + exit 1 +} + +if (! ~ $#* 1 2) { + echo $0: bad argument count >[1=2] + exit 1 +} + +if (test -d $HOSTFONTDIR -a -f $HOSTFONTDIR/$1) { + COPYFILE=$COPYFILE' '$HOSTFONTDIR/$1 +} + +# +# Include the shell library and get the command used to build the table. +# Make awk call a separate library function?? +# +if (~ $#LIBRARY 0 || ~ $LIBRARY '') LIBRARY=$FONTDIR/dev$DEVICE/shell.lib + +. $LIBRARY + +if (~ $#* 1) TEMPLATE=$1 + +CMD=`{BuiltinTables | awk '$2 == template"" { + if ( pname == "" ) + pname = $3 + printf "%s %s %s", $1, tname, pname + exit 0 +}' template=$TEMPLATE tname=$1 pname=$2} + +if (! $CMD) { + echo $0: $TEMPLATE not found >[1=2] + exit 1 +} + +# +# Build the PostScript font table program. +# + +echo $NONCONFORMING +cat $PROLOGUE +echo /DpostPrologue 100 dict dup begin +cat $DPOSTPROLOGUE +echo end def +echo $ENDPROLOG + +echo $BEGINSETUP +if (~ $COPYFILE '') COPYFILE=/dev/null +cat $COPYFILE +echo /slowdown $SLOWDOWN def +echo /startcomments $STARTCOMMENTS def +echo $ENDSETUP + +$CMD + +echo $TRAILER + diff --git a/sys/src/cmd/postscript/trofftable/trofftable.sh b/sys/src/cmd/postscript/trofftable/trofftable.sh new file mode 100755 index 000000000..528bb8f84 --- /dev/null +++ b/sys/src/cmd/postscript/trofftable/trofftable.sh @@ -0,0 +1,129 @@ +#!/bin/sh + +# +# Writes a PostScript program on standard output that builds a width +# table or typesetter description file. The program uses PostScript's +# print procedure, which means the table comes back on the printer's +# serial port. Try hardcopy if you don't have access to the port. +# + +POSTBIN=/usr/lbin/postscript +POSTLIB=/usr/lib/postscript +FONTDIR=/usr/lib/font + +PROLOGUE=$POSTLIB/trofftable.ps +DPOSTPROLOGUE=$POSTLIB/dpost.ps + +COPYFILE= +HOSTFONTDIR= +DEVICE= +LIBRARY= +TEMPLATE= + +SLOWDOWN=25 +STARTCOMMENTS=256 + +NONCONFORMING="%!PS" +ENDPROLOG="%%EndProlog" +BEGINSETUP="%%BeginSetup" +ENDSETUP="%%EndSetup" +TRAILER="%%Trailer" + +while [ -n "$1" ]; do + case $1 in + -C) shift; COPYFILE="$COPYFILE $1";; + -C*) COPYFILE="$COPYFILE `echo $1 | sed s/-C//`";; + + -F) shift; FONTDIR=$1;; + -F*) FONTDIR=`echo $1 | sed s/-F//`;; + + -H) shift; HOSTFONTDIR=$1;; + -H*) HOSTFONTDIR=`echo $1 | sed s/-H//`;; + + -L) shift; PROLOGUE=$1;; + -L*) PROLOGUE=`echo $1 | sed s/-L//`;; + + -S) shift; LIBRARY=$1;; + -S*) LIBRARY=`echo $1 | sed s/-S//`;; + + -T) shift; DEVICE=$1;; + -T*) DEVICE=`echo $1 | sed s/-T//`;; + + -c) shift; STARTCOMMENTS=$1;; + -c*) STARTCOMMENTS=`echo $1 | sed s/-c//`;; + + -o) shift; OCTALESCAPES=$1;; # only for Latin1 tables + -o*) OCTALESCAPES=`echo $1 | sed s/-o//`;; + + -s) shift; SLOWDOWN=$1;; + -s*) SLOWDOWN=`echo $1 | sed s/-s//`;; + + -t) shift; TEMPLATE=$1;; + -t*) TEMPLATE=`echo $1 | sed s/-t//`;; + + -*) echo "$0: illegal option $1" >&2; exit 1;; + + *) break;; + esac + shift +done + +if [ ! "$DEVICE" -a ! "$LIBRARY" ]; then + echo "$0: no device or shell library" >&2 + exit 1 +fi + +if [ $# -ne 1 -a $# -ne 2 ]; then + echo "$0: bad argument count" >&2 + exit 1 +fi + +if [ -d "$HOSTFONTDIR" -a -f "$HOSTFONTDIR/$1" ]; then + COPYFILE="$COPYFILE $HOSTFONTDIR/$1" +fi + +# +# Include the shell library and get the command used to build the table. +# Make awk call a separate library function?? +# + +. ${LIBRARY:-${FONTDIR}/dev${DEVICE}/shell.lib} + +if [ $# -eq 1 ] + then TEMPLATE=$1 + else TEMPLATE=${TEMPLATE:-R} +fi + +CMD=`BuiltinTables | awk '$2 == template"" { + if ( pname == "" ) + pname = $3 + printf "%s %s %s", $1, tname, pname + exit 0 +}' template="$TEMPLATE" tname="$1" pname="$2"` + +if [ ! "$CMD" ]; then + echo "$0: $TEMPLATE not found" >&2 + exit 1 +fi + +# +# Build the PostScript font table program. +# + +echo $NONCONFORMING +cat $PROLOGUE +echo "/DpostPrologue 100 dict dup begin" +cat $DPOSTPROLOGUE +echo "end def" +echo $ENDPROLOG + +echo $BEGINSETUP +cat ${COPYFILE:-/dev/null} +echo "/slowdown $SLOWDOWN def" +echo "/startcomments $STARTCOMMENTS def" +echo $ENDSETUP + +$CMD + +echo $TRAILER + |