commit 5c1fcbcc49bd74e772e2474a248f40a26eb7c08f
Author: Kyle Milz <milz@black.my.domain>
Date: Thu, 1 Aug 2019 22:13:22 -0700
xdvi-22.86
Diffstat:
A | FAQ | | | 357 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | INSTALL | | | 543 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Imakefile | | | 332 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | MAKE-VMS.COM | | | 217 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | Makefile.in | | | 151 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | README | | | 232 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | README.VMS | | | 483 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | VMS-C.OPT | | | 2 | ++ |
A | XDVI.RNH | | | 692 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | acconfig.h | | | 150 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | aclocal.m4 | | | 280 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | config.hin | | | 228 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | config.xdvi | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
A | configure | | | 4834 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | configure.in | | | 388 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | dvi-draw.c | | | 3048 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | dvi-init.c | | | 1030 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | dvi.h | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | events.c | | | 5064 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | filefind.c | | | 2867 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | filefind.h | | | 273 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | filf-app.h | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
A | font-open.c | | | 2470 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ft.c | | | 474 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | gf.c | | | 328 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | install-sh | | | 250 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | mksedscript | | | 236 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | pk.c | | | 363 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | popups.c | | | 4540 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | psdps.c | | | 832 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | psgs.c | | | 916 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | psheader.txt | | | 297 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | psnews.c | | | 923 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | special.c | | | 2284 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | squeeze.c | | | 192 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | util.c | | | 1058 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | version.h | | | 1 | + |
A | vf.c | | | 152 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | xautocnf.pat | | | 276 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | xautocnf.txt | | | 16 | ++++++++++++++++ |
A | xdvi-man.sed | | | 3244 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | xdvi.c | | | 3632 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | xdvi.h | | | 1386 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | xdvi.icon | | | 27 | +++++++++++++++++++++++++++ |
A | xdvi.lsm | | | 21 | +++++++++++++++++++++ |
A | xdvizilla | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | xdvizilla.1 | | | 115 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
47 files changed, 45479 insertions(+), 0 deletions(-)
diff --git a/FAQ b/FAQ
@@ -0,0 +1,357 @@
+This file answers the following questions about installing xdvi:
+
+ 1. Why do I get the message, ``Caution: overstrike characters may be
+ incorrect'' when running netscape and xdvi simultaneously, and why
+ does the screen output look so grainy?
+ 2. I have font files cmr10.tfm, etc. Why can't xdvi use them?
+ 3. I can't seem to set the font path correctly. Can you help me?
+ 4. Whenever I run xdvi, it prints out things like:
+ - mktexpk --mfmode cx --bdpi 300 --mag 'magstep(0)' --dpi 300 cmr7 '>&3'
+ mktexpk: /var/cache/fonts/pk/cx/public/cm/cmr7.300pk already exists.
+ Why is this?
+ 5. xdvi claims to support virtual fonts, but I can't use PostScript
+ virtual fonts (such as helv.vf or phvr.vf) with xdvi. Why not?
+ 6. Why can't xdvi correctly display metapost files containing text?
+ 7. What does the message "gs: No such file or directory" mean, and why
+ does xdvi need to call ghostscript?
+ 8. Why does the file selection popup look messed up when changing
+ directories?
+ 9. Why do I get the message "dvips: ! couldn't open output pipe"
+ when I try to print, using Red Hat 8.0?
+
+as well as the following questions (dependent on some quite old versions
+of software):
+
+ 10. Why do I get weird vertical color stripes when using xdvi on my S3
+ Virge video card?
+ 11. I am using gs 5.50 to render PostScript figures, and I find that
+ sometimes characters appear on the wrong page. Why is that?
+ 12. I am using gs 3.33 to render PostScript figures, but find that it
+ cuts some off below or to the right of a certain point, and others
+ are omitted entirely.
+ 13. I am trying to display PostScript specials with -DPS_GS, but
+ instead I get the message `gs: gs: Malformed ghostview color property.'
+ 14. What is this "_get_wmShellWidgetClass undefined" error?
+
+Last modified: 20 June 2003
+A current copy of this file can be viewed on the WWW at the URL
+http://math.berkeley.edu/~vojta/xdvi_faq.txt
+
+----------
+
+1. Why do I get the message, ``Caution: overstrike characters may be
+ incorrect'' when running netscape and xdvi simultaneously, and why
+ does the screen output look so grainy?
+
+This is because your video setup has only a limited number (typically 256)
+of different colors that can be displayed at any given time, and netscape
+is using most of them. There are several ways around this problem:
+
+ o Start xdvi before netscape. This should eliminate the problem for
+ that copy of xdvi (only).
+ o Invoke netscape via "netscape -ncols 130" This limits netscape's
+ color usage to 130. Other numbers may be used as well.
+ o Invoke netscape via "netscape -install" This causes netscape to run
+ with its own colormap. A disadvantage of this approach is that
+ netscape's colors will be bizarre when the cursor is outside netscape's
+ window, and conversely all other colors on the screen will look funny
+ when the cursor is in the netscape window.
+
+The screen output looks so grainy because xdvi is not able to use its
+anti-aliasing features without enough colors.
+
+----------
+
+2. I have font files cmr10.tfm, etc. Why can't xdvi use them?
+
+tfm files contain only minimal information about the characters
+in a font: just the height, width, depth, and kerning and ligature
+information. To obtain information about the shapes of the
+characters, xdvi needs pk or gf files. (pxl files also contain
+this information, but are obsolete. There are utilities to convert
+them to pk files though.)
+
+----------
+
+3. I can't seem to set the font path correctly. Can you help me?
+
+Try
+ xdvi -debug 32 file.dvi
+to find out where xdvi is looking for the fonts.
+
+----------
+
+4. Whenever I run xdvi, it prints out things like:
+ - mktexpk --mfmode cx --bdpi 300 --mag 'magstep(0)' --dpi 300 cmr7 '>&3'
+ mktexpk: /var/cache/fonts/pk/cx/public/cm/cmr7.300pk already exists.
+ Why is this?
+
+It means either that:
+
+ (1) Your ls-R database is not up to date (fix this by running mktexlsr), or
+ (2) Your font path is not set correctly (see #3, above).
+
+----------
+
+5. xdvi claims to support virtual fonts, but I can't use PostScript
+ virtual fonts (such as helv.vf or phvr.vf) with xdvi. Why not?
+
+The short answer is to quote the man page:
+
+ Virtual fonts are also supported, although xdvi does not
+ have any built-in fonts to which they can refer.
+
+As further explanation, let me begin by pointing out:
+
+ VIRTUAL FONTS ARE NOT FONTS.
+
+Virtual fonts are recipes for building fonts from other fonts.
+In the case of PostScript fonts, those other fonts reside on
+your printer. This is fine for dvi-to-PostScript programs
+such as dvips, but it presents a problem for xdvi since it cannot
+access your printer.
+
+There are some solutions, however.
+
+The first solution is to install gsftopk, which uses
+ghostscript to approximate the fonts. It is made for sites that
+use both xdvi and dvips, although if you just use xdvi it should
+be useful, too.
+
+Another solution is to get these fonts pre-made in common sizes.
+These were made by a program called gsrenderfont (part of the Gnu
+font utilities).
+
+These are all available via anonymous ftp:
+
+gsftopk from math.berkeley.edu:pub/TeX/gsftopk.tar.Z
+pre-made fonts from ftp.cs.umb.edu:pub/tex/psfonts.tar
+gsrenderfont from prep.ai.mit.edu:pub/gnu/fontutils-0.6.tar.gz
+
+----------
+
+6. Why can't xdvi correctly display metapost files containing text?
+
+The problem is that the PS files created by MP are (normally) not
+self-contained. xdvi delegates the display of PS files to
+ghostscript, which fails to handle those files.
+
+A solution is to instruct MP to create true EPS files, by including
+ prologues:=2;
+at the top of the document. If you have the CM postscript fonts
+installed so that ghostscript can find them, you can continue to use
+the CM fonts, otherwise you'll have to switch to Times or such for the
+illustrations.
+
+Switching the fonts can be done setting 'defaultfont' to something
+like "ptmr8r" (for Times). For the TeX material in 'btex .. etex'
+blocks, it is best to set up the fonts once in a 'verbatimtex .. etex'
+block. (And same for LaTeX of course.)
+
+This answer courtesy of Olaf Weber.
+
+----------
+
+7. What does the message "gs: No such file or directory" mean, and why
+ does xdvi need to call ghostscript?
+
+The message "gs: No such file or directory" means that xdvi needs to call
+ghostscript, but does not find it on your system. Ghostscript is a program
+used for rendering PostScript. It is needed by xdvi (1) for displaying
+PostScript specials in documents, and (2) for rendering PostScript fonts
+occurring in documents. In the latter case, xdvi calls a script (usually
+named mktexpk) which in turn calls the program gsftopk to render the font
+in a form usable by xdvi.
+
+----------
+
+8. Why does the file selection popup look messed up when changing
+ directories?
+
+This is a bug with XFree86 version 4.0.1a (and possibly other versions).
+Upgrading to version 4.0.3 (or newer) should fix the problem.
+
+----------
+
+9. Why do I get the message "dvips: ! couldn't open output pipe"
+ when I try to print, using Red Hat 8.0?
+
+When trying to print a file, the log window shows the following output:
+
+ This is dvips(k) 5.86 Copyright 1999 Radical Eye
+ Software (www.radicaleye.com)
+ ' TeX output 2003.04.08:1919' -> !lpr
+ dvips: ! couldn't open output pipe
+
+This is a known bug in (RedHat's customized version of) dvips' `secure mode',
+forbidding dvips to open pipes for printing; see also the bug report:
+
+ https://sourceforge.net/tracker/index.php?func=detail&aid=717663&group_id=23164&atid=377580
+
+and the discussion on the tetex mailing list:
+
+ http://www.mail-archive.com/tetex@informatik.uni-hannover.de/msg01782.html
+
+A possible workaround is to set the xdvi command-line option `-dvipspath'
+or the `.dvipsPath' X resource to a wrapper script that invokes dvips in
+a way that avoids the problem. An example for such a script (in Perl)
+is shown here:
+
+--- begin script ---
+#!/usr/bin/perl -w
+#
+# Wrapper for xdvi to launch dvips and avoid its secure feature that disallows
+# piping to lpr (dvips 5.92b / RH 8.0; 4/2003). Specify with -dvipspath option
+# (or .dvipsPath X11 resource) in xdvi. Written by S. Ulrich and P. Vojta.
+
+my @dvips_args = ("dvips");
+my $lpr_cmd;
+
+# Extract lpr command from the dvips args given in implicit pipe, if any
+foreach (@ARGV) {
+ if (/^-o[!\|](.*)/) {
+ $lpr_cmd = '|' . $1;
+ } else {
+ push (@dvips_args, $_);
+ }
+}
+
+# Construct explicit pipe with given lpr command
+if (defined $lpr_cmd) {
+ open(STDOUT, $lpr_cmd)
+ or die "Couldn't open output pipe $lpr_cmd: $!";
+}
+
+# Exec over to dvips
+exec @dvips_args
+ or die "Couldn't exec dvips: $!";
+--- end script ---
+
+----------
+
+10. Why do I get weird vertical color stripes when using xdvi on my
+ S3 Virge video card?
+
+This is a bug in the XF86_S3V X server. It has been reported to XFree86.
+The response from them is that the XF86_S3V server is being phased out
+and that users should use the XF86_SVGA server instead (which also, as of
+XFree86 3.3.3, supports the S3 Virge chipset).
+
+----------
+
+11. I am using gs 5.50 to render PostScript figures, and I find that
+ sometimes characters appear on the wrong page. Why is that?
+
+This is a bug in ghostscript 5.50. The following patch will fix it:
+
+*** gdevx.c.orig Fri Jul 17 07:31:27 1998
+--- gdevx.c Sat Oct 17 23:42:50 1998
+***************
+*** 59,65 ****
+ ((gx_device_X *)(dev))->up_area = 0,\
+ ((gx_device_X *)(dev))->up_count = 0
+ #define update_flush(dev)\
+! if ( ((gx_device_X *)(dev))->up_area != 0 ) update_do_flush(dev)
+ private void update_do_flush(P1(gx_device *));
+
+ #define flush_text(dev)\
+--- 59,66 ----
+ ((gx_device_X *)(dev))->up_area = 0,\
+ ((gx_device_X *)(dev))->up_count = 0
+ #define update_flush(dev)\
+! if ( ((gx_device_X *)(dev))->up_area != 0 || IN_TEXT((gx_device_X *)(dev)) )\
+! update_do_flush(dev)
+ private void update_do_flush(P1(gx_device *));
+
+ #define flush_text(dev)\
+
+----------
+
+12. I am using gs 3.33 to render PostScript figures, but find that it
+ cuts some off below or to the right of a certain point, and others
+ are omitted entirely.
+
+You should apply the following patch. This will also fix similar errors
+with ghostview. This patch supersedes a previous patch I have suggested
+to some people.
+
+*** gdevxini.c.orig Sun Nov 6 13:46:42 1994
+--- gdevxini.c Mon Jun 5 15:40:18 1995
+***************
+*** 319,344 ****
+
+ /* The following sets the imageable area according to the */
+ /* bounding box and margins sent by ghostview. */
+! { float m[4];
+! m[0] = (llx - left_margin) / 72.0; /* left */
+! m[1] = (lly - bottom_margin) / 72.0; /* bottom */
+! m[2] = xdev->width / xdev->x_pixels_per_inch -
+! (urx + right_margin) / 72.0; /* right */
+! m[3] = xdev->height / xdev->y_pixels_per_inch -
+! (ury + top_margin) / 72.0; /* top */
+!
+! /******
+! ****** For reasons I don't understand,
+! ****** we have to set the margins to zero here
+! ****** in order for Ghostview to do landscape display right.
+! ******/
+! #if 0
+! m[0] = m[1] = m[2] = m[3] = 0;
+! #endif
+!
+! gx_device_set_margins((gx_device *)xdev, m, false);
+! }
+!
+ } else if (xdev->pwin == (Window)None) {
+ eprintf("gs: Cannot get ghostview property.\n");
+ exit(1);
+--- 319,329 ----
+
+ /* The following sets the imageable area according to the */
+ /* bounding box and margins sent by ghostview. */
+! xdev->ImagingBBox[0] = llx - left_margin;
+! xdev->ImagingBBox[1] = lly - bottom_margin;
+! xdev->ImagingBBox[2] = urx + right_margin;
+! xdev->ImagingBBox[3] = ury + top_margin;
+! xdev->ImagingBBox_set = true;
+ } else if (xdev->pwin == (Window)None) {
+ eprintf("gs: Cannot get ghostview property.\n");
+ exit(1);
+
+----------
+
+13. I am trying to display PostScript specials with -DPS_GS, but
+ instead I get the message `gs: gs: Malformed ghostview color property.'
+
+xdvi needs at least version 2.6.2 of ghostscript. It will also run with
+ghostscript 2.6.1, provided you have applied fixes 1-4. This particular
+error message means that you are running gs 2.6.1 without fixes 1-4.
+Probably you should get a newer version of ghostscript.
+
+----------
+
+14. What is this "_get_wmShellWidgetClass undefined" error?
+
+ In SunOS 4.1.2 Sun fixed a shared-library bug in ld which conflicts
+with the way X builds the shared Xmu library, causing these symbols, notably,
+to be undefined when building some X11 clients on SunOS 4.1.[23]:
+ _get_wmShellWidgetClass
+ _get_applicationShellWidgetClass
+Compiling "-Bstatic -lXmu -Bdynamic" is overkill; be sure to set
+OSTeenyVersion correctly in the config/sun.cf file and rebuild X11R5.
+
+To solve the problem if you are using OpenWindows 3.0 (X11R4-based Xt), please
+contact your local Sun office and request the following patches:
+
+Patch i.d. Description
+100512-02 4.1.x OpenWindows 3.0 libXt Jumbo patch
+100573-04 OpenWindows 3.0: xstdcmap fails to set XStandardColomap for
+ 24-bit machines [this also fixes bug 1087332, "With patched
+ ld and libc, customer is getting undefined symbols"]
+
+[Greg Earle, earle@Sun.COM; 7/92]
+
+A source patch for use with the X11R4 libraries was developed by Conrad
+Kimball (cek@sdc.boeing.com); it retrofits into R4 some fixes made in R5 to
+get around this problem. The patch is on ftp.x.org in [1/93]
+ contrib/X11R4_sunos4.1.2_patch_version3.Z
diff --git a/INSTALL b/INSTALL
@@ -0,0 +1,543 @@
+INSTALLATION INSTRUCTIONS
+
+ xdvi now uses a `configure' shell script to guess correct values for
+various system-dependent variables used during compilation. The mechanism
+it uses to implement those values depends on whether imake is being used
+or not, but in both cases it creates a file `config.h' that is included
+by the C source files. It also creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'. If
+so, see the file `xautocnf.txt' for details on some custom modifications
+to autoconf.
+
+ xdvi can be installed either with the standard X tool `imake,' or with
+just plain `make.' Follow the directions in the appropriate section of
+this file.
+
+ EXCEPTION: Users of using teTeX should go directly to the section
+`COMPILING FOR USE WITH TETEX' below.
+
+
+COMPILING WITH MAKE
+
+To compile and install with make, do the following:
+
+ 1. `cd' to the directory containing the package's source code and type:
+
+ ./configure --datadir=[your texmf tree]
+
+ to configure the package for your system. If you're using `csh' on
+ an old version of System V, you might need to type
+
+ sh ./configure --datadir=[your texmf tree]
+
+ instead to prevent `csh' from trying to execute `configure' itself.
+
+ You may want to run `configure' with additional arguments to indicate
+ where it is to be installed, where the X Window System libraries
+ and include files are, and what program features are to be enabled
+ or disabled. See the section `CONFIGURE SCRIPT OPTIONS' for
+ details.
+
+ While running, `configure' prints some messages telling which
+ features it is checking for. When done, it creates a Makefile
+ and a file config.h containing the options it has determined.
+
+ 2. Compile xdvi:
+
+ make
+
+ 3. Try out xdvi.
+
+ If the settings in Step 1 are incorrect, then you can use the
+ corresponding environment variables to quickly try out different
+ values. Then go back to Step 1.
+
+ 4. Install by typing:
+
+ make install
+
+ 5. If you are compiling for several architectures, type
+
+ make archclean
+
+ and repeat the above steps on each different machine.
+
+ 6. To enable xdvi as a helper application from within the browser, follow
+ the instructions given in the man page for xdvizilla.
+
+
+COMPILING WITH IMAKE
+
+This will probably not work with X11R4 and earlier.
+
+To compile and install with imake, do the following:
+
+ 1. `cd' to the directory containing the package's source code.
+
+ 2. Edit the Imakefile according to the directions contained in that file.
+
+ 3. Create the Makefile by typing:
+
+ xmkmf
+
+ 4. Compile xdvi:
+
+ make depend
+ make
+
+ 5. Try out xdvi.
+
+ If the settings in Step 2 are incorrect, then you can use the
+ corresponding environment variables to quickly try out different
+ values. Then go back to Step 2.
+
+ 6. Install by typing:
+
+ make install install.man
+
+ 7. If you are compiling for several architectures, type
+
+ make archclean
+
+ and repeat the above steps on each different machine.
+
+ 8. To enable xdvi as a helper application from within the browser, follow
+ the instructions given in the man page for xdvizilla.
+
+ 9. If you have made any changes to config.xdvi (this is rare), then you
+ should install it manually in the dvips/config subdirectory of an
+ appropriate texmf tree. Remember to run mktexlsr again.
+
+CONFIGURE SCRIPT OPTIONS
+
+ The `configure' script is similar to others created by GNU autoconf,
+ except that it has been modified to support the different needs of
+ X applications. It recognizes the following options to control how
+ it operates:
+
+ --help
+ Print a summary of the options to `configure', and exit.
+
+ --x-top=DIR
+ Look for X include files in directory DIR/include and for X libraries
+ in directory DIR/lib. This is a convenient replacement for
+ the options --x-includes and --x-libraries.
+
+ --aux-top=DIR
+ Look for additional X include files in DIR/include and library files
+ in DIR/lib. This is useful, for example, if a locally installed
+ toolkit is being used.
+
+ --prefix=DIR
+ This option determines default values for the --bindir and --mandir
+ options. The default value is the directory specified in --x-top
+ (if one was given); otherwise /usr/local.
+
+ --bindir=DIR
+ Install the xdvi executable in DIR. By default, it will be placed
+ in the directory PREFIX/bin, where PREFIX is the value of the
+ --prefix option.
+
+ --mandir=DIR
+ Install the xdvi manual page in DIR/man1. By default, it will be
+ placed in the directory PREFIX/man/man1, where PREFIX is the value
+ of the --prefix option.
+
+ --datadir=DIR
+ Install the file config.xdvi in DIR/dvips/config. This should be set
+ whenever configuring xdvi. Normally DIR will be the texmf tree that is
+ to contain most of the files that TeX uses; e.g.,
+ /usr/local/texlive/2013/texmf-dist . If TeX is already installed,
+ then --datadir="`kpsewhich -var-value TEXMFMAIN`" should work.
+
+ --x-includes=DIR
+ Look for X include files in directory DIR.
+
+ --x-libraries=DIR
+ Look for X libraries in directory DIR.
+
+ --with-x-toolkit=PKG
+ --without-x-toolkit
+ Use the PKG toolkit for xdvi. PKG may be `xaw' (use the Xaw
+ toolkit), `xaw3d' (use the Xaw3d toolkit as a drop-in replacement for
+ Xaw), `motif' (use the Motif toolkit), or `no' (use raw X calls).
+ By default, xdvi will use the Xaw toolkit. `--without-x-toolkit'
+ is the same as `--with-x-toolkit=no'.
+
+ --enable-freetype[=DIR]
+ --disable-freetype
+ Use the FreeType library in xdvi. This allows xdvi to use scalable
+ PostScript fonts instead of font files that must be created for each
+ size at which the font is to be used. (This is enabled by default.)
+
+ --disable-grey
+ Disable greyscale anti-aliasing for displaying shrunken bitmaps.
+ (This is enabled by default.)
+
+ --disable-color
+ Disable support for dvips-style color specials. (This is enabled
+ by default.)
+
+ --disable-buttons
+ Disable the placement of radio buttons on the right side of the
+ window for commonly used commands. This option is automatically
+ disabled when compiling without a toolkit.
+
+ --disable-make-pk
+ If xdvi is compiled without disabling this option, it will use a
+ script called `mktexpk' or `MakeTeXPK' to call Metafont to render
+ a font at the desired size if that size is not already available.
+ This option turns off this feature.
+
+ --enable-make-pk=PATH
+ Specifies PATH as the name of the script for dynamically creating
+ font pixel files. This is the default value of the XDVIMAKEPK
+ environment variable; see the discussion of XDVIMAKEPK in the manual
+ page for more information.
+
+ --enable-old-make-pk
+ --enable-old-make-pk=PATH
+ Use an old `MakeTeXPK' script instead of `mktexpk' to dynamically
+ create font pixel files. If given, PATH is as in `--enable-make-pk';
+ if not given, the default is `MakeTeXPK.' This option supersedes
+ the `--enable-make-pk' option.
+
+ --enable-gf
+ Enable support for Metafont `gf' font pixel files. (The `pk' format
+ for font pixel files is always enabled.)
+
+ --enable-ps-gs
+ --enable-ps-gs=PATH
+ Enable use of Ghostscript<TM> to render PostScript<TM> specials.
+ Your system must have Ghostscript installed for this to work.
+ Versions earlier than 2.6.1 have not been tested with xdvi. The
+ PATH is the path of the ghostscript executable; "gs" by default.
+ This option can be used in combination with either of the next two
+ `--enable-ps-' options. If one of them is enabled, then they take
+ precedence over Ghostscript.
+
+ --enable-ps-dps
+ Enable use of Display PostScript<TM> to render PostScript specials.
+ Your system must have DPS for this to work.
+
+ --enable-ps-news
+ Enable use of NeWS server to display PostScript specials. Your
+ system must have the NeWS include files and libraries for this to
+ compile; the xdvi binary can be run with either a standard X server
+ or the NeWS server, but in the former case the code generated by
+ PS_NEWS will have no effect. NOTE: This option refers only to
+ OpenWindows versions 3.1 (possibly 3.2) and earlier (running under
+ SunOS 4.x). If you are using Solaris 2, then you should use PS_DPS
+ instead.
+
+ --enable-config-file=PATHLIST
+ Enable use of a configuration file in xdvi. The PATHLIST should be
+ a colon-separated list of directories to be searched for a
+ configuration file named `texmf.cnf.'
+
+ --enable-self-auto
+ --enable-self-auto=PATHLIST
+ Enable configuration files; also enable special symbols SELFAUTODIR
+ and SELFAUTOPARENT in the config file. This option also selects for
+ the use of config files; if no PATHLIST is given, the value
+ ".:$SELFAUTOLOC:$SELFAUTODIR:$SELFAUTOPARENT
+ :$SELFAUTODIR/share/texmf/web2c:$SELFAUTOPARENT/share/texmf/web2c
+ :$SELFAUTODIR/texmf/web2c:$SELFAUTOPARENT/texmf/web2c
+ :$TETEXDIR:$TEXMF/web2c" (without the line breaks) is used.
+
+ --enable-extra-app-defaults
+ --enable-extra-app-defaults=PATHLIST
+ Selects `--enable-self-auto' (with PATHLIST, if given); in addition,
+ it causes xdvi to look for a second app-defaults file, either in the
+ root directory of the texmf tree, or in the xdvi or web2c
+ subdirectories. This option is primarily intended for copies of xdvi
+ that are to be distributed with precompiled TeX distributions such as
+ teTeX. This option is not available when compiling without a toolkit.
+
+ --enable-dosnames
+ Check also for pk or gf files with names like dpi329/cmr10.pk
+ (instead of cmr10.329pk).
+
+ --enable-a4
+ Set the default paper size to `a4' instead of 8.5 x 11 inches.
+ Also change the default unit from inches to centimeters.
+
+ --enable-texxet
+ Enable support for dvi op-codes 250 and 251 (used for typesetting
+ right-to-left languages).
+
+ --with-mfmode=MODE:DPI
+ Set the default value for the `-mfmode' option to `MODE:DPI'.
+ (This is the Metafont mode used when creating fonts.) If neither this
+ option nor `--without-mfmode' is selected, then the default value
+ is `cx:300'.
+
+ --without-mfmode
+ Indicate that the `-mfmode' option has no default value.
+
+ --with-tetex
+ --with-tetex=PATHLIST
+ This causes --enable-ps-gs, --enable-dosnames, and
+ --enable-extra-app-defaults to be set by default (their values can be
+ overridden explicitly). If a PATHLIST is given, it is passed to
+ the --enable-extra-app-defaults argument.
+
+ --with-default-texmf-path=PATH
+ Set the default value of the TEXMF environment variable.
+
+ --with-default-font-path=PATH
+ Set the default value of the XDVIFONTS environment variable.
+
+ --with-default-vf-path=PATH
+ Set the default value of the VFFONTS environment variable.
+
+ --with-default-header-path=PATH
+ Set the default value of the XDVIHEADERS environment variable.
+
+ --with-default-fig-path=PATH
+ Set the default value of the XDVIPICTS environment variable.
+
+ --with-default-source-path=PATH
+ Set the default value of the XDVISOURCES environment variable.
+
+ --with-default-dvips-cf-path=PATH
+ Set the default value of the XDVITYPE1CONFIG environment variable.
+
+ --with-default-fontmap-path=PATH
+ Set the default value of the XDVIFONTMAPS environment variable.
+
+ --with-default-enc-path=PATH
+ Set the default value of the XDVIENCS environment variable.
+
+ --with-default-type1-path=PATH
+ Set the default value of the XDVIT1FONTS environment variable.
+
+ --with-default-gs-lib-path=PATH
+ Set the default value of the XDVI_GS_LIB environment variable.
+
+ --with-default-dvips-path=CMD
+ Set the default value of the dvipsPath resource, which gives the
+ command to use for printing (not applicable if compiling without the
+ X Toolkit).
+
+
+ADDITIONAL OPTIONS
+
+ Some additional rarely-used options may also be set in the `configure'
+ script. To do so, set the `CPPFLAGS' variable explicitly. This can
+ be done as in the following examples:
+
+ If using make and using the C-shell (/bin/csh, /bin/tcsh, etc.):
+
+ env CPPFLAGS='-DALTFONT="ptmr8r"' ./configure
+
+ If using make and using a Bourne-like shell (/bin/sh, /bin/bash,
+ /bin/ksh, etc.):
+
+ CPPFLAGS='-DALTFONT="ptmr8r"' ./configure
+
+ If using imake: See the instructions for setting DEFS in the Imakefile.
+
+ (Of course, options such as --prefix may be supplied to `configure'
+ as well.)
+
+ The following options are supported in CPPFLAGS:
+
+ Option Flag Explanation
+ ----------- -----------
+
+ ALTFONT Default font to use if the font named in the dvi file
+ cannot be found. Can be set to NULL. By default,
+ it is "cmr10".
+ BDPI Default number of pixels per inch to use. It is better
+ to set this value by setting the default metafont mode
+ instead.
+ DEFAULT_FONT_SIZES Colon-separated list of font sizes to look for if the exact size cannot be found, and if automatic
+ generation of pixel files fails. See the description
+ of the XDVISIZES environment variable in the manual
+ page for more details.
+ SHRINK Default value for the -s option (shrink factor).
+ If not specified, the default will be 3.
+ XDVIFONTS_ONLY Never check the TEXFONTS environment variable.
+ Normally xdvi checks TEXFONTS if the XDVIFONTS variable
+ is not set. This option is recommended if the version
+ of TeX in use requires that the TEXFONTS variable be
+ set. See the relevant paragraph in xdvi-man.sed for
+ more details. This option turns off that paragraph.
+ MKPK_REDIRECT Enables use of the `%r' specifier for MakeTeXPK scripts
+ that support sending the file name to a numbered file
+ descriptor instead of standard output. This implies
+ -DMAKEPK.
+ NOQUERY Set this if you have trouble compiling the definition
+ of drawingWidgetClass.
+ TICKTMP Directory for temporary files created by PostScript
+ specials that call for the output of a command (e.g.,
+ compressed .eps files). Default is "/tmp".
+ TICKCACHESIZE Maximum number of such files to be stored at a time
+ (this is dynamically increased if more than this number
+ occur on a single page). Default is 3.
+
+
+SETTING PATHS
+
+ Read the ENVIRONMENT section of xdvi-man.sed to determine the correct
+ default values for the TEXMF and XDVIFONTS environment variables.
+ These should be specified as arguments to `./configure' (which can
+ be set in the Imakefile, if you are going that route).
+ If your site uses virtual fonts, do the same thing with the
+ VFFONTS variable. Note that support of virtual fonts in xdvi
+ does not include support of built-in PostScript<tm> fonts.
+ Usually you will want to use the same font files as your printer;
+ given a choice, however, it has been suggested that write-white
+ fonts look better.
+
+ If you are compiling with PostScript specials enabled, then
+ you also need to set default values for the XDVIPICTS and
+ XDVIHEADERS variables. These should contain colon-separated
+ lists of directories. The XDVIPICTS variable gives the list
+ of directories to search for PostScript figures; typically
+ this is the same as the default input directory used by TeX.
+ The XDVIHEADERS variable gives the default list of directories
+ to search for PostScript headers. If you also install dvips,
+ then it is recommended that XDVIPICTS and XDVIHEADERS be set to the
+ same values as FIGPATH and HEADERPATH in the Makefile for dvips.
+
+ If you are compiling with a configuration file, then the paths
+ described above are less important, since they can be set in the
+ configuration file.
+
+
+NOTES FOR SPECIFIC OPERATING SYSTEMS
+
+ This section is probably not necessary, and will be deleted eventually.
+ If you find that part of it is needed, please let me know by sending
+ e-mail to vojta@math.berkeley.edu.
+
+ SGI/IRIX 4: You can substantially reduce the size of the xdvi binary
+ by linking with -lX11_s instead of -lX11 and -lXt_s instead of -lXt.
+ This requires some hacking in the Makefile.
+
+ SGI/IRIX 5.1: If you are not using imake, add
+
+ -cckr -float -KPIC -G 0 -Wf,-XNh2000
+
+ to CFLAGS when configuring (by treating CFLAGS similarly to
+ CPPFLAGS, as above).
+
+ Sun/Solaris 2.x: If you are using the X11R6 server (as opposed to the
+ OpenWindows server) and are running Solaris 2.4 or earlier, then
+ a bug in the threads library may cause xdvi to fail to work
+ (it won't respond to keystrokes or may not display the page).
+ If you experience this problem, edit config.h after running
+ `configure,' and undefine HAVE_STREAMS.
+ Or, better yet, try to get the appropriate patch from Sun, since
+ you are probably having other problems with X, too.
+
+ IBM RS6000: Some of the libraries are in non-obvious places:
+
+ libXmu /usr/lpp/X11/Xamples/lib/Xmu/libXmu.a
+ libXaw /usr/lpp/X11/Xamples/lib/Xaw/libXaw.a
+
+ These should be moved to /usr/lib or some more reasonable place
+ (or use symlinks), and ditto for the include files, which are
+ initially placed in /usr/lpp/X11/Xamples/include.
+
+
+COMPILING FOR USE WITH TETEX
+
+ If you are replacing the version of xdvi that comes with the teTeX
+ distribution of TeX (these instructions work with Versions 0.4 and 1.0),
+ you need to:
+
+ 1. Determine where the xdvi binary and manual page are to go. If you
+ have the `locate' command installed on your system, you can type
+ `locate xdvi' to find them.
+
+ 2. Run the following command to configure this version of xdvi.
+ The --bindir and --mandir arguments should be the directories
+ determined in Step 1. Note, however, that the --mandir directory
+ should end in `/man', not in `/man/man1'.
+
+ Also, if you found that xdvi and xdvi.1 were located in /usr/bin
+ and /usr/man/man1, respectively, then the `--bindir' and `--mandir'
+ arguments should be omitted. In that case `configure' will put them in
+ /usr/local/bin and /usr/local/man(/man1) by default, and this version
+ of xdvi will supersede the system version because presumably
+ /usr/local/bin and /usr/local/man will be searched before /usr/bin
+ and /usr/man. This paragraph applies, for example, to the teTeX that
+ comes with Debian Linux systems. (As a general rule, locally installed
+ programs should go into /usr/local.)
+
+ ./configure --with-tetex --bindir=/usr/local/teTeX/bin/i386-linux \
+ --mandir=/usr/local/teTeX/man
+
+ In the above example, the `--bindir' and `--mandir' arguments should
+ be correct for a locally installed version of teTeX.
+
+ If you are using teTeX version 0.4, you should also include
+ --enable-old-make-pk in the above arguments.
+
+ You may also, of course, use other `configure' options in addition.
+
+ 3. Locate the file texmf.cnf and add the following lines. They must go
+ before any of these symbols are defined without the .XDvi suffix:
+
+ PKFONTS.XDvi = .:$TEXMF/%s:$VARTEXFONTS/pk/{%m,modeless}//
+ VFFONTS.XDvi = .:$TEXMF/%s
+ PSHEADERS.XDvi = .:$TEXMF/%q{dvips,fonts/type1}//
+ TEXPICTS.XDvi = .:$TEXMF/%q{dvips,tex}//
+
+ In teTeX 0.4, use $TEXMFS instead of $TEXMF and VARFONTS instead of
+ VARTEXFONTS in the above lines.
+
+ You may also define MFMODE, PIXELSPERINCH, SHRINKFACTOR, and PAPER in
+ texmf.cnf. For example, if your $TEXMF/xdvi/XDvi file contains
+
+ XDvi*mfmode: ljfour
+ XDvi*pixelsPerInch: 600
+ XDvi*shrinkFactor: 4
+ XDvi*paper: letter
+
+ then the following lines can go into texmf.cnf:
+
+ MFMODE = ljfour
+ PIXELSPERINCH = 600
+ SHRINKFACTOR = 4
+ PAPER = letter
+
+ You can also put lines such as:
+
+ SHRINKBUTTON1 = 1
+ SHRINKBUTTON2 = 3
+ SHRINKBUTTON3 = 4
+ SHRINKBUTTON4 = 6
+
+ into texmf.cnf to change the labels on the buttons. You will probably
+ need to be root to edit texmf.cnf.
+
+ 4. Type "make" and see if it produces any error messages. If it does,
+ study the documentation above, make whatever changes to the Makefile
+ seem appropriate, then "make clean" and "make" again.
+
+ 5. Before installing xdvi, you may remove `xdvi.bin' from the binary
+ directory. Or, if you wish to still be able to run the version of
+ xdvik that comes with teTeX, rename `xdvi' to `xdvik' and leave
+ `xdvi.bin' alone. Omit this step if you omitted the `--bindir'
+ and `--mandir' arguments in Step 2. In that case, you will be able
+ to run the old xdvi by using its full path: `/usr/bin/xdvi ...'.
+
+ 6. Install xdvi and its man page by typing:
+
+ make install
+
+ You will probably need to do this as root.
+
+ 7. To enable xdvi as a helper application from within the browser, follow
+ the instructions given in the man page for xdvizilla.
diff --git a/Imakefile b/Imakefile
@@ -0,0 +1,332 @@
+/*
+ * Imakefile for dvi previewer. Edit the file according to the enclosed
+ * instructions before running ``xmkmf.''
+ *
+ * Some of these instructions refer to ``uncommenting'' a line. To do this,
+ * delete the word ``XCOMM'' and the space immediately following it.
+ */
+
+/* We need this first. (Do not change this.) */
+
+#ifndef XCOMM
+#define XCOMM #
+#endif
+
+/*
+ * By default, xdvi is compiled with the Athena widgets (Xaw).
+ * If you want to compile xdvi with a different widget set or without
+ * the X toolkit, you may comment out or uncomment one of the following lines.
+ *
+ * Most likely you will not want to change anything here.
+ */
+
+#define XAW /* This selects compilation with the Athena toolkit. */
+XCOMM #define MOTIF /* This selects compilation with the Motif toolkit. */
+
+/*
+ * If you have additional X include files and libraries in another location
+ * (for example, if the toolkit is not contained in the X source tree)
+ * then the top directory can be set here. To do so, uncomment the line
+ * and put the path in the quotes.
+ *
+ * EXAMPLE:
+ * #define AUX_TOP "/usr/dt"
+ */
+
+XCOMM #define AUX_TOP "PUT THE TOP DIRECTORY HERE"
+
+/*
+ * To enable support for the FreeType library (which allows xdvi to use
+ * scalable PostScript fonts instead of font files that must be created for
+ * each size at which the font is to be used), uncomment the following three
+ * lines, and put the output of freetype-config --cflags and
+ * freetype-config --libs in the second and third line, respectively.
+ *
+ * EXAMPLE:
+ * #define FREETYPE
+ * #define FT_INCLUDES -I/usr/include/freetype2
+ * #define FT_LDFLAGS -L/usr/lib/x86_64-linux-gnu -lfreetype -lz
+ */
+
+XCOMM #define FREETYPE
+XCOMM #define FT_INCLUDES (put the output of freetype-config --cflags here)
+XCOMM #define FT_LDFLAGS (put the output of freetype-config --libs here)
+
+/*
+ * To enable support for GF-format pixel files, uncomment the following line.
+ */
+
+XCOMM #define USE_GF
+
+/*
+ * PostScript options:
+ *
+ * xdvi supports PostScript specials by several mechanisms. You may select
+ * more than one of the following; it will choose the best one available at
+ * run-time.
+ *
+ * To enable PostScript support via Display PostScript, uncomment the following
+ * line:
+ */
+
+XCOMM #define PS_DPS
+
+/*
+ * To enable PostScript support via NeWS (SunOS 4 only), uncomment the
+ * following line:
+ */
+
+XCOMM #define PS_NEWS
+
+/*
+ * To enable PostScript support via ghostscript, uncomment the following line:
+ */
+
+XCOMM #define PS_GS
+
+/*
+ * If you have selected PS_GS and wish to have the path to Ghostscript
+ * compiled into the xdvi binary, uncomment and change the following line
+ * to contain the full path. This is optional.
+ *
+ * EXAMPLE:
+ * #define GSPATH "/usr/local/bin/gs"
+ */
+
+XCOMM #define GSPATH "PUT THE PATH TO GS HERE"
+
+/*
+ * Other options to the configure script can be put here. These may be
+ * chosen from the following list; see the INSTALL file for details.
+ *
+ * --disable-grey
+ * --disable-buttons
+ * --disable-make-pk
+ * --enable-make-pk=PATH
+ * --enable-old-make-pk
+ * --enable-old-make-pk=PATH
+ * --enable-config-file=PATHLIST
+ * --enable-self-auto
+ * --enable-self-auto=PATHLIST
+ * --enable-extra-app-defaults
+ * --enable-extra-app-defaults=PATHLIST
+ * --enable-dosnames
+ * --enable-a4
+ * --enable-texxet
+ * --with-mfmode=MODE:DPI
+ * --without-mfmode
+ * --with-default-texmf-path=PATH
+ * --with-default-font-path=PATH
+ * --with-default-vf-path=PATH
+ * --with-default-header-path=PATH
+ * --with-default-fig-path=PATH
+ *
+ * EXAMPLE:
+ * #define CONFIG_ARGS --aux-top=/usr/dt --disable-buttons
+ */
+
+#define CONFIG_ARGS
+
+/*
+ * If any options need to be set via the CPPFLAGS variable (as mentioned in
+ * the INSTALL file), they can be set here.
+ *
+ * EXAMPLE:
+ * DEFS = -DALTFONT="\"ptmr8r\""
+ *
+ * Note the handling of quotes. This is because the Imakefile is processed
+ * by cpp, which may choke on \".
+ */
+
+DEFS =
+
+/*----------------------------------------------------*\
+ *
+ * End of user edited part.
+ * No changes beyond this point should be necessary.
+ *
+\*----------------------------------------------------*/
+
+#ifdef XAW
+ POPUPS_C = popups.c
+ POPUPS_O = popups.o
+ LOCAL_LIBRARIES=$(DPS_LIBS) $(NEWS_LIBS) XawClientLibs
+ DEPLIBS=XawClientDepLibs
+ LINTLIBS=$(LINTXAW) $(LINTXMU) $(LINTXTOOL) \
+ $(LINTEXTENSIONLIB) $(LINTXLIB) $(MATHLIB)
+ WITH_TOOLKIT =
+#elif defined MOTIF
+ /* I'm just guessing about how to handle Motif within an Imakefile. */
+ POPUPS_C = popups.c
+ POPUPS_O = popups.o
+ LOCAL_LIBRARIES=$(DPS_LIBS) $(NEWS_LIBS) XmClientLibs
+ DEPLIBS=XmClientDepLibs
+ LINTLIBS=$(LINTXM) $(LINTXMU) $(LINTXTOOL) \
+ $(LINTEXTENSIONLIB) $(LINTXLIB) $(MATHLIB)
+ WITH_TOOLKIT = --with-x-toolkit=motif
+#else /* no toolkit */
+ POPUPS_C =
+ POPUPS_O =
+ LOCAL_LIBRARIES=$(DPS_LIBS) $(NEWS_LIBS) $(XLIB)
+ DEPLIBS=$(DEPXLIB)
+ LINTLIBS=$(LINTXLIB) $(MATHLIB)
+ WITH_TOOLKIT = --without-x-toolkit
+#endif
+
+#ifdef AUX_TOP
+ AUXTOP = AUX_TOP
+ AUXTOP_INCLUDES = -I$(AUXTOP)/include
+ AUXTOP_LDFLAGS = -L$(AUXTOP)/lib
+ LD_RUN_PATH = $(AUXTOP)/lib
+#endif
+
+#ifdef FREETYPE
+ FT_C = ft.c
+ FT_O = ft.o
+ DISABLE_FREETYPE =
+#else
+ FT_C =
+ FT_O =
+ DISABLE_FREETYPE = --disable-freetype
+#undef FT_INCLUDES
+#define FT_INCLUDES
+#undef FT_LDFLAGS
+#define FT_LDFLAGS
+#endif
+
+#ifdef USE_GF
+ GF_C = gf.c
+ GF_O = gf.o
+ ENABLE_GF = --enable-gf
+#else
+ GF_C =
+ GF_O =
+ ENABLE_GF =
+#endif
+
+#ifdef PS_DPS
+ PSDPS_C = psdps.c
+ PSDPS_O = psdps.o
+ ENABLE_PS_DPS = --enable-ps-dps
+ DPS_LIBS = -ldps
+#else
+ PSDPS_C =
+ PSDPS_O =
+ ENABLE_PS_DPS =
+ DPS_LIBS =
+#endif
+
+#if defined(PS_DPS) && defined(SunArchitecture) && OSMajorVersion == 5
+ OPENWIN_DPS_INCLUDE_HACK = -I/usr/openwin/include/X11
+#else
+ OPENWIN_DPS_INCLUDE_HACK =
+#endif
+
+#ifdef PS_NEWS
+ PSNEWS_C = psnews.c
+ PSNEWS_O = psnews.o
+ ENABLE_PS_NEWS = --enable-ps-news
+ NEWS_LIBS = -u _xv_psview_pkg -lxvps -lxview -lcps -lolgx
+#else
+ PSNEWS_C =
+ PSNEWS_O =
+ ENABLE_PS_NEWS =
+ NEWS_LIBS =
+#endif
+
+#ifdef PS_GS
+ PSGS_C = psgs.c
+ PSGS_O = psgs.o
+#ifdef GSPATH
+ ENABLE_PS_GS = --enable-ps-gs=GSPATH
+#else
+ ENABLE_PS_GS = --enable-ps-gs
+#endif
+#else
+ PSGS_C =
+ PSGS_O =
+ ENABLE_PS_GS =
+#endif
+
+#if defined(PS_DPS) || defined(PS_NEWS) || defined(PS_GS)
+ PSHEADER_C = psheader.c
+ PSHEADER_O = psheader.o
+#else
+ PSHEADER_C =
+ PSHEADER_O =
+#endif
+
+OPT_SRCS = $(POPUPS_C) $(GF_C) $(PSHEADER_C) $(PSDPS_C) $(PSNEWS_C) $(PSGS_C) \
+ $(FT_C)
+OPT_OBJS = $(POPUPS_O) $(GF_O) $(PSHEADER_O) $(PSDPS_O) $(PSNEWS_O) $(PSGS_O) \
+ $(FT_O)
+
+SRCS=xdvi.c events.c dvi-init.c dvi-draw.c special.c font-open.c filefind.c \
+ pk.c vf.c util.c $(OPT_SRCS)
+OBJS=xdvi.o events.o dvi-init.o dvi-draw.o special.o font-open.o filefind.o \
+ pk.o vf.o util.o $(OPT_OBJS)
+
+MATHLIB = -lm
+SYS_LIBRARIES = $(MATHLIB)
+DEFINES = $(DEFS) $(OPENWIN_DPS_INCLUDE_HACK)
+INCLUDES = $(AUXTOP_INCLUDES) FT_INCLUDES
+LOCAL_LDFLAGS = $(AUXTOP_LDFLAGS) FT_LDFLAGS
+
+all::xdvi.man
+
+depend::config.h $(PSHEADER_C)
+
+config.h: Imakefile configure
+ echo $(DEFS) > conftest; \
+ CC="$(CC)" CPPFLAGS="`cat conftest`" ./configure --imake \
+ --x-top=$(PROJECTROOT) $(WITH_TOOLKIT) $(ENABLE_GF) $(ENABLE_PS_DPS) \
+ $(ENABLE_PS_NEWS) $(ENABLE_PS_GS) $(DISABLE_FREETYPE) CONFIG_ARGS
+
+ComplexProgramTarget(xdvi)
+
+psheader.c: psheader.txt squeeze
+ ./squeeze psheader.txt psheader.c
+
+squeeze: squeeze.c
+ $(CC) $(CFLAGS) -o squeeze squeeze.c
+
+xdvi.man: xdvi-man.sed mksedscript Makefile config.h
+ ./mksedscript $(DEFS) > sedscript
+ sed -f sedscript < xdvi-man.sed > xdvi.man
+
+check:
+
+install::
+ $(INSTALL) $(INSTALLFLAGS) $(INSTPGMFLAGS) xdvizilla $(DESTDIR)$(BINDIR)/xdvizilla
+
+install.man::
+ $(INSTALL) $(INSTALLFLAGS) $(INSTMANFLAGS) xdvizilla.1 $(DESTDIR)$(MANDIR)/xdvizilla.$(MANSUFFIX)
+
+uninstall:
+ -$(RM) $(DESTDIR)$(BINDIR)/xdvi $(DESTDIR)$(MANDIR)/xdvi.$(MANSUFFIX)
+ -$(RM) $(DESTDIR)$(BINDIR)/xdvizilla
+ -$(RM) $(DESTDIR)$(MANDIR)/xdvizilla.$(MANSUFFIX)
+
+mostlyclean:
+ -$(RM) *.o xdvi xdvi.man core sedscript *~
+
+archclean:
+ -$(RM) *.o xdvi Makefile config.h config.cache config.status config.log
+
+clean::
+ -$(RM) xdvi.man sedscript psheader.c squeeze
+
+distclean:: clean
+ -$(RM) Makefile config.h config.cache config.status config.log
+
+veryclean: distclean
+
+realclean: distclean
+
+maintainer-clean: veryclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ rm -f config.hin configure
+
+.PHONY: all uninstall mostlyclean archclean distclean veryclean realclean \
+maintainer-clean
diff --git a/MAKE-VMS.COM b/MAKE-VMS.COM
@@ -0,0 +1,217 @@
+$! MAKE-VMS.COM
+$! A DCL `Make' procedure for compiling and linking XDVI.
+$!
+$! If you do want only the plain vanilla Xdvi just type @make_vms
+$!
+$!
+$! At the moment only support for DPS is really working to display inline
+$! postscript. To compile with DPS invoke the com as @make_vms dps
+$! You'll need a post-June 95 version of the xvmsutils installed at your
+$! site (This package is available at
+$! http://axp616.gsi.de:8080/www/vms/xvmsutils.html)
+$!
+$! If you want to compile using the Xaw lib to get buttons and scrollbars on
+$! Xdvi you will have to invoke the build as @make_vms "" tool
+$! (or @make_vms dps tool). In this case you need the Xaw3d lib installed,
+$! which you might get from http://axp616.gsi.de:8080/www/vms/xaw.html.
+$! Please edit the option file created during installation of the package
+$! to remove all references to shareable image and copy it to the dire where
+$! Xdvi resides with a name of xaw3dalpha.opt or xaw3dvax.opt.
+$!
+$! In case of problems with the install you might contact me at
+$! m.zinser@gsi.de (preferred) or eurmpz@eur.sas.com
+$!
+$!
+$ ON ERROR THEN GOTO EXIT
+$ ON CONTROL_Y THEN GOTO EXIT
+$ OLD_VERIFY = f$verify (0)
+$!
+$ MAY_USE_DECC = 1
+$!
+$ IF F$GETSYI("HW_MODEL") .GE. 1024
+$ THEN
+$ ARCH_NAME="Alpha"
+$ ARCH_PREF="AXP_"
+$ HAVE_DECC_VAX = 0
+$ USE_DECC_VAX = 0
+$ CC="CC/stand=VAX/ansi/ext=comm/obj=.''ARCH_PREF'obj"
+$ WRITE SYS$OUTPUT "Compiling on Alpha AXP using DECC"
+$ ELSE
+$ ARCH_NAME="VAX"
+$ ARCH_PREF="VAX_"
+$ IF F$search("sys$system:DECC$compiler.exe") .NES. ""
+$ THEN
+$! DECC for VAX available (and maybe VAXC, too!)
+$ HAVE_DECC_VAX = 1
+$ IF HAVE_DECC_VAX .AND. MAY_USE_DECC
+$ THEN
+$! We use DECC:
+$ USE_DECC_VAX = 1
+$ CC="CC/DECC/stand=VAX/ext=comm/obj=.''ARCH_PREF'obj"
+$ ELSE
+$! We use VAXC:
+$ USE_DECC_VAX = 0
+$ CC="CC/VAXC/obj=.''ARCH_PREF'obj"
+$ ENDIF
+$ ELSE
+$! only VAXC available
+$ HAVE_DECC_VAX = 0
+$ USE_DECC_VAX = 0
+$ CC="CC/obj=.''ARCH_PREF'obj"
+$ ENDIF
+$ IF USE_DECC_VAX
+$ THEN
+$ WRITE SYS$OUTPUT "Compiling on VAX using DECC"
+$ ELSE
+$ WRITE SYS$OUTPUT "Compiling on VAX using VAXC"
+$ ENDIF
+$ ENDIF
+$ LDFLAGS = ""
+$ if f$trnlnm("X11").eqs. "" then DEFINE X11 DECW$INCLUDE
+$ if f$trnlnm("SYS").eqs ""
+$ then
+$ IF USE_DECC_VAX .AND. (F$TRNLNM("DECC$LIBRARY_INCLUDE") .NES. "")
+$ THEN
+$ DEFINE SYS DECC$LIBRARY_INCLUDE
+$ ELSE
+$ DEFINE SYS SYS$LIBRARY
+$ ENDIF
+$ endif
+$ if f$trnlnm("DPS").eqs. "" then define dps xdps$include
+$!
+$ ps_dps = ""
+$ ps_gs = ""
+$ tool = "NOTOOL"
+$ IF f$edit(p1,"UPCASE") .eqs. "DPS" THEN ps_dps = "PSDPS"
+$ IF f$edit(p1,"UPCASE") .eqs. "GS" THEN ps_gs = "PSGS"
+$ if f$edit(p2,"UPCASE") .eqs. "TOOL" then tool = "TOOL"
+$!
+$ ps_options = ""
+$ ps_head = ""
+$ varobjs = ""
+$ IF ps_dps .EQS. "PSDPS"
+$ THEN
+$ ps_head = "PSHEADER"
+$ ps_options = ps_options + ", VFORK, PS_DPS"
+$ varobjs = varobjs + "PSDPS.''ARCH_PREF'OBJ, "
+$ ENDIF
+$ IF ps_gs .EQS. "PSGS"
+$ THEN
+$ ps_head = "PSHEADER"
+$ ps_options = ps_options + ", PS_GS"
+$ varobjs = varobjs + "PSGS.''ARCH_PREF'OBJ, "
+$ ENDIF
+$!
+$ OPEN/WRITE optfile VMS_XDVI.'ARCH_PREF'OPT
+$ if (tool.eqs."TOOL") .or. (ps_dps.EQS."PSDPS")
+$ then
+$!
+$! Find out which X-Version we're running. This will fail for older
+$! VMS versions (i.e., v5.5-1). Therefore, choose DECWindows XUI for
+$! default.
+$!
+$ On Error Then GoTo XUI
+$ @sys$update:decw$get_image_version sys$share:decw$xlibshr.exe decw$version
+$ if f$extract(4,3,decw$version).eqs."1.0"
+$ then
+$ write optfile "Sys$share:DECW$DWTLIBSHR.EXE/Share"
+$ endif
+$ if f$extract(4,3,decw$version).eqs."1.1"
+$ then
+$ write optfile "sys$share:decw$xtshr.exe/share"
+$ endif
+$ if f$extract(4,3,decw$version).eqs."1.2"
+$ then
+$ write optfile "sys$share:decw$xtlibshrr5.exe/share"
+$ endif
+$ GoTo MAIN
+$!
+$ XUI:
+$!
+$ write optfile "Sys$share:DECW$DWTLIBSHR.EXE/Share"
+$ MAIN:
+$ endif
+$ IF ps_dps .EQS. "PSDPS"
+$ THEN
+$ write optfile "x11vms:xvmsutils.olb/lib"
+$!
+$ WRITE optfile "sys$share:xdps$dpsclientshr/share"
+$ WRITE optfile "sys$share:xdps$dpsbindingsshr/share"
+$ WRITE optfile "sys$share:xdps$dpslibshr/share"
+$ ENDIF
+$ WRITE optfile "sys$share:decw$xlibshr/share"
+$ if tool .eqs. "TOOL"
+$ then
+$ write optfile "XMULIBSHR/SHARE"
+$ write optfile "XAW3DLIBSHR/SHARE"
+$ endif
+$ IF (ARCH_NAME .EQS. "VAX") .AND. (.NOT. USE_DECC_VAX)
+$ THEN
+$ WRITE optfile "sys$share:vaxcrtl/share"
+$ option_file = "VMS_XDVI.''ARCH_PREF'OPT" ! for linking SQUEEZE
+$ ELSE
+$ option_file = "nl:" ! for linking SQUEEZE
+$ ENDIF
+$ CLOSE optfile
+$ if (tool.eqs."TOOL")
+$ then
+$ copy/nolog xaw3d'arch_name'.opt,VMS_XDVI.'ARCH_PREF'OPT;-1 -
+ VMS_XDVI.'ARCH_PREF'OPT
+$ tool = "TOOL, BUTTONS"
+$ endif
+$!
+$ DEFS = "VMS, 'tool', USE_PK, USE_GF, TEXXET, GREY, MAKEPK'ps_options'"
+$ CC /DEFINE = ('DEFS') DVI_INIT.C
+$ CC /DEFINE = ('DEFS') DVI_DRAW.C
+$ CC /DEFINE = ('DEFS') GF.C
+$ CC /DEFINE = ('DEFS') PK.C
+$ CC /DEFINE = ('DEFS') VF.C
+$ CC /DEFINE = ('DEFS') UTIL.C
+$ If ps_dps .EQS. "PSDPS"
+$ then
+$!
+$! This definition of FIG_PATH and HEADER_PATH is site specific. You may
+$! want to change it!!!
+$!
+$ CC /DEFINE = ('DEFS', "DEFAULT_FONT_PATH=""TEX_FONTS""", -
+ "DEFAULT_VF_PATH=""TEX_VFDIR""", -
+ "DEFAULT_FONT_SIZES=""300/329/360/432/518/622/746""",-
+ "DEFAULT_FIG_PATH=""TEX_INPUTS:,SYS$DISK:""",-
+ "DEFAULT_HEADER_PATH=""DVI_INPUTS:,TEX_INPUTS:,SYS$LOGIN:,SYS$DISK:[]""")-
+ FONT_OPEN.C
+$ else
+$ CC /DEFINE = ('DEFS', "DEFAULT_FONT_PATH=""TEX_FONTS""", -
+ "DEFAULT_VF_PATH=""TEX_VFDIR""", -
+ "DEFAULT_FONT_SIZES=""300/329/360/432/518/622/746""") FONT_OPEN.C
+$ endif
+$ CC /DEFINE = ('DEFS') SPECIAL.C
+$ CC /DEFINE = ('DEFS') EVENTS.C
+$ IF ps_dps .NES. ""
+$ THEN
+$ CC /DEFINE = ('DEFS') PSDPS.C
+$ ENDIF
+$ IF ps_gs .NES. ""
+$ THEN
+$ CC /DEFINE = ('DEFS') PSGS.C
+$ ENDIF
+$ IF ps_head .NES. ""
+$ THEN
+$ CC /DEFINE = ('DEFS') SQUEEZE.C
+$ LINK /EXE=.'ARCH_PREF'EXE SQUEEZE.'ARCH_PREF'OBJ, 'option_file' /OPTION
+$ SQUEEZE := $SYS$DISK:[]SQUEEZE.'ARCH_PREF'EXE
+$ SQUEEZE PSHEADER.TXT PSHEADER.C
+$ CC /DEFINE = ('DEFS') PSHEADER.C
+$ varobjs = varobjs + "PSHEADER.''ARCH_PREF'OBJ,"
+$ ENDIF
+$ CC /DEFINE = ('DEFS') XDVI.C
+$!
+$ LINK 'LDFLAGS'/EXE=.'ARCH_PREF'EXE XDVI.'ARCH_PREF'OBJ, -
+ DVI_INIT.'ARCH_PREF'OBJ, DVI_DRAW.'ARCH_PREF'OBJ, -
+ GF.'ARCH_PREF'OBJ, PK.'ARCH_PREF'OBJ, VF.'ARCH_PREF'OBJ, -
+ UTIL.'ARCH_PREF'OBJ, FONT_OPEN.'ARCH_PREF'OBJ, SPECIAL.'ARCH_PREF'OBJ, -
+ EVENTS.'ARCH_PREF'OBJ, 'varobjs' VMS_XDVI.'ARCH_PREF'OPT/OPTION
+$ DELETE/NOLOG VMS_XDVI.'ARCH_PREF'OPT;*
+$!
+$EXIT:
+$ dummy=f$verify ('old_verify')
+$ EXIT
diff --git a/Makefile.in b/Makefile.in
@@ -0,0 +1,151 @@
+# Makefile.in: prototype Makefile.
+#
+# Makefile for dvi previewer.
+#
+
+SHELL=/bin/sh
+CHMOD=chmod
+RM=rm -f
+MANEXT=1
+
+LINT=lint
+# LINT=$(CC) -c -Wall -Wshadow -Wpointer-arith
+# also maybe -Wcast-qual -Wwrite-strings
+
+CC=@CC@
+CPP=@CPP@ @CPPFLAGS@ @X_CFLAGS@ -I. -I$(srcdir)
+EXEEXT=@EXEEXT@
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+mandir=@mandir@
+srcdir=@srcdir@
+datadir=@datadir@
+VPATH=@srcdir@
+
+dvipsconfdir=/dvips/config
+
+CFLAGS=@CFLAGS@ @CPPFLAGS@ -I. -I$(srcdir)
+X_CFLAGS=@X_CFLAGS@
+EXTRA_CPPFLAGS=@EXTRA_CPPFLAGS@
+
+LDFLAGS=@LDFLAGS@
+X_LDFLAGS=@LDFLAGS@ @x_linker_options@ @X_LIBS@
+X_LIBS=@X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@
+EXTRA_LIBS=@EXTRA_LIBS@
+LIBS=@LIBS@ @MATH_LIB@
+
+SRCS=xdvi.c events.c dvi-init.c dvi-draw.c special.c font-open.c filefind.c \
+ pk.c vf.c util.c@OPT_SRCS@
+OBJS=xdvi.o events.o dvi-init.o dvi-draw.o special.o font-open.o filefind.o \
+ pk.o vf.o util.o@OPT_OBJS@
+
+INSTALL=@INSTALL@
+INSTALL_PROGRAM=@INSTALL_PROGRAM@
+INSTALL_DATA=@INSTALL_DATA@
+
+all: xdvi$(EXEEXT) xdvi.man
+
+xdvi$(EXEEXT): $(OBJS)
+ $(CC) $(X_LDFLAGS) -o xdvi $(OBJS) $(X_LIBS) $(EXTRA_LIBS) $(LIBS)
+ $(CHMOD) go+rx xdvi$(EXEEXT)
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(X_CFLAGS) $(EXTRA_CPPFLAGS) $<
+
+xdvi.o: config.h xdvi.h version.h xdvi.icon @KRHEADER_H@
+events.o: config.h xdvi.h
+popups.o: config.h xdvi.h
+dvi-init.o: config.h xdvi.h dvi.h
+dvi-draw.o: config.h xdvi.h dvi.h
+vf.o: config.h xdvi.h dvi.h
+util.o: config.h xdvi.h
+pk.o: config.h xdvi.h
+gf.o: config.h xdvi.h
+ft.o: config.h xdvi.h
+psdps.o: config.h xdvi.h
+psnews.o: config.h xdvi.h
+psgs.o: config.h xdvi.h
+font-open.o: config.h xdvi.h filf-app.h filefind.h
+special.o: config.h xdvi.h filf-app.h filefind.h
+filefind.o: config.h xdvi.h filf-app.h filefind.h
+
+krheader.h: xdvi.c config.h xdvi.h Makefile
+ $(CPP) -DMAKING_HEADER $(srcdir)/xdvi.c \
+ | sed -e 1,/XDVI_KR_BEGIN1/d -e '/XDVI_KR_END1/,$$d' -e '/^ *$$/d' \
+ -e '/^#/d' \
+ | sed -e '2,$$s/^"//' -e 's/"[ ]*$$/\\/' > krheader.h
+
+psheader.c: psheader.txt squeeze$(EXEEXT)
+ ./squeeze $(srcdir)/psheader.txt psheader.c
+
+squeeze$(EXEEXT): squeeze.c
+ $(CC) $(CFLAGS) -o squeeze $(srcdir)/squeeze.c $(LIBS)
+
+lint: $(SRCS)
+ $(LINT) $(CFLAGS) $(X_CFLAGS) $(SRCS) $(LIBS)
+
+xdvi.man: xdvi-man.sed mksedscript Makefile config.h
+ $(srcdir)/mksedscript $(CFLAGS) > sedscript
+ sed -f sedscript < $(srcdir)/xdvi-man.sed > xdvi.man
+
+check:
+
+install-bin: xdvi$(EXEEXT)
+ strip xdvi$(EXEEXT)
+ $(INSTALL_PROGRAM) xdvi$(EXEEXT) ${bindir}/xdvi$(EXEEXT)
+ $(INSTALL_PROGRAM) $(srcdir)/xdvizilla ${bindir}/xdvizilla
+
+install-man: xdvi.man
+ $(INSTALL_DATA) xdvi.man ${mandir}/man$(MANEXT)/xdvi.$(MANEXT)
+ $(INSTALL_DATA) $(srcdir)/xdvizilla.1 ${mandir}/man$(MANEXT)/xdvizilla.$(MANEXT)
+
+install-data: config.xdvi
+ @if grep "original config.xdvi --" "$(datadir)$(dvipsconfdir)/config.xdvi" >/dev/null 2>&1 \
+ || test ! -r "$(datadir)$(dvipsconfdir)/config.xdvi"; then \
+ echo " $(INSTALL_DATA) '$(srcdir)/config.xdvi' '$(datadir)$(dvipsconfdir)/config.xdvi'"; \
+ $(INSTALL_DATA) "$(srcdir)/config.xdvi" "$(datadir)$(dvipsconfdir)/config.xdvi"; \
+ else :; fi
+
+install: install-bin install-man install-data
+
+uninstall:
+ -$(RM) ${bindir}/xdvi$(EXEEXT) ${mandir}/man$(MANEXT)/xdvi.$(MANEXT)
+ -$(RM) ${bindir}/xdvizilla ${mandir}/man$(MANEXT)/xdvizilla.$(MANEXT)
+ @if grep "original config.xdvi --" "$(datadir)$(dvipsconfdir)/config.xdvi" >/dev/null 2>&1 \
+ || test ! -r "$(datadir)$(dvipsconfdir)/config.xdvi"; then \
+ echo " rm -f '$(datadir)$(dvipsconfdir)/config.xdvi'"; \
+ rm -f "$(datadir)$(dvipsconfdir)/config.xdvi"; \
+ else :; fi
+
+TAGS: $(srcs)
+ etags $(srcs)
+
+mostlyclean:
+ -$(RM) *.o xdvi$(EXEEXT) xdvi.man core sedscript *~
+
+archclean:
+ -$(RM) *.o xdvi$(EXEEXT) Makefile
+ -$(RM) config.h config.cache config.status config.log
+
+clean:
+ -$(RM) *.o xdvi$(EXEEXT) xdvi.man core sedscript krheader.h *~
+ -$(RM) psheader.c squeeze$(EXEEXT)
+
+distclean: clean
+ -$(RM) Makefile config.h config.cache config.status config.log
+
+veryclean: distclean
+ -$(RM) TAGS
+
+realclean: distclean
+ -$(RM) TAGS
+
+maintainer-clean: veryclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ rm -f config.hin configure config.status
+
+.PHONY: all lint check install install-bin install-man uninstall \
+ mostlyclean archclean clean distclean veryclean realclean maintainer-clean
diff --git a/README b/README
@@ -0,0 +1,232 @@
+DESCRIPTION
+
+xdvi is a program for previewing .dvi files, which are produced by the
+mathematical typesetting system, TeX.
+
+Installation instructions are in the file INSTALL.
+
+At the present time, the person to send bug reports to is Paul Vojta,
+ vojta@math.berkeley.edu.
+When doing so, please specify hardware and OS version, options used
+when running the ./configure script, and anything else that may be
+relevant. Be sure you've checked the FAQ first, especially for questions
+regarding searching for font files.
+
+Current information on xdvi is also available on the WWW at the URL
+http://math.berkeley.edu/~vojta/xdvi.html
+
+This software has been tested under Linux.
+
+Current versions of this program can be obtained from SourceForge, at the
+following URL:
+
+ http://sourceforge.net/projects/xdvi/
+
+Note that there are two versions of xdvi available there:
+
+ xdvi this version of xdvi ("plain xdvi")
+ xdvik the version of xdvi included with most TeX distributions
+
+Paul Vojta, 27 April 2013
+
+================================================================
+
+ This program is the combined work of many people, including but not
+restricted to:
+ Eric Cooper, CMU
+ Bob Scheifler, MIT LCS
+ Paal Kvamme, Norwegian Institute of Technology
+ H\aa vard Eidnes, Norwegian Institute of Technology
+ Mark Eichin, MIT SIPB
+ Paul Vojta, UC Berkeley
+ Jeffrey Lee, U of Toronto
+ Donald Richardson, Clarkson Univ.
+ Ricardo Telichevesky, MIT
+ Luis Miguel Silveira, MIT
+
+================================================================
+
+Notes of a historical nature follow. Most recent changes are listed at the end
+of the file.
+
+================================================================
+
+This directory contains a version of xdvi capable of reading GF, PXL
+and PK font files. This version of xdvi is based on the source that
+"came with" X v10r3. Xdvi was modified by Paal Kvamme at the Norwegian
+Institute of Technology, based on the modifications I had made to
+dviimp (a dvi to ImPress converter). This code was again more or less
+directly translated from the web source of PKtoPX.
+
+If you discover (and fix) any bugs in this code, please notify me, so
+I can make the corresponding changes myself.
+
+---------
+H}vard Eidnes (TeXish: H\aa vard Eidnes)
+Division of Computer Science
+Norwegian Institute of Technology
+
+E-Mail: h_eidnes%vax.runit.unit.uninett@nta-vax.arpa
+================================================================
+Also has path search added by Mark Eichin, looks in TEXFONTS
+================================================================
+
+================================================================
+Additional notes:
+ X11 version now works on the IBM PC/RT as well as VAX.
+ [eichin:19880313.1330EST]
+================================================================
+*MORE* fixes (for athena release locker) [eichin:19880722.2058EST]
+Fixes:
+ narrow vertical and horizontal lines no longer disappear.
+ bogus underlining (which usually occured on even sample sizes
+of odd sized characters) no longer occurs.
+ -S number (or typing number followed by S) will adjust the
+sampling fraction; 0 is special cased to mean if anything in the
+sampled zone is set, set the sample, else clear it. Interesting to
+experiment with, though not useful for reading (the default value of 3
+is just right.)
+ -display and -geometry arguments work (so do old style forms,
+though they were broken before)
+ fixed one of the PK debugging messages to print the correct
+font name instead of printing the pointer as text.
+ included Ken Raeburn <raeburn>'s changes to support multiple
+screens.
+================================================================
+More changes:
+
+ 1. Incorporated the bitmap under a viewport widget using the toolkit
+ (X11 only);
+ 2. Added an icon and icon geometry arguments (X11 only);
+ 3. Supported window resizing;
+ 4. Added a 'c' option to move whatever is currently under the cursor to
+ the center of the window;
+ 5. Added an 'R' option to reread the .dvi file, and added logic to make
+ 'R' happen automatically whenever any part of the window is exposed
+ and the dvi file changes (so that you can iconify xdvi, run tex,
+ deiconify xdvi, and voila!);
+ 6. Added a 'magnifying glass': when you push a button, a window pops
+ up, showing the region of the page, unshrunk;
+ 7. Added support for gf fonts;
+ 8. Upgraded font searching (at our site we use /usr/custom/tex82/gf
+ for gf fonts, /usr/custom/tex82/pk for pk fonts, etc.);
+ 9. Made numerous internal changes (removed all the lint I could,
+ made unshrunk bitmaps permanently resident, which speeds up size
+ changing, made table.h necessary only for pxl.h, split up the source
+ file into xdvi.c, dvi.c, gf.c, pxl.c, and pk.c, made shrinking occur
+ relative to the character's hot point, etc.)
+ 10. The program reads SIGIO signals and processes incoming events
+ immediately, so that it can stop displaying things that would be
+ erased anyway. If these interrupts are not coming through, then
+ it also checks for incoming events every several dozen characters
+ displayed.
+ 11. Further split up dvi.c into dvi_init.c and dvi_draw.c; added
+ compilation options for various internal bitmap representations.
+ Fixed it so gcc won't give warnings, and so it works with R3 toolkit.
+-- Patchlevel 2: --
+ 12. Added MAXCHARS compilation option. Eliminated the nonsense with
+ generating table.h.
+-- Patchlevel 3: --
+ 13. Added -altfont command line option and SYSV compilation option.
+ 14. Modified for System V boxes: -DSYSV compiler option. Modifications
+ by Donald Richardson, donr@crystal.mie.clarkson.edu
+-- Patchlevel 4: --
+ 15. Removed MAXCHARS compilation option. It's automatic now. Made X10
+ scrolling smoother. Implemented the moving magnifying glass.
+-- Patchlevel 5: --
+ 16. Implemented compilation without the toolkit, as well as scrollbars
+ and tpic support in X10. Also this version should work with color
+ VAXstations, although overstrike characters will come out incorrectly.
+ 17. Fixed a bug in gf reading routines: specials at the beginning of
+ a character def. were not being processed. Thanks to
+ kevin@amath.washington.edu for a bug report and fix.
+ 18. Added 'k' keystroke.
+-- Patchlevel 6: --
+ 19. Added buttons on the right side of the window.
+ 20. Added -pagewidth and -pageheight command line options and A4
+ compilation option.
+ 21. Added a yet more robust font finding algorithm.
+-- Patchlevel 7: --
+ 22. Replaced -pagewidth and -pageheight options with -paper.
+-- Patchlevel 8: --
+ 23. Added compatibility for X11R4 and VMS. Fixed up alignment of rules.
+-- Patchlevel 9: --
+ 24. Removed obsolete '#' and '=' options from the X11 version: they
+ interfere with emacs.
+-- Patchlevel 10: --
+ 25. Implemented arrow keys, expert mode, searching for the font's actual
+ size first, the -[xy]offset and -sw options, and numerous bug fixes.
+-- Patchlevel 11: --
+ 26. Implemented recursive searching for font files in subdirectories.
+ 27. Changed +sw to -hushspecials and implemented -hush.
+ 28. Modified mksedscript so that the man page comes out neater.
+ 29. Added a -keep option and resource to match the `k' keystroke.
+-- Patchlevel 12: --
+ 30. Implemented virtual fonts (this does not include built-in
+ Postscript<tm> fonts!!!).
+ 31. X11R5 support, and numerous bug fixes.
+-- Patchlevel 13: --
+ 32. Added support for TeXXeT.
+-- Patchlevel 14: --
+ 33. Added support for greyscale anti-aliasing.
+-- Patchlevel 15: --
+ 34. Added support for MakeTeXPK, as in dvips.
+-- Patchlevel 16: --
+ 35. In the code for greyscale anti-aliasing, try to allocate a colormap
+ so that GXor operations can be used for drawing. Also interpolate
+ between foreground and background colors.
+-- Patchlevel 17: --
+ 36. Fixed some bugs in the greyscale code.
+ 37. Implemented an environment variable for the MakeTeXPK script.
+ 38. Replaced mksedscript with a script using /bin/sh.
+-- Patchlevel 18: --
+ 39. Implemented checking of checksums and the -hushchecksums option.
+ 40. Implemented non-square magnifying glasses.
+ 41. Removed support for X10.
+ 42. Removed support for the pxl font format.
+ 43. Added support for PostScript specials via DPS or NeWS or gs.
+-- Patchlevel 19: --
+ 44. Implemented `header=' and `!' PostScript specials (and the
+ corresponding -noscan option).
+ 45. Implemented path searching for PostScript header and figure files,
+ in addition to shell escape capability (also the -allowshell option).
+ 46. Allow setting of -gamma with the `S' keystroke.
+ 47. Added options -nomakepk, -mfmode, -safer, -interpreter, -nogssafer, and
+ -gspalette.
+-- Patchlevel 20: --
+ 48. Bug fixes.
+-- Patchlevel 21: --
+ 49. Receipt of a SIGUSR1 signal causes xdvi to reread the dvi file.
+ 50. Support for the TeX Directory Structure standard, ls-R quick-find,
+ and configuration files.
+ 51. Fix greyscale code to work with TrueColor visual. Thanks to Lee
+ Hetherington for this one.
+-- Version 22: --
+ 52. Handle rotated bounding boxes correctly when not showing PostScript.
+ (Based on a patch by H. Zeller.)
+ 53. The "-s 0" command line option.
+ 54. Support for Motif.
+ 55. Support for displays with more than one visual, and the -noinstall
+ command line option.
+ 56. Support for installing a private colormap (-install command line
+ option).
+ 57. Configuration via a script generated by a modified GNU autoconf.
+ 58. Dimension arguments may now be given in terms of any of the TeX units
+ (pt, pc, in, bp, cm, mm, dd, cc, or sp).
+ 59. Allow XDVISIZES values to be of the form m0, m0.5, etc., signifying
+ magsteps.
+ 60. Change -hushspecials to -warnspecials, and suppress warnings about
+ undefined specials by default.
+ 61. Add -gsalpha option.
+-- Added since last major release:
+ 62. Add 'V' keystroke to toggle -gsalpha argument (based on a patch by
+ fred@thp.Uni-Duisburg.DE).
+ 63. Add keyTranslations and buttonTranslations resources for customizing
+ keystrokes and buttons, respectively.
+ 64. Add the ability to drag the image by shift-dragging the mouse.
+ 65. Add support for source specials.
+ 66. Add support for color specials (color rendering of TeXxed text).
+ 67. Add lots of popup windows (when compiled with the X toolkit only).
+ 68. Add support for printing from xdvi.
+
+Paul Vojta, vojta@math.berkeley.edu
diff --git a/README.VMS b/README.VMS
@@ -0,0 +1,483 @@
+NAME
+----
+
+XDVI - DVI Previewer for VAX VMS systems running the DECWindows software.
+
+SYNOPSIS
+--------
+
+ XDVI [+[<page>]] [-s <shrink>] [-density <density>] [-nogrey]
+ [-gamma <g>] [-p <pixels>] [-margins <dimen>] [-sidemargin <dimen>]
+ [-topmargin <dimen>] [-offsets <dimen>] [-xoffset <dimen>]
+ [-yoffset <dimen>] [-paper <papertype>] [-altfont <font>] [-l] [-rv]
+ [-mgs[n] <size>] [-hush] [-hushspecials] [-hushchars] [-hushchecksums]
+ [-fg <color>] [-bg <color>] [-hl <color>] [-bd <color>] [-cr <color>]
+ [-bw <width>] [-display <host::display>] [-geometry <geometry>]
+ [-icongeometry <geometry>] [-iconic] [-keep] [-copy] [-thorough]
+ [-version] dvi_file
+
+DESCRIPTION
+-----------
+
+ XDVI is a program which runs under the DECWindows system. It is used to
+ preview DVI files, such as those produced by TeX and LaTeX.
+
+ XDVI has the capability of displaying the file reduced by various (integer)
+ factors, and also has a "magnifying glass" which allows one to see a small
+ part of the unshrunk image momentarily.
+
+ Before displaying any page or part thereof, XDVI checks to see if the DVI
+ file has changed since the last time it was displayed. If this is the case,
+ XDVI will reinitialize itself for the new DVI file. For this reason,
+ exposing parts of the XDVI window while TeX is running should be avoided.
+ This feature allows you to preview many versions of the same file while
+ running XDVI only once.
+
+OPTIONS
+-------
+
+ In addition to specifying the DVI file (with or without the .DVI extension),
+ XDVI supports the following command line options. If the option begins with
+ a "+" instead of a "-", the option is restored to its default value. By
+ default, these options can be set via the resource names given in parentheses
+ in the description of each option.
+
+ +<page> Specifies the first page to show. If + is given
+ without a number, the last page is assumed; the first
+ page is the default.
+
+ -altfont <font> (.altFont) Declares a default font to use when the
+ font in the DVI file cannot be found. This is useful,
+ for example, with PostScript fonts.
+
+ -background <color> (.background) Determines the color of the background.
+ Same as -bg.
+
+ -bd <color> (.borderColor) Determines the color of the window
+ border.
+
+ -bg <color> (.background) Determines the color of the background.
+
+ -bordercolor <color> Same as -bd.
+
+ -borderwidth <width> (.borderWidth) Specifies the width of the border of
+ the window. Same as -bw.
+
+ -bw <width> (.borderWidth) Specifies the width of the border of
+ the window.
+
+ -copy (.copy) Always use the copy operation when writing
+ characters to the display. This option may be
+ necessary for correct operation on a color display, but
+ overstrike characters will be incorrect. If greyscale
+ anti-aliasing is in use, the -copy operation will
+ disable the use of colorplanes and make overstrikes
+ come out incorrectly. See also -thorough.
+
+ -cr <color> (.cursorColor) Determines the color of the cursor.
+ The default is the color of the page border.
+
+ -density <density> (.densityPercent) Determines the density used when
+ shrinking bitmaps for fonts. A higher value produces a
+ lighter font. The default value is 40.
+
+ -display <display> Specifies the host, display, and screen to be used for
+ displaying the DVI file. The display must be specified
+ in the form node::display.screen. The default is
+ obtained from the logical name "DECW$DISPLAY", which
+ may be defined using the SET DISPLAY command.
+
+ -fg <color> (.foreground) Determines the color of the text
+ (foreground).
+
+ -foreground <color> Same as -fg.
+
+ -gamma <gamma> (.gamma) Controls the interpolation of colors in the
+ greyscale anti-aliasing color palette. The default
+ value is 1.0. For 0 < gamma < 1, the fonts will be
+ lighter (more like the background), and for gamma > 1,
+ the fonts will be darker (more like the foreground).
+ Negative values behave the same way, but use a slightly
+ different algorithm.
+
+ -geometry <geometry> (*geometry) Specifies the initial geometry of the
+ window.
+
+ -hl <color> (.highlight) Determines the color of the page border.
+ The default is the foreground color.
+
+ -hush (.Hush) Causes XDVI to suppress all suppressible
+ warnings.
+
+ -hushchars (.hushLostChars) Causes XDVI to suppress warnings
+ about references to characters which are not defined in
+ the font.
+
+ -hushchecksums (.hushChecksums) Causes XDVI to suppress warnings
+ about checksum mismatches between the DVI file and the
+ font file.
+
+ -hushspecials (.hushSpecials) Causes XDVI to suppress warnings about
+ \special strings which it cannot process.
+
+ -icongeometry <geometry> (.iconGeometry) Specifies the initial position for
+ the icon.
+
+ -iconic (.iconic) Causes the XDVI window to start in the
+ iconic state. The default is to start with the window
+ open.
+
+ -keep (.keepPosition) Sets a flag to indicate that XDVI
+ should not move to the home position when moving to a
+ new page. See also the `k' keystroke.
+
+ -l (.listFonts) Causes the names of the fonts used to be
+ listed.
+
+ -margins <dimen> (.Margin) Specifies the size of both the top and side
+ margins. This should be a decimal number optionally
+ followed by "cm", e.g., 1.5 or 3cm, giving a
+ measurement in inches or centimeters. XDVI determines
+ the "home" position of the page within the window as
+ follows. If the entire page fits in the window, then
+ the margin settings are ignored. If, even after
+ removing the margins from the left, right, top, and
+ bottom, the page still cannot fit in the window, then
+ the page is put in the window such that the top and
+ left margins are hidden, and presumably the upper
+ left-hand corner of the text on the page will be in the
+ upper left-hand corner of the window. Otherwise, the
+ text is centered in the window. See also -sidemargin,
+ -topmargin, and the keystroke `M'.
+
+ -mgs <size> Same as -mgs1.
+
+ -mgs[n] <size> (.magnifierSize[n]) Specifies the size of the window
+ to be used for the "magnifying glass" for Button n.
+ The size may be given as an integer (indicating that
+ the magnifying glass is to be square), or it may be
+ given in the form WxH. See the MOUSE ACTIONS section.
+ Defaults are 200x150, 400x250, 700x500, 1000x800, and
+ 1200x1200.
+
+ -nogrey (.grey) Turns off the use of greyscale anti-aliasing
+ when printing shrunken bitmaps. In this case, the
+ logic of the corresponding resource is the reverse:
+ -nogrey corresponds to grey:off; +nogrey to grey:on.
+ See also the 'G' keystroke.
+
+ -offsets <dimen> (.Offset) Specifies the size of both the horizontal
+ and vertical offsets of the output on the page. This
+ should be a decimal number optionally followed by "cm",
+ e.g., 1.5 or 3cm, giving a measurement in inches or
+ centimeters. By decree of the Stanford TeX Project,
+ the default TeX page origin is always 1 inch over and
+ down from the top-left page corner, even when
+ non-American paper sizes are used. Therefore, the
+ default offsets are 1.0 inch. See also -xoffset and
+ -yoffset.
+
+ -p <pixels> (.pixelsPerInch) Defines the size of the fonts to use,
+ in pixels per inch. The default value is 300.
+
+ -paper <papertype> (.paper) Specifies the size of the printed page. This
+ may be of the form WxH (or WxHcm), where W is the width
+ in inches (or cm) and H is the height in inches (or
+ cm), respectively. There are also synonyms which may
+ be used: us (8.5x11), usr (11x8.5), legal (8.5x14),
+ foolscap (13.5x17), as well as the ISO sizes a1-a7,
+ b1-b7, c1-c7, a1r-a7r (a1-a7 rotated), etc. The
+ default size is 8.5 x 11 inches.
+
+ -rv (.reverseVideo) Causes the page to be displayed with
+ white characters on a black background, instead of vice
+ versa.
+
+ -s <shrink> (.shrinkFactor) Defines the initial shrink factor.
+ The default value is 3.
+
+ -sidemargin <dimen> (.sideMargin) Specifies the side margin (see
+ -margins).
+
+ -thorough (.thorough) XDVI will usually try to ensure that
+ overstrike characters (e.g., \notin) are printed
+ correctly. On monochrome displays, this is always
+ possible with one logical operation, either AND or OR.
+ On color displays, however, this may take two
+ operations, one to set the appropriate bits and one to
+ clear other bits. If this is the case, then by default
+ XDVI will instead use the copy operation, which does
+ not handle overstriking correctly. The -thorough
+ option chooses the slower but more correct choice. See
+ also -copy.
+
+ -topmargin <dimen> (.topMargin) Specifies the top and bottom margins (see
+ -margins).
+
+ -version Print information on the version of XDVI.
+
+ -xoffset <dimen> (.xOffset) Specifies the size of the horizontal
+ offset of the output on the page. See -offsets.
+
+ -yoffset <dimen> (.yOffset) Specifies the size of the vertical offset
+ of the output on the page. See -offsets.
+
+KEYSTROKES
+----------
+
+ XDVI recognizes the following keystrokes when typed in its window. Each may
+ optionally be preceded by a (positive or negative) number, whose
+ interpretation will depend on the particular keystroke. Note that the
+ keystrokes are case sensitive.
+
+ q Quits the program. Control-C, control-D, and control-Z will do this,
+ too.
+
+ n Moves to the next page (or to the nth next page if a number is given).
+ Synonyms are `f', Space, Return, Line Feed, and <Next Screen>.
+
+ p Moves to the previous page (or back n pages). Synonyms are `b',
+ control-H, Delete, and <Prev Screen>.
+
+ g Moves to the page with the given number. Initially, the first page is
+ assumed to be page number 1, but this can be changed with the `P'
+ keystroke, below. If no page number is given, then it goes to the last
+ page.
+
+ P "This is page number n." This can be used to make the `g' keystroke
+ refer to actual page numbers instead of absolute page numbers.
+
+ Control-L Redisplays the current page.
+
+ ^ Move to the "home" position of the page. This is normally the upper
+ left-hand corner of the page, depending on the margins as described in
+ the -margins option, above.
+
+ u Moves up two thirds of a window-full. The <Up Arrow> key is a synonym
+ for this keystroke.
+
+ d Moves down two thirds of a window-full. The <Down Arrow> key is a
+ synonym for this keystroke.
+
+ l Moves left two thirds of a window-full. The <Left Arrow> key is a
+ synonym for this keystroke.
+
+ r Moves right two thirds of a window-full. The <Right Arrow> key is a
+ synonym for this keystroke.
+
+ c Moves the page so that the point currently beneath the cursor is moved
+ to the middle of the window. It also (gasp!) warps the cursor to the
+ same place.
+
+ M Sets the margins so that the point currently under the cursor is the
+ upper left-hand corner of the text in the page. Note that this command
+ itself does not move the image at all. For details on how the margins
+ are used, see the -margins option.
+
+ s Changes the shrink factor to the given number. If no number is given,
+ the smallest factor that makes the entire page fit in the window will be
+ used. (Margins are ignored in this computation.)
+
+ S Sets the density factor to be used when shrinking bitmaps. This should
+ be a number between 0 and 100; higher numbers produce lighter
+ characters.
+
+ R Forces the DVI file to be reread. This allows you to preview many
+ versions of the same file while running XDVI only once.
+
+ k Normally when XDVI switches pages, it moves to the home position as
+ well. The `k' keystroke toggles a `keep-position' flag which, when set,
+ will keep the same position when moving between pages. Also `0k' and
+ `1k' clear and set this flag, respectively. See also the -keep option.
+
+ G This key toggles the use of greyscale anti-aliasing for displaying
+ shrunken bitmaps. In addition, the key sequences `0G' and `1G' clear and
+ set this flag, respectively. See also the -nogrey option.
+
+MOUSE ACTIONS
+-------------
+
+ If the shrink factor is set to any number other than one, then clicking any
+ mouse button will pop up a "magnifying glass" which shows the unshrunk image
+ in the vicinity of the mouse click. This subwindow disappears when the mouse
+ button is released. Different mouse buttons produce different sized windows,
+ as indicated by the -mgs option. Moving the cursor while holding the button
+ down will move the magnifying glass.
+
+ Also, the scrollbars (if present) behave in the standard X Window way:
+ pushing Button 2 in a scrollbar moves the top or left edge of the scrollbar
+ to that point and optionally drags it; pushing Button 1 moves the image up
+ or right by an amount equal to the distance from the button press to the
+ upper left-hand corner of the window; pushing Button 3 moves the image down
+ or left by the same amount. Note that this is different than the way
+ DECWindows normally defines the actions of the mouse buttons in scrollbars.
+
+LOGICAL NAMES
+-------------
+
+ Unless the -display option is used on the command line, XDVI uses the logical
+ name "DECW$DISPLAY" to specify which bit map display terminal to use. This
+ logical name may be defined with the SET DISPLAY command.
+
+ The logical name "XDVIFONTS" determines the directory path(s) searched for
+ fonts in the following manner. The string consists of one or more strings
+ separated by slashes. In each such string, the substring "%f" is changed to
+ the font name; "%d" is changed to the magnification; and "%p" is changed to
+ the font file format ("pk" or "gf"). If no "%f" appears in the string, then
+ the string ":%f.%d%p" is added on the end. For example, if the string is
+ "TEX_FONTS" and the font is cmr10 at 300 dots per inch, then XDVI searches
+ for TEX_FONTS:CMR10.300PK and TEX_FONTS:CMR10.300GF, in that order. An extra
+ slash anywhere in the "XDVIFONTS" logical name causes the system default
+ directories to be tried at that point. If the font is not found in the
+ desired size, then XDVI will try to find the nearest size. If the font
+ cannot be found at all, then XDVI will try to vary the point size of the font
+ (within a certain range), and if this fails, then it will use the font
+ specified as the alternate font (cf. -altfont).
+
+ In addition, a "%F" specifier is available; it is a synonym for "%f", but it
+ does not inhibit putting the string ":%f.%d%p" at the end. Finally, a "%b"
+ specifier is available; it is converted to the current resolution being used
+ (i.e., the value of the -p parameter or the .pixelsperinch resource).
+
+ For compatibility with some versions of TeX, you may also use the logical
+ name "TEXFONTS" in place of "XDVIFONTS", although in that case the string
+ should not include any "%" specifiers. The reason for recognizing "TEXFONTS"
+ is that certain versions of TeX also support the convention regarding an
+ extra slash in the font path; therefore, users who create their own fonts can
+ put both their .TFM and raster files in the same directory and do
+
+ $ DEFINE TEXFONTS "/MFDIR"
+
+ or
+
+ $ DEFINE TEXFONTS "MFDIR/"
+
+ in order to get both TeX and XDVI to search their directory in addition to
+ the system standard directories. The "XDVIFONTS" logical name overrides the
+ "TEXFONTS" logical name, so that on those sites where "TEXFONTS" must be set
+ explicitly, and therefore this feature is not useful, the "XDVIFONTS" logical
+ name may be set to an empty string to cause XDVI to ignore "TEXFONTS".
+
+ XDVI also recognizes the "PKFONTS" and "TEXPKS" logical names, which are
+ checked after "XDVIFONTS" but before "TEXFONTS".
+
+ The logical name "XDVISIZES" may be set to indicate which sizes of fonts are
+ available. It should consist of a list of numbers separated by slashes. If
+ the list begins with a slash, the system default sizes are used, as well.
+ Sizes are expressed in dots per inch and must be integers. The current
+ default set of sizes is 300/329/360/432/518/622/746. XDVI will also try the
+ actual size of the font before trying any of the given sizes.
+
+ Virtual fonts are also supported, although XDVI does not have any built-in
+ fonts to which they can refer. The search path for .VF files can be
+ specified with the "XDVIVFS" logical name in a similar manner to that for the
+ "XDVIFONTS" logical name. XDVI will also check the "VFFONTS" logical name if
+ the "XDVIFONTS" logical name is not defined. Virtual fonts are searched for
+ immediately after looking for the font as a normal font in the exact size
+ specified.
+
+FILES
+-----
+
+ TEX_FONTS System default directory for font pixel files.
+
+RESOURCE NAMES
+--------------
+
+ All of the command line options may be set via the resource names given in
+ parentheses in the descriptions of the options. This may be used to define a
+ specific set of options as the default each time you run XDVI. To make use
+ of this feature, create a file named DECW$XDEFAULTS.DAT in the same directory
+ as the rest of your DECW*.DAT files. Include in this file the resource names
+ and arguments of each of the options you wish to specify. For example:
+
+ XDvi.copy: off
+ XDvi.thorough: on
+ XDvi.shrinkFactor: 2
+ XDvi.Margin: 0.95
+ XDvi*geometry: 1015x750+3+25
+
+ When XDVI is invoked, it would behave as if it had been invoked with the
+ following command:
+
+ XDVI +copy -thorough -s 2 -margins 0.95 -geometry 1015x750+3+25 dvifile
+
+ Specifying options on the command line will override any options specified
+ via resource names in the DECW$XDEFAULTS.DAT file.
+
+INSTALLATION
+------------
+
+ The installation of XDVI on a VMS system is relatively easy. If you have a
+ source-only distribution, you will need to have access to the VAX C compiler
+ to build an executable image. The following steps should get you started:
+
+ 1) Gather all of the distribution files into one directory, and then create
+ the executable image by executing the MAKE-VMS.COM file:
+
+ $ @MAKE-VMS
+
+ 2) Create a help file for XDVI using the supplied XDVI.RNH file:
+
+ $ RUNOFF XDVI.RNH
+
+ 3) Insert the resulting XDVI.HLP file into one of your local help libraries:
+
+ $ LIBRARY /INSERT HELPLIB.HLB XDVI.HLP
+
+ 4) Modify the command file you use to set up the TEX commands so that it
+ defines the foreign symbol XDVI, and the logical names "XDVIFONTS",
+ "XDVIVFS", and "XDVISIZES". For more information on the expected contents
+ of the logical names, see the LOGICAL NAMES section of this document. The
+ following lines are what I use locally:
+
+ $ PROC = F$ENVIRONMENT ("PROCEDURE")
+ $ TEXDIR = F$PARSE (PROC, , , "DEVICE", "NO_CONCEAL") + -
+ F$PARSE (PROC, , , "DIRECTORY", "NO_CONCEAL")
+ $ TEXDIR = TEXDIR - "][" - "][" - "][" - "]"
+ $ TEXDISK = TEXDIR + ".]"
+ $ PIXELS = TEXDIR + ".GF.CANON300.]"
+ $ LPIXELS = TEXDIR + ".LOCAL.PIXELS.CANON300.]"
+ $!
+ $! Define the virtual disk devices.
+ $!
+ $ DEFINE /PROCESS /TRANSLATE = (CONCEAL, TERMINAL) TEX_DISK 'TEXDISK'
+ $ DEFINE /PROCESS /TRANSLATE = (CONCEAL, TERMINAL) PIXELS$ 'PIXELS'
+ $ DEFINE /PROCESS /TRANSLATE = (CONCEAL, TERMINAL) LPIXELS$ 'LPIXELS'
+ $!
+ $! Define the directories for TeX and its related TeXware.
+ $!
+ $ DEFINE TEX_EXE TEX_DISK:[LOCAL.PROGRAMS]
+ $ DEFINE TEX_PIXELS PIXELS$, LPIXELS$
+ $!
+ $! Define the information necessary to run XDVI.
+ $!
+ $ XDVI :== "$TEX_EXE:XDVI"
+ $ DEFINE XDVIFONTS "TEX_PIXELS:[DPI%d]%f.%p"
+ $ DEFINE XDVIVFS XDVIFONTS
+ $ DEFINE XDVISIZES -
+ "300/329/360/432/518/600/622/746/896/1075/1200/1290/1548"
+ $ EXIT
+
+ 5) If you wish, you may create a DECW$XDEFAULTS.DAT file that specifies a
+ default set of command line options. See the RESOURCE NAMES section for
+ more information and an example of what I use locally.
+
+ If you have any comments about XDVI, or find any bugs in the program, please
+ contact me at the address below. Enjoy!
+
+ Scott Allendorf
+ Department of Physics and Astronomy
+ The University of Iowa
+ Iowa City, IA 52242
+
+ Email: scott-allendorf@uiowa.edu
+
+AUTHORS
+-------
+
+ Eric Cooper, CMU, did a version for direct output to a QVSS.
+ Modified for X by Bob Scheifler, MIT Laboratory for Computer Science.
+ Modified for X11 by Mark Eichin, MIT SIPB.
+ Modified for VMS and DECWindows by Scott Allendorf, University of Iowa.
+ Additional enhancements by many others.
diff --git a/VMS-C.OPT b/VMS-C.OPT
@@ -0,0 +1,2 @@
+sys$share:decw$xlibshr/share
+sys$share:vaxcrtl/share
diff --git a/XDVI.RNH b/XDVI.RNH
@@ -0,0 +1,692 @@
+.!
+.! This is a RUNOFF source file that produces a VMS-style HELP library
+.! for the XDVI program.
+.!
+.! This file was created by hand-converting XDVI.MAN. The internal date
+.! in the XDVI.MAN file was "27 March 1990". If you improve this file,
+.! please let me know. Pete Siemsen, siemsen@usc.edu
+.!
+.! Merged with patchlevel 8.001 help file for VMS by Scott Allendorf.
+.! Added new switches for patchlevel 10. Scott Allendorf.
+.! Added new switches for patchlevel 11. Scott Allendorf.
+.! Added new switches for patchlevel 14. Scott Allendorf.
+.! Added new switches for patchlevel 16. Scott Allendorf.
+.! Updated for patchlevel 17. Scott Allendorf.
+.! Updated for patchlevel 18. Scott Allendorf.
+.!
+.NO PAGING
+.NO FLAGS ALL
+.RIGHT MARGIN 71
+.LITERAL
+!
+! DO NOT EDIT THIS FILE. It was produced by passing a .RNH file through
+! RUNOFF. Edit the .RNH file instead.
+!
+.END LITERAL
+.LEFT MARGIN 1
+
+.INDENT -1
+1 XDVI
+.BREAK
+XDVI is a program which runs under the DECWindows system. It is used to
+preview DVI files, such as those produced by TeX and LaTeX.
+.SKIP
+XDVI has the capability of displaying the file reduced by various
+(integer) factors, and also has a "magnifying glass" which allows one
+to see a small part of the unshrunk image momentarily.
+.SKIP
+Before displaying any page or part thereof, XDVI checks to see if
+the DVI file has changed since the last time it was displayed. If this
+is the case, XDVI will reinitialize itself for the new DVI file. For
+this reason, exposing parts of the XDVI window while TeX is running
+should be avoided. This feature allows you to preview many versions
+of the same file while running XDVI only once.
+
+.SKIP
+Format:
+.SKIP
+.INDENT +3
+XDVI [Options] dvi_file
+
+.INDENT -1
+2 Options
+.BREAK
+In addition to specifying the DVI file (with or without the .DVI extension),
+XDVI supports the following command line options. If the option
+begins with a "+" instead of a "-", the option is restored to its
+default value. By default, these options can be set via the resource
+names given in the description of each option.
+.INDENT -1
+3 +
+.BREAK
++<page>
+.SKIP
+Specifies the first page to show. If + is given without a number, the
+last page is assumed; the first page is the default.
+.INDENT -1
+3 -altfont
+.BREAK
+-altfont <font>
+.SKIP
+Declares a default font to use when the font in the DVI file cannot be
+found. This is useful, for example, with PostScript fonts.
+.SKIP
+The resource name is ".altFont".
+.INDENT -1
+3 -background
+.BREAK
+-background <color>
+.SKIP
+Determines the color of the background. Same as -bg.
+.SKIP
+The resource name is ".background".
+.INDENT -1
+3 -bd
+.BREAK
+-bd <color>
+.SKIP
+Determines the color of the window border.
+.SKIP
+The resource name is ".borderColor".
+.INDENT -1
+3 -bg
+.BREAK
+-bg <color>
+.SKIP
+Determines the color of the background.
+.SKIP
+The resource name is ".background".
+.INDENT -1
+3 -bordercolor
+.BREAK
+-bordercolor <color>
+.SKIP
+Same as -bd.
+.INDENT -1
+3 -borderwidth
+.BREAK
+-borderwidth <width>
+.SKIP
+Specifies the width of the border of the window. Same as -bw.
+.SKIP
+The resource name is ".borderWidth".
+.INDENT -1
+3 -bw
+.BREAK
+-bw <width>
+.SKIP
+Specifies the width of the border of the window.
+.SKIP
+The resource name is ".borderWidth".
+.INDENT -1
+3 -copy
+.BREAK
+Always use the copy operation when writing characters to the display.
+This option may be necessary for correct operation on a color display,
+but overstrike characters will be incorrect. If greyscale anti-aliasing
+is in use, the -copy operation will disable the use of colorplanes and make
+overstrikes come out incorrectly. See also -thorough.
+.SKIP
+The resource name is ".copy".
+.INDENT -1
+3 -cr
+.BREAK
+-cr <color>
+.SKIP
+Determines the color of the cursor. The default is the
+color of the page border.
+.SKIP
+The resource name is ".cursorColor".
+.INDENT -1
+3 -debug
+.BREAK
+-debug <bitmask>
+.SKIP
+If nonzero, prints additional debugging information on standard output.
+The bitmask should be given as a decimal number. The values of the bits
+are defined in the source file xdvi.h .
+.SKIP
+The resource name is ".debugLevel".
+.INDENT -1
+3 -density
+.BREAK
+-density <density>
+.SKIP
+Determines the density used when shrinking bitmaps for fonts. A
+higher value produces a lighter font. The default value is 40.
+.SKIP
+The resource name is ".densityPercent".
+.INDENT -1
+3 -display
+.BREAK
+-display <display>
+.SKIP
+Specifies the host, display, and screen to be used for displaying the DVI file.
+The display must be specified in the form node::display.screen. The default
+is obtained from the logical name "DECW$DISPLAY", which may be defined using the
+SET DISPLAY command.
+.INDENT -1
+3 -fg
+.BREAK
+-fg <color>
+.SKIP
+Determines the color of the text (foreground).
+.SKIP
+The resource name is ".foreground".
+.INDENT -1
+3 -foreground
+.BREAK
+-foreground <color>
+.SKIP
+Same as -fg.
+.INDENT -1
+3 -gamma
+.BREAK
+-gamma <gamma>
+.SKIP
+Controls the interpolation of colors in the greyscale anti-aliasing color
+palette. The default value is 1.0. For 0 < gamma < 1, the fonts will be
+lighter (more like the background), and for gamma > 1, the fonts will be darker
+(more like the foreground). Negative values behave the same way, but use a
+slightly different algorithm.
+.SKIP
+The resource name is ".gamma".
+.INDENT -1
+3 -geometry
+.BREAK
+-geometry <geometry>
+.SKIP
+Specifies the initial geometry of the window.
+.SKIP
+The resource name is "*geometry".
+.INDENT -1
+3 -hl
+.BREAK
+-hl <color>
+.SKIP
+Determines the color of the page border. The default is the foreground color.
+.SKIP
+The resource name is ".highlight".
+.INDENT -1
+3 -hush
+.BREAK
+Causes XDVI to suppress all suppressible warnings.
+.SKIP
+The resource name is ".Hush".
+.INDENT -1
+3 -hushchars
+.BREAK
+Causes XDVI to suppress warnings about references to characters which
+are not defined in the font.
+.SKIP
+The resource name is ".hushLostChars".
+.INDENT -1
+3 -hushchecksums
+.BREAK
+-hushchecksums
+.SKIP
+Causes XDVI to supress warnings about checksum mismatches between the DVI file
+and the font file.
+.SKIP
+The resource name is ".hushChecksums".
+.INDENT -1
+3 -hushspecials
+.BREAK
+Causes XDVI to suppress warnings about \special strings which it cannot process.
+.SKIP
+The resource name is ".hushSpecials".
+.INDENT -1
+3 -icongeometry
+.BREAK
+-icongeometry <geometry>
+.SKIP
+Specifies the initial position for the icon.
+.SKIP
+The resource name is ".iconGeometry".
+.INDENT -1
+3 -iconic
+.BREAK
+-iconic
+.SKIP
+Causes the XDVI window to start in the iconic state. The default is to start
+with the window open.
+.SKIP
+The resource name is ".iconic".
+.INDENT -1
+3 -keep
+.BREAK
+-keep
+.SKIP
+Sets a flag to indicate that XDVI should not move to the home position when
+moving to a new page. See also `k' under the Keystrokes help entry.
+.SKIP
+The resource name is ".keepPosition".
+.INDENT -1
+3 -l
+.BREAK
+Causes the names of the fonts used to be listed.
+.SKIP
+The resource name is ".listFonts".
+.INDENT -1
+3 -margins
+.BREAK
+-margins <dimen>
+.SKIP
+Specifies the size of both the top and side margins. This should be a
+decimal number optionally followed by "cm", e.g., 1.5 or 3cm, giving a
+measurement in inches or centimeters.
+XDVI determines the "home" position of
+the page within the window as follows. If the entire page fits in the
+window, then the margin settings are ignored. If, even after removing
+the margins from the left, right, top, and bottom, the page still
+cannot fit in the window, then the page is put in the window such that
+the top and left margins are hidden, and presumably the upper
+left-hand corner of the text on the page will be in the upper
+left-hand corner of the window. Otherwise, the text is centered in
+the window. See also -sidemargin, -topmargin under the Options help entry,
+and `M' under the Keystrokes help entry.
+.SKIP
+The resource name is ".Margin".
+.INDENT -1
+3 -mfmode
+.BREAK
+-mfmode <mode-def>
+.SKIP
+Specifies a `mode-def' string, which can be used in searching for fonts
+(see also the 'Logical_Names' entry).
+It is also passed to METAFONT during automatic creation of fonts.
+.SKIP
+The resource name is ".mfMode"
+.INDENT -1
+3 -mgs[n]
+.BREAK
+-mgs[n] <size>
+.SKIP
+Specifies the size of the window to be used for the "magnifying glass"
+for Button n. The size may be given as an integer (indicating that the
+magnifying glass is to be square), or it may be given in the form WxH. See
+the Mouse_Actions section.
+Defaults are 200x150, 400x250, 700x500, 1000x800, and 1200x1200.
+.SKIP
+The resource name is ".magnifierSize[n]".
+.INDENT -1
+3 -mgs
+.BREAK
+-mgs <size>
+.SKIP
+Same as -mgs1.
+.INDENT -1
+3 -nogrey
+.BREAK
+-nogrey
+.SKIP
+Turns off the use of greyscale anti-aliasing when printing shrunken bitmaps.
+In this case, the logic of the corresponding resource is the reverse:
+-nogrey corresponds to grey:off; +nogrey to grey:on.
+See also 'G' under the Keystrokes help entry.
+.SKIP
+The resource name is ".grey".
+.INDENT -1
+3 -nomakepk
+.BREAK
+-nomakepk
+.SKIP
+Turns off the automatic generation of missing font files that cannot be
+found by other means.
+For this option, the logic of the corresponding resource is reversed:
+-nogrey corresponds to makePK:off; +nogrey to makePK:on.
+.SKIP
+The resource name is ".makePK".
+.INDENT -1
+3 -offsets
+.BREAK
+-offsets <dimen>
+.SKIP
+Specifies the size of both the horizontal and vertical offsets of the
+output on the page. This should be a decimal number optionally followed by
+"cm", e.g., 1.5 or 3cm, giving a measurement in inches or centimeters.
+By decree
+of the Stanford TeX Project, the default TeX page origin is always 1 inch
+over and down from the top-left page corner, even when non-American paper
+sizes are used. Therefore, the default offsets are 1.0 inch. See also -xoffset
+and -yoffset.
+.SKIP
+The resource name is ".Offset".
+.INDENT -1
+3 -p
+.BREAK
+-p <pixels>
+.SKIP
+Defines the size of the fonts to use, in pixels per inch. The
+default value is 300.
+.SKIP
+The resource name is ".pixelsPerInch".
+.INDENT -1
+3 -paper
+.BREAK
+-paper <papertype>
+.SKIP
+Specifies the size of the printed page. This may be of the form WxH
+(or WxHcm), where W is the width in inches (or cm) and H is the height
+in inches (or cm), respectively. There are also synonyms which may be
+used: us (8.5x11), usr (11x8.5), legal (8.5x14), foolscap (13.5x17),
+as well as the ISO sizes a1-a7, b1-b7, c1-c7, a1r-a7r (a1-a7 rotated),
+etc. The default size is 8.5 x 11 inches.
+.SKIP
+The resource name is ".paper".
+.INDENT -1
+3 -rv
+.BREAK
+Causes the page to be displayed with white characters on a black
+background, instead of vice versa.
+.SKIP
+The resource name is ".reverseVideo".
+.INDENT -1
+3 -s
+.BREAK
+-s <shrink>
+.SKIP
+Defines the initial shrink factor. The default value is 3.
+.SKIP
+The resource name is ".shrinkFactor".
+.INDENT -1
+3 -sidemargin
+.BREAK
+-sidemargin <dimen>
+.SKIP
+Specifies the side margin (see -margins).
+.SKIP
+The resource name is ".sideMargin".
+.INDENT -1
+3 -thorough
+.BREAK
+XDVI will usually try to ensure that overstrike characters (e.g.,
+\notin) are printed correctly. On monochrome displays, this is always
+possible with one logical operation, either AND or OR. On color
+displays, however, this may take two operations, one to set the
+appropriate bits and one to clear other bits. If this is the case,
+then by default XDVI will instead use the copy operation, which does
+not handle overstriking correctly. The -thorough option chooses the
+slower but more correct choice. See also -copy.
+.SKIP
+The resource name is ".thorough".
+.INDENT -1
+3 -topmargin
+.BREAK
+-topmargin <dimen>
+.SKIP
+Specifies the top and bottom margins (see -margins).
+.SKIP
+The resource name is ".topMargin".
+.INDENT -1
+3 -version
+.BREAK
+-version
+.SKIP
+Print information on the version of XDVI.
+.INDENT -1
+3 -xoffset
+.BREAK
+-xoffset <dimen>
+.SKIP
+Specifies the size of the horizontal offset of the output on the page. See
+-offsets.
+.SKIP
+The resource name is ".xOffset".
+.INDENT -1
+3 -yoffset
+.BREAK
+-yoffset <dimen>
+.SKIP
+Specifies the size of the vertical offset of the output on the page. See
+-offsets.
+.SKIP
+The resource name is ".yOffset".
+
+.INDENT -1
+2 Keystrokes
+.BREAK
+Xdvi recognizes the following keystrokes when typed in its window.
+Each may optionally be preceded by a (positive or negative) number, whose
+interpretation will depend on the particular keystroke. Note that the
+keystrokes are case sensitive.
+.INDENT -1
+3 q
+.BREAK
+Quits the program. Control-C, control-D, and control-Z will do this, too.
+.INDENT -1
+3 n
+.BREAK
+Moves to the next page (or to the nth next page if a number is given).
+Synonyms are `f', Space, Return, Line Feed, and <Next Screen>.
+.INDENT -1
+3 p
+.BREAK
+Moves to the previous page (or back n pages). Synonyms are
+`b', control-H, Delete, and <Prev Screen>.
+.INDENT -1
+3 g
+.BREAK
+Moves to the page with the given number. Initially, the first page is
+assumed to be page number 1, but this can be changed with the `P'
+keystroke. If no page number is given, then it goes to the last page.
+.INDENT -1
+3 P
+.BREAK
+"This is page number n." This can be used to make the `g'
+keystroke refer to actual page numbers instead of absolute page numbers.
+.INDENT -1
+3 Control-L
+.BREAK
+Redisplays the current page.
+.INDENT -1
+3 ^
+.BREAK
+Move to the "home" position of the page. This is normally the upper
+left-hand corner of the page, depending on the margins as described in
+the -margins option.
+.INDENT -1
+3 u
+.BREAK
+Moves up two thirds of a window-full. The <Up Arrow> key is a synonym for this
+keystroke.
+.INDENT -1
+3 d
+.BREAK
+Moves down two thirds of a window-full. The <Down Arrow> key is a synonym for
+this keystroke.
+.INDENT -1
+3 l
+.BREAK
+Moves left two thirds of a window-full. The <Left Arrow> key is a synonym for
+this keystroke.
+.INDENT -1
+3 r
+.BREAK
+Moves right two thirds of a window-full. The <Right Arrow> key is a synonym for
+this keystroke.
+.INDENT -1
+3 c
+.BREAK
+Moves the page so that the point currently beneath the cursor is moved to
+the middle of the window. It also (gasp!) warps the cursor to the same place.
+.INDENT -1
+3 M
+.BREAK
+Sets the margins so that the point currently under the cursor is the upper
+left-hand corner of the text in the page. Note that this command itself does
+not move the image at all. For details on how the margins are used, see
+the -margins option.
+.INDENT -1
+3 s
+.BREAK
+Changes the shrink factor to the given number. If no number is given, the
+smallest factor that makes the entire page fit in the window will be used.
+(Margins are ignored in this computation.)
+.INDENT -1
+3 S
+.BREAK
+Sets the density factor to be used when shrinking bitmaps. This should
+be a number between 0 and 100; higher numbers produce lighter characters.
+If greyscaling mode is in effect, this changes the value of gamma instead.
+The new value of gamma is the given number divided by 100; negative values
+are allowed.
+.INDENT -1
+3 R
+.BREAK
+Forces the DVI file to be reread. This allows you to preview many
+versions of the same file while running XDVI only once.
+.INDENT -1
+3 k
+.BREAK
+Normally when XDVI switches pages, it moves to the home position as
+well. The `k' keystroke toggles a `keep-position' flag which, when
+set, will keep the same position when moving between pages. Also `0k'
+and `1k' clear and set this flag, respectively. See also the -keep option.
+.INDENT -1
+3 G
+.BREAK
+The key toggles the use of greyscale anti-aliasing for displaying shrunken
+bitmaps. In addition, the key sequences `0G' and `1G' clear and set this flag,
+respectively. See also the -nogrey option.
+
+.INDENT -1
+2 Mouse_Actions
+.BREAK
+If the shrink factor is set to any number other than one, then
+clicking any mouse button will pop up a "magnifying glass" which shows
+the unshrunk image in the vicinity of the mouse click. This subwindow
+disappears when the mouse button is released. Different mouse buttons
+produce different sized windows, as indicated by the -mgs option.
+Moving the cursor while holding the button down will move the
+magnifying glass.
+.SKIP
+Also, the scrollbars (if present) behave in the standard X Window way: pushing
+Button 2 in a scrollbar moves the top or left edge of the scrollbar to
+that point and optionally drags it; pushing Button 1 moves the image
+up or right by an amount equal to the distance from the button press
+to the upper left-hand corner of the window; pushing Button 3 moves
+the image down or left by the same amount. Note that this is
+different than the way
+DECWindows normally defines the actions of the mouse buttons in scrollbars.
+
+.INDENT -1
+2 Logical_Names
+.BREAK
+Some logical names can be defined to override the values defined when
+XDVI was compiled.
+.INDENT -1
+3 DECW$DISPLAY
+.BREAK
+Unless the -display option is used on the command line, XDVI uses the logical
+name "DECW$DISPLAY" to specify which bit map
+display terminal to use. This logical name may be defined with the SET
+DISPLAY command.
+.INDENT -1
+3 XDVIFONTS
+.BREAK
+The logical name "XDVIFONTS" determines the directory path(s) searched for fonts
+in the following manner. The string consists of one or more strings
+separated by slashes. In each such string, the substring "%f" is
+changed to the font name; "%d" is changed to the magnification; and
+"%p" is changed to the font file format ("pk" or "gf"). If no "%f"
+appears in the string, then the string ":%f.%d%p" is added on the end.
+For example, if the string is "TEX_FONTS" and the font is
+cmr10 at 300 dots per inch, then XDVI searches for TEX_FONTS:CMR10.300PK
+and TEX_FONTS:CMR10.300GF,
+in that order.
+An extra slash anywhere in the the "XDVIFONTS" logical name causes the
+system default directories to be tried at that point. If the font is not
+found in the desired size, then XDVI will try to find the nearest size. If the
+font cannot be found at all, then XDVI will try to vary the point size
+of the font (within a certain range), and if this fails, then it will
+use the font specified as the alternate font (cf. -altfont).
+.SKIP
+In addition, a "%F" specifier is available; it is a synonym for "%f", but it
+does not inhibit putting the string ":%f.%d%p" at the end. Finally, a "%b"
+specifier is available; it is converted to the current resolution being used
+(i.e., the value of the -p parameter or the .pixelsperinch resource).
+.SKIP
+For compatibility with some versions of TeX, you may also use the logical name
+"TEXFONTS" in place of "XDVIFONTS", although in that case the string should
+not include any "%" specifiers. The reason for recognizing "TEXFONTS" is
+that certain versions of TeX also support the convention regarding an extra
+slash in the font path; therefore, users who create their own fonts can put
+both their .TFM and raster file in the same directory and do
+.SKIP
+.LITERAL
+ $ DEFINE TEXFONTS "/MFDIR"
+
+or
+
+ $ DEFINE TEXFONTS "MFDIR/"
+.END LITERAL
+.SKIP
+in order to get TeX and XDVI to search their directory in addition to the
+system standard directories. The "XDVIFONTS" logical name overrides the
+"TEXFONTS" logical name, so that on those sites where "TEXFONTS" must be set
+explicitly, and therefore this feature is not useful, the "XDVIFONTS" logical
+name may be set to an empty string to cause XDVI to ignore "TEXFONTS".
+.SKIP
+XDVI also recognizes the "PKFONTS" and "TEXPKS" logical names, which are
+checked after "XDVIFONTS" but before "TEXFONTS".
+
+.INDENT -1
+3 XDVISIZES
+.BREAK
+The logical name "XDVISIZES" may be set to indicate which
+sizes of fonts are available. It should consists of a list of numbers
+separated by slashes. If the list begins with a slash, the system
+default sizes are used, as well. Sizes are expressed in dots per
+inch and must be integers. The current default set of
+sizes is 300/329/360/432/518/622/746. XDVI will also try the actual
+size of the font before trying any of the given sizes.
+
+.INDENT -1
+3 XDVIVFS
+.BREAK
+Virtual fonts are supported, although XDVI does not have any built-in fonts to
+which they can refer. The search path for .VF files can be specified with the
+"XDVIVFS" logical name in a similar manner to that for the "XDVIFONTS" logical
+name. XDVI will also check the "VFFONTS" logical name if the "XDVIFONTS"
+logical name is not defined. Virtual fonts are searched for immediately after
+looking for the font as a normal font in the exact size specified.
+
+.INDENT -1
+2 Resource_Names
+.BREAK
+ All of the command line options may be set via the resource names given in
+ the descriptions of the options. This may be used to define a
+ specific set of options as the default each time you run XDVI. To make use
+ of this feature, create a file named DECW$XDEFAULTS.DAT in the same directory
+ as the rest of your DECW*.DAT files. Include in this file the resource names
+ and arguments of each of the options you wish to specify. For example:
+.SKIP
+.LITERAL
+ XDvi.copy: off
+ XDvi.thorough: on
+ XDvi.shrinkFactor: 2
+ XDvi.Margin: 0.95
+ XDvi*geometry: 1015x750+3+25
+.END LITERAL
+.SKIP
+ When XDVI is invoked, it would behave as if it had been invoked with the
+ following command:
+.SKIP
+.LITERAL
+ XDVI +copy -thorough -s 2 -margins 0.95 -geometry 1015x750+3+25 dvifile
+.END LITERAL
+.SKIP
+ Specifying options on the command line will override any options specified
+ via resource names in the DECW$XDEFAULTS.DAT file.
+
+.INDENT -1
+2 Authors
+.BREAK
+.LITERAL
+Eric Cooper, CMU, did a version for direct output to a QVSS.
+Modified for X by Bob Scheifler, MIT Laboratory for Computer Science.
+Modified for X11 by Mark Eichin, MIT SIPB.
+Modified for VMS and DECWindows by Scott Allendorf, University of Iowa.
+Additional enhancements by many others.
+.END LITERAL
diff --git a/acconfig.h b/acconfig.h
@@ -0,0 +1,150 @@
+/* Define as the type of the result of subtracting two pointers, if the system
+ doesn't define it. */
+/* #undef ptrdiff_t */
+
+/* Define to determine the integer type to be used in bitmaps. The type used
+ will be "unsigned BMTYPE". */
+#define BMTYPE int
+
+/* Define to the length (in bytes) of the above type. */
+#define BMBYTES 4
+
+/* Define if your C compiler does not do string concatenation. */
+#undef CC_K_AND_R
+
+/* Define if your system has STREAMS (and if X uses it). */
+#undef HAVE_STREAMS
+
+/* Define if you are using SunOS 4.x. */
+#undef SUNOS4
+
+/* Define if you are using Linux 2.1.xxx -- 2.2.8,
+ or if you find it necessary. */
+#undef FLAKY_SIGPOLL
+
+/* Define if your system has <poll.h> and poll(). */
+#undef HAVE_POLL
+
+/* Define if your system has XkbBell(). */
+#undef HAVE_XKB_BELL_EXT
+
+/* Define if your system allows setsid() within vfork(). */
+#undef HAVE_GOOD_SETSID_VFORK
+
+/* Define if your system has waitpid(). */
+#undef HAVE_WAITPID
+
+/* Define if your system has putenv(). */
+#undef HAVE_PUTENV
+
+/* Define if your system has C99-compatible versions of (v)snprintf(). */
+#undef HAVE_GOOD_VSNPRINTF
+
+/* Define to use the Xaw toolkit. */
+#undef XAW
+
+/* Define this and XAW to use the Xaw3d toolkit. */
+#undef XAW3D
+
+/* Define to use the Motif toolkit. */
+#undef MOTIF
+
+/* Define to enable greyscale anti-aliasing for shrunken bitmaps. */
+#undef GREY
+
+/* Define to enable support for color specials. */
+#undef COLOR
+
+/* Define to enable radio buttons on the side of the window for common
+ commands. */
+#undef BUTTONS
+
+/* Define to enable calling of mktexpk to automatically create missing
+ pixel files. */
+#undef MKTEXPK
+
+/* Define to enable old-style MakeTeXPK scripts to automatically create missing
+ pixel files. */
+#undef MAKETEXPK
+
+/* Define to point to the mktexpk or MakeTeXPK script (optional). */
+#undef MKTEXPK_PATH
+
+/* Define to enable gf format files (in addition to pk format). */
+#undef USE_GF
+
+/* Define to enable PostScript support via ghostscript. */
+#undef PS_GS
+
+/* Define to point to the ghostscript interpreter (optional). */
+#undef GS_PATH
+
+/* Define to enable PostScript support via Display PostScript. */
+#undef PS_DPS
+
+/* Define to enable PostScript support via NeWS (Sun OpenWindows). */
+#undef PS_NEWS
+
+/* Define to enable support for a configuration file. Its value must be a
+ colon-separated list of paths to search. */
+#undef DEFAULT_CONFIG_PATH
+
+/* Define to enable support for a configuration file (as above), including
+ support for the variables $SELFAUTODIR and $SELFAUTOPARENT. */
+#undef SELFAUTO
+
+/* Define to enable support for an additional app-defaults file (located with
+ the texmf hierarchy). */
+#undef EXTRA_APP_DEFAULTS
+
+/* Define to use DOS-style names for font files (e.g., dpi300/cmr10.pk instead
+ of cmr10.300pk). */
+#undef DOSNAMES
+
+/* Define to use A4 as the default paper size. */
+#undef A4
+
+/* Define to enable right-to-left typesetting. */
+#undef TEXXET
+
+/* Define to set a default mfmode and resolution. */
+#undef MFMODE
+
+/* Define to enable FreeType fonts */
+#undef FREETYPE
+
+/* Define to set the default list of texmf trees. */
+#undef DEFAULT_TEXMF_PATH
+
+/* Define to set the default path for font searching. */
+#undef DEFAULT_FONT_PATH
+
+/* Define to set the default path for virtual-font searching. */
+#undef DEFAULT_VF_PATH
+
+/* Define to set the default path for PostScript header searching. */
+#undef DEFAULT_HEADER_PATH
+
+/* Define to set the default path for PostScript figure searching. */
+#undef DEFAULT_FIG_PATH
+
+/* Define to set the default path for dvips configuration file searching. */
+#undef DEFAULT_DVIPS_CF_PATH
+
+/* Define to set the default path for (dvips-style) fontmap file searching. */
+#undef DEFAULT_FONTMAP_PATH
+
+/* Define to set the default path for encoding file searching. */
+#undef DEFAULT_ENC_PATH
+
+/* Define to set the default path for Type 1 font file searching. */
+#undef DEFAULT_TYPE1_PATH
+
+/* Define to set the default path for ghostscript-style font searching. */
+#undef DEFAULT_GS_LIB_PATH
+
+/* Define to set the default path for files edited by source specials. */
+#undef DEFAULT_SOURCE_PATH
+
+/* Define to point to the default command to use for printing (optional). */
+#undef DEFAULT_DVIPS_PATH
diff --git a/aclocal.m4 b/aclocal.m4
@@ -0,0 +1,280 @@
+dnl ### Determine integer type to use for bitmaps
+
+AC_DEFUN(XDVI_C_BITMAP_TYPE,
+[AC_MSG_CHECKING(for integer type to use in bitmaps)
+AC_CACHE_VAL(xdvi_cv_bitmap_type,
+[AC_TRY_RUN(
+[#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ if ((sizeof(unsigned long) == 4 || sizeof(unsigned long) == 2)
+ && sizeof(unsigned long) != sizeof(unsigned int))
+ fprintf(f, "BMTYPE=long BMBYTES=%d\n", sizeof(unsigned long));
+ if (sizeof(unsigned int) == 4 || sizeof(unsigned int) == 2)
+ fprintf(f, "BMTYPE=int BMBYTES=%d\n", sizeof(unsigned int));
+ else if (sizeof(unsigned short) == 4 || sizeof(unsigned short) == 2)
+ fprintf(f, "BMTYPE=short BMBYTES=%d\n", sizeof(unsigned short));
+ else fprintf(f, "BMTYPE=char BMBYTES=%d\n", sizeof(unsigned char));
+ exit(0);
+}],
+xdvi_cv_bitmap_type="`cat conftestval`",
+AC_MSG_ERROR(could not determine integer type for bitmap))])
+eval "$xdvi_cv_bitmap_type"
+AC_DEFINE_UNQUOTED(BMTYPE, $BMTYPE)
+AC_DEFINE_UNQUOTED(BMBYTES, $BMBYTES)
+AC_MSG_RESULT([unsigned $BMTYPE, size = $BMBYTES])])
+
+
+dnl ### Check for whether the C compiler does string concatenation
+
+AC_DEFUN(XDVI_CC_CONCAT,
+[AC_CACHE_CHECK([for whether the C compiler supports string concatenation],
+xdvi_cc_concat,
+[AC_TRY_COMPILE(
+[#include <stdio.h>
+], [puts("Testing" " string" " concatenation");
+], xdvi_cc_concat=yes, xdvi_cc_concat=no)])
+KRHEADER_H=
+if test $xdvi_cc_concat = no; then
+ AC_DEFINE(CC_K_AND_R)
+ KRHEADER_H=krheader.h
+fi
+AC_SUBST(KRHEADER_H)])
+
+
+dnl ### Check for at-least-pretend Streams capability
+
+AC_DEFUN(XDVI_SYS_STREAMS,
+[AC_CACHE_CHECK([for stropts.h and isastream()], xdvi_cv_sys_streams,
+[AC_TRY_LINK(
+[#include <stropts.h>
+], [#ifndef I_SETSIG
+choke me
+#else
+isastream(0);
+#endif], xdvi_cv_sys_streams=yes, xdvi_cv_sys_streams=no)])
+if test $xdvi_cv_sys_streams = yes; then
+ AC_DEFINE(HAVE_STREAMS)
+fi])
+
+
+dnl ### Check for poll()
+
+AC_DEFUN(XDVI_FUNC_POLL,
+[AC_CACHE_CHECK([for poll.h and poll()], xdvi_cv_func_poll,
+[AC_TRY_LINK(
+[#include <poll.h>
+], [poll((struct pollfd *) 0, 0, 0);],
+xdvi_cv_func_poll=yes, xdvi_cv_func_poll=no)])
+if test $xdvi_cv_func_poll = yes; then
+ AC_DEFINE(HAVE_POLL)
+else
+ AC_CHECK_HEADERS(sys/select.h select.h)
+fi])
+
+
+dnl ### Check for a C99-compatible implementation of (v)snprintf()
+
+AC_DEFUN(XDVI_FUNC_C99_VSNPRINTF,
+[AC_CACHE_CHECK([for a c99-compatible implementation of (v)snprintf()],
+xdvi_cv_func_good_vsnprintf,
+[AC_TRY_RUN(
+[#include <stdio.h>
+int main()
+{
+ char s[2];
+ return (snprintf(s, 0, "test") != 4);
+}],
+xdvi_cv_func_good_vsnprintf=yes,
+xdvi_cv_func_good_vsnprintf=no)])
+if test $xdvi_cv_func_good_vsnprintf = yes; then
+ AC_DEFINE(HAVE_GOOD_VSNPRINTF)
+fi])
+
+
+dnl ### Check for SunOS 4
+
+AC_DEFUN(XDVI_SYS_SUNOS_4,
+[AC_CACHE_CHECK([for SunOS 4], xdvi_cv_sys_sunos_4,
+[case "`(uname -sr) 2>/dev/null`" in
+"SunOS 4."*)
+ xdvi_cv_sys_sunos_4=yes ;;
+*) xdvi_cv_sys_sunos_4=no ;;
+esac])
+if test $xdvi_cv_sys_sunos_4 = yes; then
+ AC_DEFINE(SUNOS4)
+fi])
+
+
+dnl ### Check for certain broken versions of Linux
+
+AC_DEFUN(XDVI_SYS_OLD_LINUX,
+[AC_CACHE_CHECK([for certain old versions of Linux], xdvi_cv_sys_old_linux,
+[case "`(uname -sr) 2>/dev/null`" in
+"Linux 2."[[01]].* | "Linux 2.2."[[0-8]] | "Linux 2.2."[[0-8]]-*)
+ xdvi_cv_sys_old_linux=yes ;;
+*) xdvi_cv_sys_old_linux=no ;;
+esac])
+if test $xdvi_cv_sys_old_linux = yes; then
+ AC_DEFINE(FLAKY_SIGPOLL)
+fi])
+
+
+dnl ### Process a string argument
+
+dnl XDVI_ARG_STRING(PACKAGE, HELP-STRING, VARIABLE, DEFAULT_VALUE)
+AC_DEFUN(XDVI_ARG_STRING,
+[AC_ARG_WITH($1, [$2], [AC_DEFINE_UNQUOTED($3, "$withval")
+], [AC_DEFINE($3, [$4])
+])])
+
+
+dnl ### Determine the path to use for GS_LIB.
+
+AC_DEFUN(XDVI_GS_LIB_PATH,
+[AC_ARG_WITH(default-gs-lib-path, [ --with-default-gs-lib-path=PATH
+ set default path for finding font aliases to PATH],
+[AC_DEFINE_UNQUOTED(DEFAULT_GS_LIB_PATH, "$withval")
+],
+[AC_CACHE_CHECK([for the path to be used for Ghostscript searches],
+xdvi_gs_lib_path,
+[if gs -h >/dev/null 2>&1; then
+ ac_tmp="`gs -h \
+ | sed \
+ -e '1,/Search path:/d' \
+ -e '/For more information/,$d' \
+ -e '/Initialization files are compiled/d' \
+ -e 's/$/\/\/\//' \
+ -e 's/^ //' \
+ | tr '\n' '/'`"
+ # Solaris 9 sed doesn't handle incomplete lines at eof
+ xdvi_gs_lib_path=`echo "$ac_tmp" \
+ | sed -e 's/\/\/\/\// /g' -e 's/ *$//' -e 's/ : /:/g'`
+else
+ xdvi_gs_lib_path=none
+fi])
+if test "$xdvi_gs_lib_path" != none; then
+ AC_DEFINE_UNQUOTED(DEFAULT_GS_LIB_PATH, "$xdvi_gs_lib_path")
+else
+ AC_MSG_WARN(Could not determine Ghostscript search path)
+ AC_DEFINE(DEFAULT_GS_LIB_PATH, NULL)
+fi
+])])
+
+
+dnl ### Check for whether we need -lXpm
+
+AC_DEFUN(XDVI_CHECK_XPM,
+[if test -z "$imake"; then
+# Cygwin needs -lXpm to be linked in explicitly; yet on older (<4.2)
+# versions of XFree86, -lXpm exists, but is not needed. So we do two checks.
+AC_CACHE_CHECK([for whether -lXpm needs to be explicitly given],
+xdvi_needs_explicit_xpm,
+[xdvi_save_LIBS=$LIBS
+LIBS="-l$1 -lXmu -lXt$X_PRE_LIBS -lXext $LIBS $X_LIBS -lX11"
+AC_TRY_LINK_FUNC(XawTextReplace, xdvi_needs_explicit_xpm=no,
+[LIBS="$LIBS -lXpm"
+AC_TRY_LINK_FUNC(XawTextReplace, xdvi_needs_explicit_xpm=yes,
+xdvi_needs_explicit_xpm=unknown)])
+LIBS=$xdvi_save_LIBS])
+if test "$xdvi_needs_explicit_xpm" = yes; then
+ X_PRE_LIBS=" -lXpm$X_PRE_LIBS"
+fi
+fi])
+
+
+dnl ### Check for XkbBell() functionality. Adapted from xterm's version.
+AC_DEFUN([XDVI_XKB_BELL_EXT],[
+AC_CACHE_CHECK([for XKB Bell extension], xdvi_cv_xkb_bell_ext,
+[xdvi_save_LIBS=$LIBS
+LIBS="$X_PRE_LIBS"$1" $LIBS $X_LIBS -lX11"
+AC_TRY_LINK([
+#include <X11/X.h>
+#include <X11/XKBlib.h> /* has the prototype */
+],[
+ Atom y;
+ XkbBell((Display *)0, (Window)0, 0, y);
+],[xdvi_cv_xkb_bell_ext=yes],[xdvi_cv_xkb_bell_ext=no])
+LIBS=$xdvi_save_LIBS])
+if test "$xdvi_cv_xkb_bell_ext" = yes; then
+ X_PRE_LIBS="$X_PRE_LIBS"$1
+ AC_DEFINE(HAVE_XKB_BELL_EXT)
+fi])
+
+
+dnl ### Check for whether setsid() is allowed within vfork()
+dnl (Mac OS X 10.3 (Panther, 11/2003) is one O/S which does not allow this.)
+
+AC_DEFUN(XDVI_FUNC_SETSID_IN_VFORK,
+[if test $ac_cv_func_vfork_works = yes; then
+AC_CACHE_CHECK([for whether setsid() is allowed within vfork()],
+xdvi_cv_setsid_in_vfork,
+[AC_TRY_RUN(
+[/* Test adapted from Gnu autoconf */
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+int
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ child = vfork ();
+
+ if (child == 0) {
+ if (setsid () == -1)
+ _exit(1);
+ _exit(0);
+ } else {
+ int status;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+ );
+ }
+}],
+xdvi_cv_setsid_in_vfork=yes,
+xdvi_cv_setsid_in_vfork=no)])
+if test $xdvi_cv_setsid_in_vfork = yes; then
+ AC_DEFINE(HAVE_GOOD_SETSID_VFORK)
+fi]
+fi)
+
+
+dnl ### Check if the --allow-multiple-definition linker flag is
+dnl ### available (assuming that we need to use it if it is)
+
+AC_DEFUN(XDVI_LINKER_MULTIPLE_DEFNS,
+[AC_CACHE_CHECK([whether linker supports the --allow-multiple-definition flag],
+xdvi_linker_multiple_defns,
+xdvi_save_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Xlinker --allow-multiple-definition"
+x_linker_options=""
+[AC_TRY_LINK(
+ [#include <stdio.h>
+ ],
+ [void foo(void);
+ ],
+ xdvi_linker_multiple_defns=yes, xdvi_linker_multiple_defns=no
+)]
+)
+if test $xdvi_linker_multiple_defns = yes; then
+x_linker_options="-Xlinker --allow-multiple-definition"
+fi
+LDFLAGS="$xdvi_save_LDFLAGS"
+AC_SUBST(x_linker_options)])
diff --git a/config.hin b/config.hin
@@ -0,0 +1,228 @@
+/* config.hin. Generated automatically from configure.in by autoheader. */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if your installation of X has X11/Xosdefs.h. */
+#undef HAVE_X11_XOSDEFS_H
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define as the type of the result of subtracting two pointers, if the system
+ doesn't define it. */
+/* #undef ptrdiff_t */
+
+/* Define to determine the integer type to be used in bitmaps. The type used
+ will be "unsigned BMTYPE". */
+#define BMTYPE int
+
+/* Define to the length (in bytes) of the above type. */
+#define BMBYTES 4
+
+/* Define if your C compiler does not do string concatenation. */
+#undef CC_K_AND_R
+
+/* Define if your system has STREAMS (and if X uses it). */
+#undef HAVE_STREAMS
+
+/* Define if you are using SunOS 4.x. */
+#undef SUNOS4
+
+/* Define if you are using Linux 2.1.xxx -- 2.2.8,
+ or if you find it necessary. */
+#undef FLAKY_SIGPOLL
+
+/* Define if your system has <poll.h> and poll(). */
+#undef HAVE_POLL
+
+/* Define if your system has XkbBell(). */
+#undef HAVE_XKB_BELL_EXT
+
+/* Define if your system allows setsid() within vfork(). */
+#undef HAVE_GOOD_SETSID_VFORK
+
+/* Define if your system has waitpid(). */
+#undef HAVE_WAITPID
+
+/* Define if your system has putenv(). */
+#undef HAVE_PUTENV
+
+/* Define if your system has C99-compatible versions of (v)snprintf(). */
+#undef HAVE_GOOD_VSNPRINTF
+
+/* Define to use the Xaw toolkit. */
+#undef XAW
+
+/* Define this and XAW to use the Xaw3d toolkit. */
+#undef XAW3D
+
+/* Define to use the Motif toolkit. */
+#undef MOTIF
+
+/* Define to enable greyscale anti-aliasing for shrunken bitmaps. */
+#undef GREY
+
+/* Define to enable support for color specials. */
+#undef COLOR
+
+/* Define to enable radio buttons on the side of the window for common
+ commands. */
+#undef BUTTONS
+
+/* Define to enable calling of mktexpk to automatically create missing
+ pixel files. */
+#undef MKTEXPK
+
+/* Define to enable old-style MakeTeXPK scripts to automatically create missing
+ pixel files. */
+#undef MAKETEXPK
+
+/* Define to point to the mktexpk or MakeTeXPK script (optional). */
+#undef MKTEXPK_PATH
+
+/* Define to enable gf format files (in addition to pk format). */
+#undef USE_GF
+
+/* Define to enable PostScript support via ghostscript. */
+#undef PS_GS
+
+/* Define to point to the ghostscript interpreter (optional). */
+#undef GS_PATH
+
+/* Define to enable PostScript support via Display PostScript. */
+#undef PS_DPS
+
+/* Define to enable PostScript support via NeWS (Sun OpenWindows). */
+#undef PS_NEWS
+
+/* Define to enable support for a configuration file. Its value must be a
+ colon-separated list of paths to search. */
+#undef DEFAULT_CONFIG_PATH
+
+/* Define to enable support for a configuration file (as above), including
+ support for the variables $SELFAUTODIR and $SELFAUTOPARENT. */
+#undef SELFAUTO
+
+/* Define to enable support for an additional app-defaults file (located with
+ the texmf hierarchy). */
+#undef EXTRA_APP_DEFAULTS
+
+/* Define to use DOS-style names for font files (e.g., dpi300/cmr10.pk instead
+ of cmr10.300pk). */
+#undef DOSNAMES
+
+/* Define to use A4 as the default paper size. */
+#undef A4
+
+/* Define to enable right-to-left typesetting. */
+#undef TEXXET
+
+/* Define to set a default mfmode and resolution. */
+#undef MFMODE
+
+/* Define to enable FreeType fonts */
+#undef FREETYPE
+
+/* Define to set the default list of texmf trees. */
+#undef DEFAULT_TEXMF_PATH
+
+/* Define to set the default path for font searching. */
+#undef DEFAULT_FONT_PATH
+
+/* Define to set the default path for virtual-font searching. */
+#undef DEFAULT_VF_PATH
+
+/* Define to set the default path for PostScript header searching. */
+#undef DEFAULT_HEADER_PATH
+
+/* Define to set the default path for PostScript figure searching. */
+#undef DEFAULT_FIG_PATH
+
+/* Define to set the default path for dvips configuration file searching. */
+#undef DEFAULT_DVIPS_CF_PATH
+
+/* Define to set the default path for (dvips-style) fontmap file searching. */
+#undef DEFAULT_FONTMAP_PATH
+
+/* Define to set the default path for encoding file searching. */
+#undef DEFAULT_ENC_PATH
+
+/* Define to set the default path for Type 1 font file searching. */
+#undef DEFAULT_TYPE1_PATH
+
+/* Define to set the default path for ghostscript-style font searching. */
+#undef DEFAULT_GS_LIB_PATH
+
+/* Define to set the default path for files edited by source specials. */
+#undef DEFAULT_SOURCE_PATH
+
+/* Define to point to the default command to use for printing (optional). */
+#undef DEFAULT_DVIPS_PATH
+
+/* Define if you have the mkstemp function. */
+#undef HAVE_MKSTEMP
+
+/* Define if you have the setenv function. */
+#undef HAVE_SETENV
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the vasprintf function. */
+#undef HAVE_VASPRINTF
+
+/* Define if you have the vsnprintf function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if you have the wait4 function. */
+#undef HAVE_WAIT4
+
+/* Define if you have the <X11/IntrinsicI.h> header file. */
+#undef HAVE_X11_INTRINSICI_H
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <select.h> header file. */
+#undef HAVE_SELECT_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
diff --git a/config.xdvi b/config.xdvi
@@ -0,0 +1,45 @@
+% original config.xdvi -- Configuration file for Type 1 rendering in xdvi.
+% (If you change or delete `original' in the first line of this file,
+% new xdvi installations won't overwrite the file.)
+%
+% This file is part of xdvi (notwithstanding its location).
+%
+% Lines starting with `%' are comments.
+%
+% This file indicates which map files are to be used when running xdvi.
+% (It is not used by dvips, unless you type "dvips -Pxdvi ...", which is not
+% likely. Doing so, however, would allow you to use the same map files
+% in dvips as are used in xdvi.)
+%
+% The format is the same as for dvips configuration files, except that only
+% the `p' and `p+' directives are used. A line
+%
+% p file.map
+%
+% clears the existing list of map files and sets the list to the given file.
+% A line
+%
+% p+ file2.map
+%
+% adds the given map file to the end of the list. If you use "p file.map"
+% anywhere other than as the first (non-comment, non-blank) line of the file,
+% then you are probably making a mistake.
+%
+% If a font entry is found in several files, the earlier entry will be used
+% (as is done in dvips). Therefore, to override font entries in the standard
+% file psfonts.map, you should use entries such as:
+%
+% p myfile.map
+% p+ anotherfile.map
+% p+ psfonts.map
+%
+% However, normally it isn't necessary to add any other map file here
+% because psfonts.map is (normally) a generated file (by the updmap
+% script). Instead, map files should be added to the updmap.cfg file.
+%
+% By default, xdvi will use psfonts.map if no map files have been specified,
+% so if the normal dvips config.ps file doesn't specify any map files, or if
+% the map files in config.ps are the ones to be used by xdvi, then this file
+% can be empty (or absent).
+%
+% p psfonts.map
diff --git a/configure b/configure
@@ -0,0 +1,4834 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --with-x-toolkit=PKG use X toolkit PKG (xaw, xaw3d, motif, or no) [xaw]"
+ac_help="$ac_help
+ --with-tetex compile for use with teTeX"
+ac_help="$ac_help
+ --disable-grey disable greyscale anti-aliasing for shrunken bitmaps"
+ac_help="$ac_help
+ --disable-color disable support for color specials"
+ac_help="$ac_help
+ --disable-buttons disable buttons on the side of the window"
+ac_help="$ac_help
+ --disable-make-pk disable automatic generation of pk files via mktexpk
+ --enable-make-pk=PATH specify path for mktexpk"
+ac_help="$ac_help
+ --enable-old-make-pk[=PATH]
+ use old-style MakeTeXPK script instead of mktexpk"
+ac_help="$ac_help
+ --enable-gf enable gf format pixel files (in addition to pk)"
+ac_help="$ac_help
+ --enable-ps-gs[=PATH] enable PostScript support via ghostscript
+ (PATH, if given, points to the gs interpreter)"
+ac_help="$ac_help
+ --enable-ps-dps enable PostScript support via Display PostScript"
+ac_help="$ac_help
+ --enable-ps-news enable PostScript support via NeWS (Sun OpenWin)"
+ac_help="$ac_help
+ --enable-config-file=PATHLIST
+ look for configuration file in PATHLIST"
+ac_help="$ac_help
+ --enable-self-auto[=PATHLIST]
+ same as above; also determine xdvi binary path"
+ac_help="$ac_help
+ --enable-extra-app-defaults[=PATHLIST]
+ same as above; also enable extra app-defaults file"
+ac_help="$ac_help
+ --enable-dosnames use DOS-style names for fonts (e.g., dpi300/cmr10.pk)"
+ac_help="$ac_help
+ --enable-a4 set default paper size to A4 and default unit to cm"
+ac_help="$ac_help
+ --enable-texxet enable typesetting for right-to-left languages"
+ac_help="$ac_help
+ --with-mfmode=MODE:DPI set default Metafont mode to MODE at DPI dots/inch
+ --without-mfmode set default Metafont mode to none"
+ac_help="$ac_help
+ --enable-freetype[=DIR] compile with the freetype2 library (default: enabled);
+ DIR=path of freetype-config binary"
+ac_help="$ac_help
+ --with-default-texmf-path=PATH
+ set default texmf list to PATH"
+ac_help="$ac_help
+ --with-default-font-path=PATH
+ set default font path to PATH"
+ac_help="$ac_help
+ --with-default-vf-path=PATH
+ set default virtual font path to PATH"
+ac_help="$ac_help
+ --with-default-header-path=PATH
+ set default path path for PS figures to PATH"
+ac_help="$ac_help
+ --with-default-fig-path=PATH
+ set default figure path to PATH"
+ac_help="$ac_help
+ --with-default-dvips-cf-path=PATH
+ set default dvips configuration file path to PATH"
+ac_help="$ac_help
+ --with-default-fontmap-path=PATH
+ set default path for fontmap files to PATH"
+ac_help="$ac_help
+ --with-default-enc-path=PATH
+ set default path for encoding files to PATH"
+ac_help="$ac_help
+ --with-default-type1-path=PATH
+ set default path for type 1 fonts to PATH"
+ac_help="$ac_help
+ --with-default-gs-lib-path=PATH
+ set default path for finding font aliases to PATH"
+ac_help="$ac_help
+ --with-default-source-path=PATH
+ set default path for source specials to PATH"
+ac_help="$ac_help
+ --with-default-dvips-path=CMD
+ set default print command to CMD"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+aux_top=NONE
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+imake=
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+x_top=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -aux-top | --aux-top | --aux-to | --aux-t | --aux- | --aux | --au | --a)
+ ac_prev=aux_top ;;
+ -aux-top=* | --aux-top=* | --aux-to=* | --aux-t=* | --aux-=* | --aux=* \
+ | --au=* | --a=*)
+ aux_top="$ac_optarg" ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --imake set flag for running from within imake
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --x-top=XTOP installation directory for X
+ --aux-top=AUXTOP secondary X top directory (e.g., for toolkit)
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [XTOP or $ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR [XTOP/include or guessed]
+ --x-libraries=DIR X library files are in DIR [XTOP/lib or guessed]
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ --imake | --imak | --ima | --im | -imake | -imak | -ima | -im)
+ imake=yes ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -x-top | --x-top | --x-to | --x-t)
+ ac_prev=x_top ;;
+ -x-top=* | --x-top=* | --x-to=* | --x-t=*)
+ x_top="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# Set prefix to x-top if appropriate.
+test "x$prefix" = xNONE && prefix="$x_top"
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=xdvi.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:631: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:661: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:712: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:744: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 755 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:786: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:791: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:800: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:819: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:881: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
+echo "configure:934: checking for Cygwin environment" >&5
+if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 939 "configure"
+#include "confdefs.h"
+
+int main() {
+
+#ifndef __CYGWIN__
+#define __CYGWIN__ __CYGWIN32__
+#endif
+return __CYGWIN__;
+; return 0; }
+EOF
+if { (eval echo configure:950: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_cygwin=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_cygwin=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_cygwin" 1>&6
+CYGWIN=
+test "$ac_cv_cygwin" = yes && CYGWIN=yes
+echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6
+echo "configure:967: checking for mingw32 environment" >&5
+if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 972 "configure"
+#include "confdefs.h"
+
+int main() {
+return __MINGW32__;
+; return 0; }
+EOF
+if { (eval echo configure:979: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_mingw32=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_mingw32=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_mingw32" 1>&6
+MINGW32=
+test "$ac_cv_mingw32" = yes && MINGW32=yes
+
+
+echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
+echo "configure:998: checking for executable suffix" >&5
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$CYGWIN" = yes || test "$MINGW32" = yes; then
+ ac_cv_exeext=.exe
+else
+ rm -f conftest*
+ echo 'int main () { return 0; }' > conftest.$ac_ext
+ ac_cv_exeext=
+ if { (eval echo configure:1008: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ for file in conftest.*; do
+ case $file in
+ *.c | *.o | *.obj) ;;
+ *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
+ esac
+ done
+ else
+ { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; }
+ fi
+ rm -f conftest*
+ test x"${ac_cv_exeext}" = x && ac_cv_exeext=no
+fi
+fi
+
+EXEEXT=""
+test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext}
+echo "$ac_t""${ac_cv_exeext}" 1>&6
+ac_exeext=$EXEEXT
+
+
+
+cat <<EOF >>confdefs.h
+#undef _XOPEN_SOURCE /* needed because of imake */
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+#define __EXTENSIONS__ 1
+#ifdef _AIX
+#define _ALL_SOURCE 1
+#endif
+EOF
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1042: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1057 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1063: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1074 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1080: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1091 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1097: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+# If we find X, set shell vars x_includes and x_libraries to the
+# paths, otherwise set no_x=yes.
+# Uses ac_ vars as temps to allow command line to override cache and checks.
+# --without-x overrides everything else, but does not touch the cache.
+echo $ac_n "checking for X""... $ac_c" 1>&6
+echo "configure:1126: checking for X" >&5
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then
+ # Both variables are already set.
+ have_x=yes
+ else
+if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+if test "x$x_top" != xNONE; then
+ ac_x_includes="$x_top/include" ac_x_libraries="$x_top/lib"
+ if test ! -f "$ac_x_includes/X11/Xos.h" || test ! -d "$ac_x_libraries"; then
+ { echo "configure: error: $x_top does not point to a valid X install tree" 1>&2; exit 1; }
+ fi
+else
+ ac_x_includes=NO ac_x_libraries=NO
+ rm -fr conftestdir
+if mkdir conftestdir; then
+ cd conftestdir
+ # Make sure to not put "make" in the Imakefile rules, since we grep it out.
+ cat > Imakefile <<'EOF'
+acfindx:
+ @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"'
+EOF
+ if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+ eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl; do
+ if test ! -f $ac_im_usrlibdir/libX11.$ac_extension &&
+ test -f $ac_im_libdir/libX11.$ac_extension; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case "$ac_im_incroot" in
+ /usr/include) ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;;
+ esac
+ case "$ac_im_usrlibdir" in
+ /usr/lib | /lib) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;;
+ esac
+ fi
+ cd ..
+ rm -fr conftestdir
+fi
+
+fi
+if test "$ac_x_includes" = NO; then
+ # Guess where to find include files, by looking for this one X11 .h file.
+ test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h
+
+ # First, try using that file with no special directory specified.
+cat > conftest.$ac_ext <<EOF
+#line 1189 "configure"
+#include "confdefs.h"
+#include <$x_direct_test_include>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1194: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ # Look for the header file in a standard set of common directories.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ for ac_dir in \
+ /usr/X11/include \
+ /usr/X11R6/include \
+ /usr/X11R5/include \
+ /usr/X11R4/include \
+ \
+ /usr/include/X11 \
+ /usr/include/X11R6 \
+ /usr/include/X11R5 \
+ /usr/include/X11R4 \
+ \
+ /usr/local/X11/include \
+ /usr/local/X11R6/include \
+ /usr/local/X11R5/include \
+ /usr/local/X11R4/include \
+ \
+ /usr/local/include/X11 \
+ /usr/local/include/X11R6 \
+ /usr/local/include/X11R5 \
+ /usr/local/include/X11R4 \
+ \
+ /usr/X386/include \
+ /usr/x386/include \
+ /usr/XFree86/include/X11 \
+ \
+ /usr/include \
+ /usr/local/include \
+ /usr/unsupported/include \
+ /usr/athena/include \
+ /usr/local/x11r5/include \
+ /usr/lpp/Xamples/include \
+ \
+ /usr/openwin/include \
+ /usr/openwin/share/include \
+ ; \
+ do
+ if test -r "$ac_dir/$x_direct_test_include"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+ done
+fi
+rm -f conftest*
+fi # $ac_x_includes = NO
+
+if test "$ac_x_libraries" = NO; then
+ # Check for the libraries.
+
+ test -z "$x_direct_test_library" && x_direct_test_library=Xt
+ test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc
+
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS="$LIBS"
+ LIBS="-l$x_direct_test_library $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1263 "configure"
+#include "confdefs.h"
+
+int main() {
+${x_direct_test_function}()
+; return 0; }
+EOF
+if { (eval echo configure:1270: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ LIBS="$ac_save_LIBS"
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$ac_save_LIBS"
+# First see if replacing the include by lib works.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \
+ /usr/X11/lib \
+ /usr/X11R6/lib \
+ /usr/X11R5/lib \
+ /usr/X11R4/lib \
+ \
+ /usr/lib/X11 \
+ /usr/lib/X11R6 \
+ /usr/lib/X11R5 \
+ /usr/lib/X11R4 \
+ \
+ /usr/local/X11/lib \
+ /usr/local/X11R6/lib \
+ /usr/local/X11R5/lib \
+ /usr/local/X11R4/lib \
+ \
+ /usr/local/lib/X11 \
+ /usr/local/lib/X11R6 \
+ /usr/local/lib/X11R5 \
+ /usr/local/lib/X11R4 \
+ \
+ /usr/X386/lib \
+ /usr/x386/lib \
+ /usr/XFree86/lib/X11 \
+ \
+ /usr/lib \
+ /usr/local/lib \
+ /usr/unsupported/lib \
+ /usr/athena/lib \
+ /usr/local/x11r5/lib \
+ /usr/lpp/Xamples/lib \
+ /lib/usr/lib/X11 \
+ \
+ /usr/openwin/lib \
+ /usr/openwin/share/lib \
+ ; \
+do
+ for ac_extension in a so sl; do
+ if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f conftest*
+fi # $ac_x_libraries = NO
+
+if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then
+ # Didn't find X anywhere. Cache the known absence of X.
+ ac_cv_have_x="have_x=no"
+else
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes \
+ ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries"
+fi
+fi
+ fi
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ echo "$ac_t""$have_x" 1>&6
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes \
+ ac_x_includes=$x_includes ac_x_libraries=$x_libraries"
+ echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6
+fi
+
+if test "$no_x" = yes || test -n "$imake"; then
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+ if test "x$aux_top" != xNONE; then
+ X_CFLAGS="$X_CFLAGS -I$aux_top/include"
+ X_LIBS="$X_LIBS -L$aux_top/lib"
+ fi
+
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ # It would also be nice to do this for all -L options, not just this one.
+ if test -n "$x_libraries"; then
+ X_LIBS="$X_LIBS -L$x_libraries"
+ # For Solaris; some versions of Sun CC require a space after -R and
+ # others require no space. Words are not sufficient . . . .
+ case "`(uname -sr) 2>/dev/null`" in
+ "SunOS 5"*)
+ echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6
+echo "configure:1376: checking whether -R must be followed by a space" >&5
+ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries"
+ cat > conftest.$ac_ext <<EOF
+#line 1379 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_R_nospace=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_R_nospace=no
+fi
+rm -f conftest*
+ if test $ac_R_nospace = yes; then
+ echo "$ac_t""no" 1>&6
+ if test "x$aux_top" != xNONE; then
+ X_LIBS="$X_LIBS -R$aux_top/lib"
+ fi
+ X_LIBS="$X_LIBS -R$x_libraries"
+ else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ cat > conftest.$ac_ext <<EOF
+#line 1405 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1412: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_R_space=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_R_space=no
+fi
+rm -f conftest*
+ if test $ac_R_space = yes; then
+ echo "$ac_t""yes" 1>&6
+ if test "x$aux_top" != xNONE; then
+ X_LIBS="$X_LIBS -R $aux_top/lib"
+ fi
+ X_LIBS="$X_LIBS -R $x_libraries"
+ else
+ echo "$ac_t""neither works" 1>&6
+ fi
+ fi
+ LIBS="$ac_xsave_LIBS"
+ esac
+ fi
+
+ # Check for system-dependent libraries X programs must link with.
+ # Do this before checking for the system-independent R6 libraries
+ # (-lICE), since we may need -lsocket or whatever for X linking.
+
+ if test "$ISC" = yes; then
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+ else
+ # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X
+ # libraries were built with DECnet support. And karl@cs.umb.edu says
+ # the Alpha needs dnet_stub (dnet does not exist).
+ echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6
+echo "configure:1447: checking for dnet_ntoa in -ldnet" >&5
+ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldnet $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1455 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dnet_ntoa();
+
+int main() {
+dnet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:1466: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+ echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6
+echo "configure:1488: checking for dnet_ntoa in -ldnet_stub" >&5
+ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldnet_stub $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1496 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dnet_ntoa();
+
+int main() {
+dnet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:1507: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+ # to get the SysV transport functions.
+ # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4)
+ # needs -lnsl.
+ # The nsl library prevents programs from opening the X display
+ # on Irix 5.2, according to dickey@clark.net.
+ echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:1536: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1541 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_gethostbyname = no; then
+ echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:1585: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1593 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1604: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # lieder@skyler.mavd.honeywell.com says without -lsocket,
+ # socket/setsockopt and other routines are undefined under SCO ODT
+ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
+ # on later versions), says simon@lia.di.epfl.ch: it contains
+ # gethostby* variants that don't use the nameserver (or something).
+ # -lsocket must be given before -lnsl if both are needed.
+ # We assume that if connect needs -lnsl, so does gethostbyname.
+ echo $ac_n "checking for connect""... $ac_c" 1>&6
+echo "configure:1634: checking for connect" >&5
+if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1639 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char connect(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_connect) || defined (__stub___connect)
+choke me
+#else
+connect();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1662: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_connect=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_connect=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_connect = no; then
+ echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6
+echo "configure:1683: checking for connect in -lsocket" >&5
+ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1691 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect();
+
+int main() {
+connect()
+; return 0; }
+EOF
+if { (eval echo configure:1702: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX.
+ echo $ac_n "checking for remove""... $ac_c" 1>&6
+echo "configure:1726: checking for remove" >&5
+if eval "test \"`echo '$''{'ac_cv_func_remove'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1731 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char remove(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char remove();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_remove) || defined (__stub___remove)
+choke me
+#else
+remove();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1754: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_remove=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_remove=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'remove`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_remove = no; then
+ echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6
+echo "configure:1775: checking for remove in -lposix" >&5
+ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lposix $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1783 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char remove();
+
+int main() {
+remove()
+; return 0; }
+EOF
+if { (eval echo configure:1794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+ echo $ac_n "checking for shmat""... $ac_c" 1>&6
+echo "configure:1818: checking for shmat" >&5
+if eval "test \"`echo '$''{'ac_cv_func_shmat'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1823 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shmat(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shmat();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shmat) || defined (__stub___shmat)
+choke me
+#else
+shmat();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1846: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_shmat=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_shmat=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'shmat`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_shmat = no; then
+ echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6
+echo "configure:1867: checking for shmat in -lipc" >&5
+ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lipc $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1875 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shmat();
+
+int main() {
+shmat()
+; return 0; }
+EOF
+if { (eval echo configure:1886: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+ fi
+
+ # Check for libraries that X11R6 Xt/Xaw programs need.
+ ac_save_LDFLAGS="$LDFLAGS"
+ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+ # check for ICE first), but we must link in the order -lSM -lICE or
+ # we get undefined symbols. So assume we have SM if we have ICE.
+ # These have to be linked with before -lX11, unlike the other
+ # libraries we check for below, so use a different variable.
+ # --interran@uluru.Stanford.EDU, kb@cs.umb.edu.
+ echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6
+echo "configure:1919: checking for IceConnectionNumber in -lICE" >&5
+ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1927 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char IceConnectionNumber();
+
+int main() {
+IceConnectionNumber()
+; return 0; }
+EOF
+if { (eval echo configure:1938: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ LDFLAGS="$ac_save_LDFLAGS"
+
+fi
+
+if test "x$have_x" != xyes; then
+ { echo "configure: error: this program cannot be compiled without X" 1>&2; exit 1; }
+fi
+
+ac_save_cpp=$ac_cpp
+ac_cpp="$ac_cpp $X_CFLAGS"
+for ac_hdr in X11/IntrinsicI.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1972: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1977 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1982: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ac_cpp=$ac_save_cpp
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:2012: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2017 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2025: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2042 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2060 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2081 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:2092: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+ echo $ac_n "checking for X11/Xosdefs.h""... $ac_c" 1>&6
+echo "configure:2114: checking for X11/Xosdefs.h" >&5
+if eval "test \"`echo '$''{'ac_cv_x11_xosdefs_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_x11_xosdefs_h=no
+ if test -n "$x_includes"; then
+ if test -r "$x_includes/X11/Xosdefs.h"; then
+ ac_cv_x11_xosdefs_h=yes
+ fi
+ else
+ cat > conftest.$ac_ext <<EOF
+#line 2125 "configure"
+#include "confdefs.h"
+#include <X11/Xosdefs.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2130: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_x11_xosdefs_h=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ fi
+fi
+
+echo "$ac_t""$ac_cv_x11_xosdefs_h" 1>&6
+ if test $ac_cv_x11_xosdefs_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_X11_XOSDEFS_H 1
+EOF
+
+ fi
+fi
+
+for ac_hdr in unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2157: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2162 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2167: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:2198: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2203 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:2211: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:2236: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2244 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2255: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:2277: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2285 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2296: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:2319: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2324 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:2340: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:2363: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 2370 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2381: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 2385 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2396: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_bigendian=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2416 "configure"
+#include "confdefs.h"
+main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+if { (eval echo configure:2429: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_bigendian=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+ cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo $ac_n "checking for integer type to use in bitmaps""... $ac_c" 1>&6
+echo "configure:2453: checking for integer type to use in bitmaps" >&5
+if eval "test \"`echo '$''{'xdvi_cv_bitmap_type'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2461 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ if ((sizeof(unsigned long) == 4 || sizeof(unsigned long) == 2)
+ && sizeof(unsigned long) != sizeof(unsigned int))
+ fprintf(f, "BMTYPE=long BMBYTES=%d\n", sizeof(unsigned long));
+ if (sizeof(unsigned int) == 4 || sizeof(unsigned int) == 2)
+ fprintf(f, "BMTYPE=int BMBYTES=%d\n", sizeof(unsigned int));
+ else if (sizeof(unsigned short) == 4 || sizeof(unsigned short) == 2)
+ fprintf(f, "BMTYPE=short BMBYTES=%d\n", sizeof(unsigned short));
+ else fprintf(f, "BMTYPE=char BMBYTES=%d\n", sizeof(unsigned char));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_cv_bitmap_type="`cat conftestval`"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ { echo "configure: error: could not determine integer type for bitmap" 1>&2; exit 1; }
+fi
+rm -fr conftest*
+fi
+
+fi
+
+eval "$xdvi_cv_bitmap_type"
+cat >> confdefs.h <<EOF
+#define BMTYPE $BMTYPE
+EOF
+
+cat >> confdefs.h <<EOF
+#define BMBYTES $BMBYTES
+EOF
+
+echo "$ac_t""unsigned $BMTYPE, size = $BMBYTES" 1>&6
+echo $ac_n "checking for whether the C compiler supports string concatenation""... $ac_c" 1>&6
+echo "configure:2504: checking for whether the C compiler supports string concatenation" >&5
+if eval "test \"`echo '$''{'xdvi_cc_concat'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2509 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+puts("Testing" " string" " concatenation");
+
+; return 0; }
+EOF
+if { (eval echo configure:2518: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ xdvi_cc_concat=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cc_concat=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cc_concat" 1>&6
+KRHEADER_H=
+if test $xdvi_cc_concat = no; then
+ cat >> confdefs.h <<\EOF
+#define CC_K_AND_R 1
+EOF
+
+ KRHEADER_H=krheader.h
+fi
+
+echo $ac_n "checking for stropts.h and isastream()""... $ac_c" 1>&6
+echo "configure:2541: checking for stropts.h and isastream()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_sys_streams'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2546 "configure"
+#include "confdefs.h"
+#include <stropts.h>
+
+int main() {
+#ifndef I_SETSIG
+choke me
+#else
+isastream(0);
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_cv_sys_streams=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cv_sys_streams=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cv_sys_streams" 1>&6
+if test $xdvi_cv_sys_streams = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STREAMS 1
+EOF
+
+fi
+echo $ac_n "checking for SunOS 4""... $ac_c" 1>&6
+echo "configure:2578: checking for SunOS 4" >&5
+if eval "test \"`echo '$''{'xdvi_cv_sys_sunos_4'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "`(uname -sr) 2>/dev/null`" in
+"SunOS 4."*)
+ xdvi_cv_sys_sunos_4=yes ;;
+*) xdvi_cv_sys_sunos_4=no ;;
+esac
+fi
+
+echo "$ac_t""$xdvi_cv_sys_sunos_4" 1>&6
+if test $xdvi_cv_sys_sunos_4 = yes; then
+ cat >> confdefs.h <<\EOF
+#define SUNOS4 1
+EOF
+
+fi
+echo $ac_n "checking for certain old versions of Linux""... $ac_c" 1>&6
+echo "configure:2597: checking for certain old versions of Linux" >&5
+if eval "test \"`echo '$''{'xdvi_cv_sys_old_linux'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "`(uname -sr) 2>/dev/null`" in
+"Linux 2."[01].* | "Linux 2.2."[0-8] | "Linux 2.2."[0-8]-*)
+ xdvi_cv_sys_old_linux=yes ;;
+*) xdvi_cv_sys_old_linux=no ;;
+esac
+fi
+
+echo "$ac_t""$xdvi_cv_sys_old_linux" 1>&6
+if test $xdvi_cv_sys_old_linux = yes; then
+ cat >> confdefs.h <<\EOF
+#define FLAKY_SIGPOLL 1
+EOF
+
+fi
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:2616: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2621 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:2649: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2654 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:2682: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2687 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6
+echo "configure:2715: checking for ptrdiff_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_ptrdiff_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2720 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])ptrdiff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_ptrdiff_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_ptrdiff_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_ptrdiff_t" 1>&6
+if test $ac_cv_type_ptrdiff_t = no; then
+ cat >> confdefs.h <<\EOF
+#define ptrdiff_t long
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2748: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2753 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2770: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for poll.h and poll()""... $ac_c" 1>&6
+echo "configure:2789: checking for poll.h and poll()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_func_poll'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2794 "configure"
+#include "confdefs.h"
+#include <poll.h>
+
+int main() {
+poll((struct pollfd *) 0, 0, 0);
+; return 0; }
+EOF
+if { (eval echo configure:2802: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_cv_func_poll=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cv_func_poll=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cv_func_poll" 1>&6
+if test $xdvi_cv_func_poll = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_POLL 1
+EOF
+
+else
+ for ac_hdr in sys/select.h select.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2825: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2830 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2835: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for vfork.h""... $ac_c" 1>&6
+echo "configure:2864: checking for vfork.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2869 "configure"
+#include "confdefs.h"
+#include <vfork.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2874: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_VFORK_H 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for working vfork""... $ac_c" 1>&6
+echo "configure:2899: checking for working vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo $ac_n "checking for vfork""... $ac_c" 1>&6
+echo "configure:2905: checking for vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2910 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vfork(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vfork();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vfork) || defined (__stub___vfork)
+choke me
+#else
+vfork();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2933: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_vfork=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_vfork=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2955 "configure"
+#include "confdefs.h"
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+ argument registers are propagated back to the parent.
+ The compiler is told about this with #include <vfork.h>,
+ but some compilers (e.g. gcc -O) don't grok <vfork.h>.
+ Test for this by using a static variable whose address
+ is put into a register that is clobbered by the vfork. */
+static
+#ifdef __cplusplus
+sparc_address_test (int arg)
+#else
+sparc_address_test (arg) int arg;
+#endif
+{
+ static pid_t child;
+ if (!child) {
+ child = vfork ();
+ if (child < 0) {
+ perror ("vfork");
+ _exit(2);
+ }
+ if (!child) {
+ arg = getpid();
+ write(-1, "", 0);
+ _exit (arg);
+ }
+ }
+}
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ sparc_address_test ();
+
+ child = vfork ();
+
+ if (child == 0) {
+ /* Here is another test for sparc vfork register problems.
+ This test uses lots of local variables, at least
+ as many local variables as main has allocated so far
+ including compiler temporaries. 4 locals are enough for
+ gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe.
+ A buggy compiler should reuse the register of parent
+ for one of the local variables, since it will think that
+ parent can't possibly be used any more in this routine.
+ Assigning to the local variable will thus munge parent
+ in the parent process. */
+ pid_t
+ p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+ p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+ /* Convince the compiler that p..p7 are live; otherwise, it might
+ use the same hardware register for all 8 local variables. */
+ if (p != p1 || p != p2 || p != p3 || p != p4
+ || p != p5 || p != p6 || p != p7)
+ _exit(1);
+
+ /* On some systems (e.g. IRIX 3.3),
+ vfork doesn't separate parent from child file descriptors.
+ If the child closes a descriptor before it execs or exits,
+ this munges the parent's descriptor as well.
+ Test for this by closing stdout in the child. */
+ _exit(close(fileno(stdout)) != 0);
+ } else {
+ int status;
+ struct stat st;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+
+ /* Did the vfork/compiler bug occur? */
+ || parent != getpid()
+
+ /* Did the file descriptor bug occur? */
+ || fstat(fileno(stdout), &st) != 0
+ );
+ }
+}
+EOF
+if { (eval echo configure:3050: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_vfork_works=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_vfork_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_vfork_works" 1>&6
+if test $ac_cv_func_vfork_works = no; then
+ cat >> confdefs.h <<\EOF
+#define vfork fork
+EOF
+
+fi
+
+if test $ac_cv_func_vfork_works = yes; then
+echo $ac_n "checking for whether setsid() is allowed within vfork()""... $ac_c" 1>&6
+echo "configure:3074: checking for whether setsid() is allowed within vfork()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_setsid_in_vfork'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3082 "configure"
+#include "confdefs.h"
+/* Test adapted from Gnu autoconf */
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+int
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ child = vfork ();
+
+ if (child == 0) {
+ if (setsid () == -1)
+ _exit(1);
+ _exit(0);
+ } else {
+ int status;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+ );
+ }
+}
+EOF
+if { (eval echo configure:3121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_cv_setsid_in_vfork=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ xdvi_cv_setsid_in_vfork=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$xdvi_cv_setsid_in_vfork" 1>&6
+if test $xdvi_cv_setsid_in_vfork = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GOOD_SETSID_VFORK 1
+EOF
+
+fi
+fi
+echo $ac_n "checking for waitpid""... $ac_c" 1>&6
+echo "configure:3144: checking for waitpid" >&5
+if eval "test \"`echo '$''{'ac_cv_func_waitpid'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3149 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char waitpid(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char waitpid();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_waitpid) || defined (__stub___waitpid)
+choke me
+#else
+waitpid();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3172: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_waitpid=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_waitpid=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'waitpid`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_WAITPID 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+for ac_func in wait4
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3195: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3200 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3223: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking for putenv""... $ac_c" 1>&6
+echo "configure:3250: checking for putenv" >&5
+if eval "test \"`echo '$''{'ac_cv_func_putenv'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3255 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char putenv(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char putenv();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_putenv) || defined (__stub___putenv)
+choke me
+#else
+putenv();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3278: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_putenv=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_putenv=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'putenv`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_PUTENV 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+for ac_func in setenv
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3301: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3306 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3329: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+for ac_func in mkstemp sigaction strerror vsnprintf vasprintf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3358: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3363 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+if test $ac_cv_func_vsnprintf = yes; then
+ echo $ac_n "checking for a c99-compatible implementation of (v)snprintf()""... $ac_c" 1>&6
+echo "configure:3413: checking for a c99-compatible implementation of (v)snprintf()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_func_good_vsnprintf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3421 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main()
+{
+ char s[2];
+ return (snprintf(s, 0, "test") != 4);
+}
+EOF
+if { (eval echo configure:3430: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_cv_func_good_vsnprintf=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ xdvi_cv_func_good_vsnprintf=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$xdvi_cv_func_good_vsnprintf" 1>&6
+if test $xdvi_cv_func_good_vsnprintf = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GOOD_VSNPRINTF 1
+EOF
+
+fi
+fi
+
+MATH_LIB=
+echo $ac_n "checking for sin""... $ac_c" 1>&6
+echo "configure:3455: checking for sin" >&5
+if eval "test \"`echo '$''{'ac_cv_func_sin'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3460 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char sin(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sin();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_sin) || defined (__stub___sin)
+choke me
+#else
+sin();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_sin=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_sin=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'sin`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for sin in -lm""... $ac_c" 1>&6
+echo "configure:3501: checking for sin in -lm" >&5
+ac_lib_var=`echo m'_'sin | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lm $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3509 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sin();
+
+int main() {
+sin()
+; return 0; }
+EOF
+if { (eval echo configure:3520: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ MATH_LIB="-lm"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+
+echo $ac_n "checking whether linker supports the --allow-multiple-definition flag""... $ac_c" 1>&6
+echo "configure:3545: checking whether linker supports the --allow-multiple-definition flag" >&5
+if eval "test \"`echo '$''{'xdvi_linker_multiple_defns'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ xdvi_save_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Xlinker --allow-multiple-definition"
+x_linker_options=""
+cat > conftest.$ac_ext <<EOF
+#line 3553 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+void foo(void);
+
+; return 0; }
+EOF
+if { (eval echo configure:3562: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_linker_multiple_defns=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_linker_multiple_defns=no
+
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$xdvi_linker_multiple_defns" 1>&6
+if test $xdvi_linker_multiple_defns = yes; then
+x_linker_options="-Xlinker --allow-multiple-definition"
+fi
+LDFLAGS="$xdvi_save_LDFLAGS"
+
+
+
+
+OPT_SRCS= OPT_OBJS=
+
+# Check whether --with-x-toolkit or --without-x-toolkit was given.
+if test "${with_x_toolkit+set}" = set; then
+ withval="$with_x_toolkit"
+ case "$withval" in
+yes | xaw)
+ X_PRE_LIBS="$X_PRE_LIBS $MATH_LIB"
+ MATH_LIB=
+ if test -z "$imake"; then
+# Cygwin needs -lXpm to be linked in explicitly; yet on older (<4.2)
+# versions of XFree86, -lXpm exists, but is not needed. So we do two checks.
+echo $ac_n "checking for whether -lXpm needs to be explicitly given""... $ac_c" 1>&6
+echo "configure:3598: checking for whether -lXpm needs to be explicitly given" >&5
+if eval "test \"`echo '$''{'xdvi_needs_explicit_xpm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ xdvi_save_LIBS=$LIBS
+LIBS="-lXaw -lXmu -lXt$X_PRE_LIBS -lXext $LIBS $X_LIBS -lX11"
+cat > conftest.$ac_ext <<EOF
+#line 3605 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XawTextReplace();
+
+int main() {
+XawTextReplace()
+; return 0; }
+EOF
+if { (eval echo configure:3616: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$LIBS -lXpm"
+cat > conftest.$ac_ext <<EOF
+#line 3625 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XawTextReplace();
+
+int main() {
+XawTextReplace()
+; return 0; }
+EOF
+if { (eval echo configure:3636: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=unknown
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+LIBS=$xdvi_save_LIBS
+fi
+
+echo "$ac_t""$xdvi_needs_explicit_xpm" 1>&6
+if test "$xdvi_needs_explicit_xpm" = yes; then
+ X_PRE_LIBS=" -lXpm$X_PRE_LIBS"
+fi
+fi
+ X_PRE_LIBS=" -lXaw -lXmu -lXt$X_PRE_LIBS -lXext"
+ cat >> confdefs.h <<\EOF
+#define XAW 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o" ;;
+xaw3d)
+ X_PRE_LIBS="$X_PRE_LIBS $MATH_LIB"
+ MATH_LIB=
+ if test -z "$imake"; then
+# Cygwin needs -lXpm to be linked in explicitly; yet on older (<4.2)
+# versions of XFree86, -lXpm exists, but is not needed. So we do two checks.
+echo $ac_n "checking for whether -lXpm needs to be explicitly given""... $ac_c" 1>&6
+echo "configure:3670: checking for whether -lXpm needs to be explicitly given" >&5
+if eval "test \"`echo '$''{'xdvi_needs_explicit_xpm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ xdvi_save_LIBS=$LIBS
+LIBS="-lXaw3d -lXmu -lXt$X_PRE_LIBS -lXext $LIBS $X_LIBS -lX11"
+cat > conftest.$ac_ext <<EOF
+#line 3677 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XawTextReplace();
+
+int main() {
+XawTextReplace()
+; return 0; }
+EOF
+if { (eval echo configure:3688: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$LIBS -lXpm"
+cat > conftest.$ac_ext <<EOF
+#line 3697 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XawTextReplace();
+
+int main() {
+XawTextReplace()
+; return 0; }
+EOF
+if { (eval echo configure:3708: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=unknown
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+LIBS=$xdvi_save_LIBS
+fi
+
+echo "$ac_t""$xdvi_needs_explicit_xpm" 1>&6
+if test "$xdvi_needs_explicit_xpm" = yes; then
+ X_PRE_LIBS=" -lXpm$X_PRE_LIBS"
+fi
+fi
+ X_PRE_LIBS=" -lXaw3d -lXmu -lXt$X_PRE_LIBS -lXext"
+ cat >> confdefs.h <<\EOF
+#define XAW 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define XAW3D 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o" ;;
+motif)
+ X_PRE_LIBS=" -lXm -lXmu -lXt$X_PRE_LIBS -lXext"
+ cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o" ;;
+no)
+ X_PRE_LIBS=
+ X_EXT_LIBS=" -lXext" ;;
+*)
+ { echo "configure: error: invalid toolkit $withval given" 1>&2; exit 1; } ;;
+esac
+
+else
+ X_PRE_LIBS="$X_PRE_LIBS $MATH_LIB"
+ MATH_LIB=
+ if test -z "$imake"; then
+# Cygwin needs -lXpm to be linked in explicitly; yet on older (<4.2)
+# versions of XFree86, -lXpm exists, but is not needed. So we do two checks.
+echo $ac_n "checking for whether -lXpm needs to be explicitly given""... $ac_c" 1>&6
+echo "configure:3761: checking for whether -lXpm needs to be explicitly given" >&5
+if eval "test \"`echo '$''{'xdvi_needs_explicit_xpm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ xdvi_save_LIBS=$LIBS
+LIBS="-lXaw -lXmu -lXt$X_PRE_LIBS -lXext $LIBS $X_LIBS -lX11"
+cat > conftest.$ac_ext <<EOF
+#line 3768 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XawTextReplace();
+
+int main() {
+XawTextReplace()
+; return 0; }
+EOF
+if { (eval echo configure:3779: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$LIBS -lXpm"
+cat > conftest.$ac_ext <<EOF
+#line 3788 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XawTextReplace();
+
+int main() {
+XawTextReplace()
+; return 0; }
+EOF
+if { (eval echo configure:3799: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_needs_explicit_xpm=unknown
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+LIBS=$xdvi_save_LIBS
+fi
+
+echo "$ac_t""$xdvi_needs_explicit_xpm" 1>&6
+if test "$xdvi_needs_explicit_xpm" = yes; then
+ X_PRE_LIBS=" -lXpm$X_PRE_LIBS"
+fi
+fi
+ X_PRE_LIBS=" -lXaw -lXmu -lXt$X_PRE_LIBS -lXext"
+ cat >> confdefs.h <<\EOF
+#define XAW 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o"
+fi
+
+
+
+echo $ac_n "checking for XKB Bell extension""... $ac_c" 1>&6
+echo "configure:3831: checking for XKB Bell extension" >&5
+if eval "test \"`echo '$''{'xdvi_cv_xkb_bell_ext'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ xdvi_save_LIBS=$LIBS
+LIBS="$X_PRE_LIBS""$X_EXT_LIBS"" $LIBS $X_LIBS -lX11"
+cat > conftest.$ac_ext <<EOF
+#line 3838 "configure"
+#include "confdefs.h"
+
+#include <X11/X.h>
+#include <X11/XKBlib.h> /* has the prototype */
+
+int main() {
+
+ Atom y;
+ XkbBell((Display *)0, (Window)0, 0, y);
+
+; return 0; }
+EOF
+if { (eval echo configure:3851: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_cv_xkb_bell_ext=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cv_xkb_bell_ext=no
+fi
+rm -f conftest*
+LIBS=$xdvi_save_LIBS
+fi
+
+echo "$ac_t""$xdvi_cv_xkb_bell_ext" 1>&6
+if test "$xdvi_cv_xkb_bell_ext" = yes; then
+ X_PRE_LIBS="$X_PRE_LIBS""$X_EXT_LIBS"
+ cat >> confdefs.h <<\EOF
+#define HAVE_XKB_BELL_EXT 1
+EOF
+
+fi
+
+# Check whether --with-tetex or --without-tetex was given.
+if test "${with_tetex+set}" = set; then
+ withval="$with_tetex"
+ if test "$withval" != "no"; then
+ if test "${enable_ps_gs+set}" != set; then
+ enable_ps_gs=yes
+ fi
+ if test "${enable_extra_app_defaults+set}" != set; then
+ enable_extra_app_defaults="$withval"
+ fi
+ if test "${enable_dosnames+set}" != set; then
+ enable_dosnames=yes
+ fi
+fi
+
+fi
+
+
+# Check whether --enable-grey or --disable-grey was given.
+if test "${enable_grey+set}" = set; then
+ enableval="$enable_grey"
+ if test "$enableval" = yes; then
+ cat >> confdefs.h <<\EOF
+#define GREY 1
+EOF
+
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define GREY 1
+EOF
+
+fi
+
+
+# Check whether --enable-color or --disable-color was given.
+if test "${enable_color+set}" = set; then
+ enableval="$enable_color"
+ if test "$enableval" = yes; then
+ cat >> confdefs.h <<\EOF
+#define COLOR 1
+EOF
+
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define COLOR 1
+EOF
+
+fi
+
+
+# Check whether --enable-buttons or --disable-buttons was given.
+if test "${enable_buttons+set}" = set; then
+ enableval="$enable_buttons"
+ if test "$enableval" = yes; then
+ cat >> confdefs.h <<\EOF
+#define BUTTONS 1
+EOF
+
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define BUTTONS 1
+EOF
+
+fi
+
+
+# Check whether --enable-make-pk or --disable-make-pk was given.
+if test "${enable_make_pk+set}" = set; then
+ enableval="$enable_make_pk"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define MKTEXPK 1
+EOF
+
+ if test "$enableval" != yes; then
+ cat >> confdefs.h <<EOF
+#define MKTEXPK_PATH "$enableval"
+EOF
+
+ fi
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define MKTEXPK 1
+EOF
+
+fi
+
+
+# Check whether --enable-old-make-pk or --disable-old-make-pk was given.
+if test "${enable_old_make_pk+set}" = set; then
+ enableval="$enable_old_make_pk"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define MKTEXPK 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define MAKETEXPK 1
+EOF
+
+ if test "$enableval" != yes; then
+ cat >> confdefs.h <<EOF
+#define MKTEXPK_PATH "$enableval"
+EOF
+
+ fi
+fi
+fi
+
+
+# Check whether --enable-gf or --disable-gf was given.
+if test "${enable_gf+set}" = set; then
+ enableval="$enable_gf"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define USE_GF 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS gf.c"
+ OPT_OBJS="$OPT_OBJS gf.o"
+fi
+fi
+
+
+xdvi_ps_c= xdvi_ps_o= xdvi_need_gs_lib=
+# Check whether --enable-ps-gs or --disable-ps-gs was given.
+if test "${enable_ps_gs+set}" = set; then
+ enableval="$enable_ps_gs"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define PS_GS 1
+EOF
+
+ xdvi_ps_c=" psgs.c"
+ xdvi_ps_o=" psgs.o"
+ if test "$enableval" != yes; then
+ cat >> confdefs.h <<EOF
+#define GS_PATH "$enableval"
+EOF
+
+ fi
+fi
+fi
+
+
+# Check whether --enable-ps-dps or --disable-ps-dps was given.
+if test "${enable_ps_dps+set}" = set; then
+ enableval="$enable_ps_dps"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define PS_DPS 1
+EOF
+
+ xdvi_ps_c="$xdvi_ps_c psdps.c"
+ xdvi_ps_o="$xdvi_ps_o psdps.o"
+ X_PRE_LIBS=" -ldps$X_PRE_LIBS"
+ # Work around a bug in Solaris 2. This doesn't work with imake.
+ if test "x$x_includes" = x/usr/openwin/include && test ! -d $x_includes/DPS \
+ && test -d $x_includes/X11/DPS; then
+ CFLAGS="$CFLAGS -I$x_includes/X11"
+ fi
+fi
+fi
+
+
+# Check whether --enable-ps-news or --disable-ps-news was given.
+if test "${enable_ps_news+set}" = set; then
+ enableval="$enable_ps_news"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define PS_NEWS 1
+EOF
+
+ xdvi_ps_c="$xdvi_ps_c psnews.c"
+ xdvi_ps_o="$xdvi_ps_o psnews.o"
+ X_PRE_LIBS=" -u _xv_psview_pkg -lxvps -lxview -lcps -lolgx$X_PRE_LIBS"
+fi
+fi
+
+
+if test -n "$xdvi_ps_c"; then
+ OPT_SRCS="$OPT_SRCS psheader.c$xdvi_ps_c"
+ OPT_OBJS="$OPT_OBJS psheader.o$xdvi_ps_o"
+ xdvi_need_gs_lib=y
+fi
+
+# Check whether --enable-config-file or --disable-config-file was given.
+if test "${enable_config_file+set}" = set; then
+ enableval="$enable_config_file"
+ if test "$enableval" != no; then
+ if test "$enableval" = yes; then
+ { echo "configure: error: Option \`--enable-config-file' requires an argument" 1>&2; exit 1; }
+ fi
+ cat >> confdefs.h <<EOF
+#define DEFAULT_CONFIG_PATH "$enableval"
+EOF
+
+fi
+fi
+
+
+# Check whether --enable-self-auto or --disable-self-auto was given.
+if test "${enable_self_auto+set}" = set; then
+ enableval="$enable_self_auto"
+ if test "$enableval" != no; then
+ if test "$enableval" != yes; then
+ cat >> confdefs.h <<EOF
+#define DEFAULT_CONFIG_PATH "$enableval"
+EOF
+
+ fi
+ cat >> confdefs.h <<\EOF
+#define SELFAUTO 1
+EOF
+
+fi
+fi
+
+
+# Check whether --enable-extra-app-defaults or --disable-extra-app-defaults was given.
+if test "${enable_extra_app_defaults+set}" = set; then
+ enableval="$enable_extra_app_defaults"
+ if test "$enableval" != no; then
+ if test "$enableval" != yes; then
+ cat >> confdefs.h <<EOF
+#define DEFAULT_CONFIG_PATH "$enableval"
+EOF
+
+ fi
+ cat >> confdefs.h <<\EOF
+#define EXTRA_APP_DEFAULTS 1
+EOF
+
+fi
+fi
+
+
+# Check whether --enable-dosnames or --disable-dosnames was given.
+if test "${enable_dosnames+set}" = set; then
+ enableval="$enable_dosnames"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define DOSNAMES 1
+EOF
+
+fi
+fi
+
+
+# Check whether --enable-a4 or --disable-a4 was given.
+if test "${enable_a4+set}" = set; then
+ enableval="$enable_a4"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define A4 1
+EOF
+
+fi
+fi
+
+
+# Check whether --enable-texxet or --disable-texxet was given.
+if test "${enable_texxet+set}" = set; then
+ enableval="$enable_texxet"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define TEXXET 1
+EOF
+
+fi
+fi
+
+
+# Check whether --with-mfmode or --without-mfmode was given.
+if test "${with_mfmode+set}" = set; then
+ withval="$with_mfmode"
+ if test "x$withval" != xno; then
+ echo "$withval" | grep ':[0-9][0-9]*$' >/dev/null 2>&1 \
+ || echo "configure: warning: the mfmode should end with a dots-per-inch value" 1>&2
+ cat >> confdefs.h <<EOF
+#define MFMODE "$withval"
+EOF
+
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define MFMODE "cx:300"
+EOF
+
+fi
+
+
+# Extra libraries
+EXTRA_CPPFLAGS=
+EXTRA_LIBS=
+
+# Check whether --enable-freetype or --disable-freetype was given.
+if test "${enable_freetype+set}" = set; then
+ enableval="$enable_freetype"
+ if test "x$enableval" != xno; then
+ xdvi_freetype_config=freetype-config
+ if test "x$enableval" != xyes; then
+ if test -x "$enableval/freetype-config"; then
+ xdvi_freetype_config="$enableval/freetype-config"
+ elif test -x "$enableval/bin/freetype-config"; then
+ xdvi_freetype_config="$enableval/bin/freetype-config"
+ else
+ echo "configure: warning: Cannot find $enableval/freetype-config or $enableval/bin/freetype-config" 1>&2
+ fi
+ fi
+ EXTRA_CPPFLAGS="$EXTRA_CPPFLAGS `$xdvi_freetype_config --cflags`"
+ EXTRA_LIBS="$EXTRA_LIBS `$xdvi_freetype_config --libs`"
+ cat >> confdefs.h <<\EOF
+#define FREETYPE 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS ft.c"
+ OPT_OBJS="$OPT_OBJS ft.o"
+ xdvi_need_gs_lib=y
+fi
+else
+ if freetype-config --cflags >conftest.cflags 2>/dev/null \
+ && freetype-config --libs >conftest.libs 2>/dev/null ; then
+ EXTRA_CPPFLAGS="$EXTRA_CPPFLAGS `cat conftest.cflags`"
+ EXTRA_LIBS="$EXTRA_LIBS `cat conftest.libs`"
+ rm -f conftest.cflags conftest.libs
+ cat >> confdefs.h <<\EOF
+#define FREETYPE 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS ft.c"
+ OPT_OBJS="$OPT_OBJS ft.o"
+ xdvi_need_gs_lib=y
+fi
+fi
+
+
+
+
+
+# End extra libraries section
+
+# Check whether --with-default-texmf-path or --without-default-texmf-path was given.
+if test "${with_default_texmf_path+set}" = set; then
+ withval="$with_default_texmf_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_TEXMF_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_TEXMF_PATH "/usr/local/tex/texmf"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-font-path or --without-default-font-path was given.
+if test "${with_default_font_path+set}" = set; then
+ withval="$with_default_font_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_FONT_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_FONT_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-vf-path or --without-default-vf-path was given.
+if test "${with_default_vf_path+set}" = set; then
+ withval="$with_default_vf_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_VF_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_VF_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-header-path or --without-default-header-path was given.
+if test "${with_default_header_path+set}" = set; then
+ withval="$with_default_header_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_HEADER_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_HEADER_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-fig-path or --without-default-fig-path was given.
+if test "${with_default_fig_path+set}" = set; then
+ withval="$with_default_fig_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_FIG_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_FIG_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-dvips-cf-path or --without-default-dvips-cf-path was given.
+if test "${with_default_dvips_cf_path+set}" = set; then
+ withval="$with_default_dvips_cf_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_DVIPS_CF_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_DVIPS_CF_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-fontmap-path or --without-default-fontmap-path was given.
+if test "${with_default_fontmap_path+set}" = set; then
+ withval="$with_default_fontmap_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_FONTMAP_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_FONTMAP_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-enc-path or --without-default-enc-path was given.
+if test "${with_default_enc_path+set}" = set; then
+ withval="$with_default_enc_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_ENC_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_ENC_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-type1-path or --without-default-type1-path was given.
+if test "${with_default_type1_path+set}" = set; then
+ withval="$with_default_type1_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_TYPE1_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_TYPE1_PATH ".:%S"
+EOF
+
+
+fi
+
+
+if test -n "$xdvi_need_gs_lib"; then
+ # Check whether --with-default-gs-lib-path or --without-default-gs-lib-path was given.
+if test "${with_default_gs_lib_path+set}" = set; then
+ withval="$with_default_gs_lib_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_GS_LIB_PATH "$withval"
+EOF
+
+
+else
+ echo $ac_n "checking for the path to be used for Ghostscript searches""... $ac_c" 1>&6
+echo "configure:4383: checking for the path to be used for Ghostscript searches" >&5
+if eval "test \"`echo '$''{'xdvi_gs_lib_path'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if gs -h >/dev/null 2>&1; then
+ ac_tmp="`gs -h \
+ | sed \
+ -e '1,/Search path:/d' \
+ -e '/For more information/,$d' \
+ -e '/Initialization files are compiled/d' \
+ -e 's/$/\/\/\//' \
+ -e 's/^ //' \
+ | tr '\n' '/'`"
+ # Solaris 9 sed doesn't handle incomplete lines at eof
+ xdvi_gs_lib_path=`echo "$ac_tmp" \
+ | sed -e 's/\/\/\/\// /g' -e 's/ *$//' -e 's/ : /:/g'`
+else
+ xdvi_gs_lib_path=none
+fi
+fi
+
+echo "$ac_t""$xdvi_gs_lib_path" 1>&6
+if test "$xdvi_gs_lib_path" != none; then
+ cat >> confdefs.h <<EOF
+#define DEFAULT_GS_LIB_PATH "$xdvi_gs_lib_path"
+EOF
+
+else
+ echo "configure: warning: Could not determine Ghostscript search path" 1>&2
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_GS_LIB_PATH NULL
+EOF
+
+fi
+
+fi
+
+fi
+
+# Check whether --with-default-source-path or --without-default-source-path was given.
+if test "${with_default_source_path+set}" = set; then
+ withval="$with_default_source_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_SOURCE_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_SOURCE_PATH ".:%S"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-dvips-path or --without-default-dvips-path was given.
+if test "${with_default_dvips_path+set}" = set; then
+ withval="$with_default_dvips_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_DVIPS_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_DVIPS_PATH "dvips"
+EOF
+
+
+fi
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# A kludge necessary for CPPFLAGS to allow quoted args
+CPPFLAGS="`echo "$CPPFLAGS" | sed 's/\\\"/\\\\\\\"/g'`"
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo " config.h:config.hin" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@x_top@%$x_top%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@EXEEXT@%$EXEEXT%g
+s%@CPP@%$CPP%g
+s%@X_CFLAGS@%$X_CFLAGS%g
+s%@X_PRE_LIBS@%$X_PRE_LIBS%g
+s%@X_LIBS@%$X_LIBS%g
+s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g
+s%@KRHEADER_H@%$KRHEADER_H%g
+s%@MATH_LIB@%$MATH_LIB%g
+s%@x_linker_options@%$x_linker_options%g
+s%@EXTRA_CPPFLAGS@%$EXTRA_CPPFLAGS%g
+s%@EXTRA_LIBS@%$EXTRA_LIBS%g
+s%@OPT_SRCS@%$OPT_SRCS%g
+s%@OPT_OBJS@%$OPT_OBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+if test -n "$imake"; then
+ ac_noimake_makefile=
+else
+ ac_noimake_makefile='Makefile '
+fi
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"$ac_noimake_makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h:config.hin"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
@@ -0,0 +1,388 @@
+dnl Process this file with xautoconf (not autoconf!) to produce a
+dnl configure script. See xautocnf.txt for details on xautoconf.
+dnl
+AC_INIT(xdvi.c)
+AC_CONFIG_HEADER(config.h:config.hin)
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_EXEEXT
+
+dnl ### Some O/S dependent kludges.
+
+cat <<EOF >>confdefs.h
+#undef _XOPEN_SOURCE /* needed because of imake */
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+#define __EXTENSIONS__ 1
+#ifdef _AIX
+#define _ALL_SOURCE 1
+#endif
+EOF
+
+dnl ### X setup.
+
+AC_PATH_X
+AC_PATH_XTRA
+AC_REQUIRE_X
+
+ac_save_cpp=$ac_cpp
+ac_cpp="$ac_cpp $X_CFLAGS"
+AC_CHECK_HEADERS(X11/IntrinsicI.h)
+ac_cpp=$ac_save_cpp
+
+dnl ### Header files.
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS(unistd.h)
+AC_HEADER_DIRENT
+AC_HEADER_SYS_WAIT
+dnl
+dnl No AC_HEADER_STAT: I don't think X runs on the indicated systems.
+dnl No AC_HEADER_TIME: I don't use struct tm, just structs timeval & timezone.
+dnl <X11/Xos.h> takes care of <sys/types.h>, <string(s).h>, <malloc.h>,
+dnl <fcntl.h>, and structs timeval and timezone.
+
+dnl ### Functions, etc.
+
+AC_C_BIGENDIAN
+XDVI_C_BITMAP_TYPE
+XDVI_CC_CONCAT
+XDVI_SYS_STREAMS
+XDVI_SYS_SUNOS_4
+XDVI_SYS_OLD_LINUX
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_TYPE([ptrdiff_t], [long])
+AC_TYPE_SIGNAL
+dnl AC_CHECK_TYPE(ino_t, unsigned long) [Is this needed for any system?]
+XDVI_FUNC_POLL
+AC_FUNC_VFORK
+XDVI_FUNC_SETSID_IN_VFORK
+AC_CHECK_FUNC(waitpid, AC_DEFINE(HAVE_WAITPID), AC_CHECK_FUNCS(wait4))
+AC_CHECK_FUNC(putenv, AC_DEFINE(HAVE_PUTENV), AC_CHECK_FUNCS(setenv))
+AC_CHECK_FUNCS(mkstemp sigaction strerror vsnprintf vasprintf)
+
+if test $ac_cv_func_vsnprintf = yes; then
+ XDVI_FUNC_C99_VSNPRINTF
+fi
+
+MATH_LIB=
+AC_CHECK_FUNC(sin,, AC_CHECK_LIB(m, sin,[MATH_LIB="-lm"]))
+AC_SUBST(MATH_LIB)
+
+dnl for `--allow-multiple-definition' linker flag on Cygwin
+XDVI_LINKER_MULTIPLE_DEFNS
+
+dnl No AC_C_CONST: X takes care of it.
+dnl No AC_FUNC_MEMCMP: I only check memcmp() == 0.
+dnl No AC_FUNC_CLOSEDIR_VOID: Too lazy.
+
+dnl ### Program compilation options
+
+OPT_SRCS= OPT_OBJS=
+
+AC_ARG_WITH(x-toolkit,
+[ --with-x-toolkit=PKG use X toolkit PKG (xaw, xaw3d, motif, or no) [xaw]],
+[case "$withval" in
+yes | xaw)
+ X_PRE_LIBS="$X_PRE_LIBS $MATH_LIB"
+ MATH_LIB=
+ XDVI_CHECK_XPM([Xaw])
+ X_PRE_LIBS=" -lXaw -lXmu -lXt$X_PRE_LIBS -lXext"
+ AC_DEFINE(XAW)
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o" ;;
+xaw3d)
+ X_PRE_LIBS="$X_PRE_LIBS $MATH_LIB"
+ MATH_LIB=
+ XDVI_CHECK_XPM([Xaw3d])
+ X_PRE_LIBS=" -lXaw3d -lXmu -lXt$X_PRE_LIBS -lXext"
+ AC_DEFINE(XAW)
+ AC_DEFINE(XAW3D)
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o" ;;
+motif)
+ X_PRE_LIBS=" -lXm -lXmu -lXt$X_PRE_LIBS -lXext"
+ AC_DEFINE(MOTIF)
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o" ;;
+no)
+ X_PRE_LIBS=
+ X_EXT_LIBS=" -lXext" ;;
+*)
+ AC_MSG_ERROR(invalid toolkit $withval given) ;;
+esac
+],
+[X_PRE_LIBS="$X_PRE_LIBS $MATH_LIB"
+ MATH_LIB=
+ XDVI_CHECK_XPM([Xaw])
+ X_PRE_LIBS=" -lXaw -lXmu -lXt$X_PRE_LIBS -lXext"
+ AC_DEFINE(XAW)
+ OPT_SRCS="$OPT_SRCS popups.c"
+ OPT_OBJS="$OPT_OBJS popups.o"])
+
+XDVI_XKB_BELL_EXT("$X_EXT_LIBS")
+
+AC_ARG_WITH(tetex,
+[ --with-tetex compile for use with teTeX],
+[if test "$withval" != "no"; then
+ if test "${enable_ps_gs+set}" != set; then
+ enable_ps_gs=yes
+ fi
+ if test "${enable_extra_app_defaults+set}" != set; then
+ enable_extra_app_defaults="$withval"
+ fi
+ if test "${enable_dosnames+set}" != set; then
+ enable_dosnames=yes
+ fi
+fi
+])
+
+AC_ARG_ENABLE(grey,
+[ --disable-grey disable greyscale anti-aliasing for shrunken bitmaps],
+[if test "$enableval" = yes; then
+ AC_DEFINE(GREY)
+fi],
+AC_DEFINE(GREY))
+
+AC_ARG_ENABLE(color,
+[ --disable-color disable support for color specials],
+[if test "$enableval" = yes; then
+ AC_DEFINE(COLOR)
+fi],
+AC_DEFINE(COLOR))
+
+AC_ARG_ENABLE(buttons,
+[ --disable-buttons disable buttons on the side of the window],
+[if test "$enableval" = yes; then
+ AC_DEFINE(BUTTONS)
+fi],
+AC_DEFINE(BUTTONS))
+
+AC_ARG_ENABLE(make-pk,
+[ --disable-make-pk disable automatic generation of pk files via mktexpk
+ --enable-make-pk=PATH specify path for mktexpk],
+[if test "$enableval" != no; then
+ AC_DEFINE(MKTEXPK)
+ if test "$enableval" != yes; then
+ AC_DEFINE_UNQUOTED(MKTEXPK_PATH, "$enableval")
+ fi
+fi],
+AC_DEFINE(MKTEXPK))
+
+AC_ARG_ENABLE(old-make-pk,
+[ --enable-old-make-pk[=PATH]
+ use old-style MakeTeXPK script instead of mktexpk],
+[if test "$enableval" != no; then
+ AC_DEFINE(MKTEXPK)
+ AC_DEFINE(MAKETEXPK)
+ if test "$enableval" != yes; then
+ AC_DEFINE_UNQUOTED(MKTEXPK_PATH, "$enableval")
+ fi
+fi])
+
+AC_ARG_ENABLE(gf,
+[ --enable-gf enable gf format pixel files (in addition to pk)],
+[if test "$enableval" != no; then
+ AC_DEFINE(USE_GF)
+ OPT_SRCS="$OPT_SRCS gf.c"
+ OPT_OBJS="$OPT_OBJS gf.o"
+fi])
+
+xdvi_ps_c= xdvi_ps_o= xdvi_need_gs_lib=
+AC_ARG_ENABLE(ps-gs,
+[ --enable-ps-gs[=PATH] enable PostScript support via ghostscript
+ (PATH, if given, points to the gs interpreter)],
+[if test "$enableval" != no; then
+ AC_DEFINE(PS_GS)
+ xdvi_ps_c=" psgs.c"
+ xdvi_ps_o=" psgs.o"
+ if test "$enableval" != yes; then
+ AC_DEFINE_UNQUOTED(GS_PATH, "$enableval")
+ fi
+fi])
+
+AC_ARG_ENABLE(ps-dps,
+[ --enable-ps-dps enable PostScript support via Display PostScript],
+[if test "$enableval" != no; then
+ AC_DEFINE(PS_DPS)
+ xdvi_ps_c="$xdvi_ps_c psdps.c"
+ xdvi_ps_o="$xdvi_ps_o psdps.o"
+ X_PRE_LIBS=" -ldps$X_PRE_LIBS"
+ # Work around a bug in Solaris 2. This doesn't work with imake.
+ if test "x$x_includes" = x/usr/openwin/include && test ! -d $x_includes/DPS \
+ && test -d $x_includes/X11/DPS; then
+ CFLAGS="$CFLAGS -I$x_includes/X11"
+ fi
+fi])
+
+AC_ARG_ENABLE(ps-news,
+[ --enable-ps-news enable PostScript support via NeWS (Sun OpenWin)],
+[if test "$enableval" != no; then
+ AC_DEFINE(PS_NEWS)
+ xdvi_ps_c="$xdvi_ps_c psnews.c"
+ xdvi_ps_o="$xdvi_ps_o psnews.o"
+ X_PRE_LIBS=" -u _xv_psview_pkg -lxvps -lxview -lcps -lolgx$X_PRE_LIBS"
+fi])
+
+if test -n "$xdvi_ps_c"; then
+ OPT_SRCS="$OPT_SRCS psheader.c$xdvi_ps_c"
+ OPT_OBJS="$OPT_OBJS psheader.o$xdvi_ps_o"
+ xdvi_need_gs_lib=y
+fi
+
+AC_ARG_ENABLE(config-file,
+[ --enable-config-file=PATHLIST
+ look for configuration file in PATHLIST],
+[if test "$enableval" != no; then
+ if test "$enableval" = yes; then
+ AC_MSG_ERROR(Option \`--enable-config-file' requires an argument)
+ fi
+ AC_DEFINE_UNQUOTED(DEFAULT_CONFIG_PATH, "$enableval")
+fi])
+
+AC_ARG_ENABLE(self-auto,
+[ --enable-self-auto[=PATHLIST]
+ same as above; also determine xdvi binary path],
+[if test "$enableval" != no; then
+ if test "$enableval" != yes; then
+ AC_DEFINE_UNQUOTED(DEFAULT_CONFIG_PATH, "$enableval")
+ fi
+ AC_DEFINE(SELFAUTO)
+fi])
+
+AC_ARG_ENABLE(extra-app-defaults,
+[ --enable-extra-app-defaults[=PATHLIST]
+ same as above; also enable extra app-defaults file],
+[if test "$enableval" != no; then
+ if test "$enableval" != yes; then
+ AC_DEFINE_UNQUOTED(DEFAULT_CONFIG_PATH, "$enableval")
+ fi
+ AC_DEFINE(EXTRA_APP_DEFAULTS)
+fi])
+
+AC_ARG_ENABLE(dosnames,
+[ --enable-dosnames use DOS-style names for fonts (e.g., dpi300/cmr10.pk)],
+[if test "$enableval" != no; then
+ AC_DEFINE(DOSNAMES)
+fi])
+
+AC_ARG_ENABLE(a4,
+[ --enable-a4 set default paper size to A4 and default unit to cm],
+[if test "$enableval" != no; then
+ AC_DEFINE(A4)
+fi])
+
+AC_ARG_ENABLE(texxet,
+[ --enable-texxet enable typesetting for right-to-left languages],
+[if test "$enableval" != no; then
+ AC_DEFINE(TEXXET)
+fi])
+
+AC_ARG_WITH(mfmode,
+[ --with-mfmode=MODE:DPI set default Metafont mode to MODE at DPI dots/inch
+ --without-mfmode set default Metafont mode to none],
+[if test "x$withval" != xno; then
+ echo "$withval" | grep [':[0-9][0-9]*$'] >/dev/null 2>&1 \
+ || AC_MSG_WARN(the mfmode should end with a dots-per-inch value)
+ AC_DEFINE_UNQUOTED(MFMODE, "$withval")
+fi],
+[AC_DEFINE(MFMODE, "cx:300")])
+
+# Extra libraries
+EXTRA_CPPFLAGS=
+EXTRA_LIBS=
+
+AC_ARG_ENABLE(freetype,
+[ --enable-freetype[=DIR] compile with the freetype2 library (default: enabled);
+ DIR=path of freetype-config binary],
+[if test "x$enableval" != xno; then
+ xdvi_freetype_config=freetype-config
+ if test "x$enableval" != xyes; then
+ if test -x "$enableval/freetype-config"; then
+ xdvi_freetype_config="$enableval/freetype-config"
+ elif test -x "$enableval/bin/freetype-config"; then
+ xdvi_freetype_config="$enableval/bin/freetype-config"
+ else
+ AC_MSG_WARN(Cannot find $enableval/freetype-config or $enableval/bin/freetype-config)
+ fi
+ fi
+ EXTRA_CPPFLAGS="$EXTRA_CPPFLAGS `$xdvi_freetype_config --cflags`"
+ EXTRA_LIBS="$EXTRA_LIBS `$xdvi_freetype_config --libs`"
+ AC_DEFINE(FREETYPE)
+ OPT_SRCS="$OPT_SRCS ft.c"
+ OPT_OBJS="$OPT_OBJS ft.o"
+ xdvi_need_gs_lib=y
+fi],
+[if freetype-config --cflags >conftest.cflags 2>/dev/null \
+ && freetype-config --libs >conftest.libs 2>/dev/null ; then
+ EXTRA_CPPFLAGS="$EXTRA_CPPFLAGS `cat conftest.cflags`"
+ EXTRA_LIBS="$EXTRA_LIBS `cat conftest.libs`"
+ rm -f conftest.cflags conftest.libs
+ AC_DEFINE(FREETYPE)
+ OPT_SRCS="$OPT_SRCS ft.c"
+ OPT_OBJS="$OPT_OBJS ft.o"
+ xdvi_need_gs_lib=y
+fi])
+
+AC_SUBST(EXTRA_CPPFLAGS)
+AC_SUBST(EXTRA_LIBS)
+
+# End extra libraries section
+
+XDVI_ARG_STRING(default-texmf-path, [ --with-default-texmf-path=PATH
+ set default texmf list to PATH],
+DEFAULT_TEXMF_PATH, "/usr/local/tex/texmf")
+
+XDVI_ARG_STRING(default-font-path, [ --with-default-font-path=PATH
+ set default font path to PATH],
+DEFAULT_FONT_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-vf-path, [ --with-default-vf-path=PATH
+ set default virtual font path to PATH],
+DEFAULT_VF_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-header-path, [ --with-default-header-path=PATH
+ set default path path for PS figures to PATH],
+DEFAULT_HEADER_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-fig-path, [ --with-default-fig-path=PATH
+ set default figure path to PATH],
+DEFAULT_FIG_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-dvips-cf-path, [ --with-default-dvips-cf-path=PATH
+ set default dvips configuration file path to PATH],
+DEFAULT_DVIPS_CF_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-fontmap-path, [ --with-default-fontmap-path=PATH
+ set default path for fontmap files to PATH],
+DEFAULT_FONTMAP_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-enc-path, [ --with-default-enc-path=PATH
+ set default path for encoding files to PATH],
+DEFAULT_ENC_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-type1-path, [ --with-default-type1-path=PATH
+ set default path for type 1 fonts to PATH],
+DEFAULT_TYPE1_PATH, ".:%S")
+
+if test -n "$xdvi_need_gs_lib"; then
+ XDVI_GS_LIB_PATH
+fi
+
+XDVI_ARG_STRING(default-source-path, [ --with-default-source-path=PATH
+ set default path for source specials to PATH],
+DEFAULT_SOURCE_PATH, ".:%S")
+
+XDVI_ARG_STRING(default-dvips-path, [ --with-default-dvips-path=CMD
+ set default print command to CMD],
+DEFAULT_DVIPS_PATH, "dvips")
+
+AC_SUBST(OPT_SRCS)dnl
+AC_SUBST(OPT_OBJS)dnl
+
+dnl Done.
+dnl Makefile is automatically included, unless imake is in use.
+AC_OUTPUT()
diff --git a/dvi-draw.c b/dvi-draw.c
@@ -0,0 +1,3048 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi.h"
+#include "dvi.h"
+#include <ctype.h>
+
+#if HAVE_VFORK_H
+# include <vfork.h>
+#endif
+
+#if XAW
+# include <X11/StringDefs.h>
+# if XAW3d
+# include <X11/Xaw3d/Label.h>
+# else
+# include <X11/Xaw/Label.h>
+# endif
+#elif MOTIF
+#endif
+
+#if HAVE_XKB_BELL_EXT
+# include <X11/XKBlib.h>
+# define XBell(dpy, percent) XkbBell(dpy, mane.win, percent, (Atom) None)
+#endif
+
+#if NeedVarargsPrototypes /* this is for tell_oops */
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef DOPRNT /* define this if vfprintf gives you trouble */
+#define vfprintf(stream, message, args) _doprnt(message, args, stream)
+#endif
+
+static struct frame frame0; /* dummy head of list */
+#ifdef TEXXET
+static struct frame *scan_frame; /* head frame for scanning */
+#endif
+
+#ifndef DVI_BUFFER_LEN
+#define DVI_BUFFER_LEN 512
+#endif
+
+static ubyte dvi_buffer[DVI_BUFFER_LEN];
+static struct frame *current_frame;
+
+/* Points to drawinf record containing current dvi file location (for update by
+ geom_scan). */
+static struct drawinf *dvi_pointer_frame INIT(NULL);
+
+#ifndef TEXXET
+#define DIR 1
+#else
+#define DIR currinf.dir
+#endif
+
+/*
+ * Explanation of the following constant:
+ * offset_[xy] << 16: margin (defaults to one inch)
+ * shrink_factor << 16: one pixel page border
+ * shrink_factor << 15: rounding for pixel_conv
+ */
+#define OFFSET_X (offset_x << 16) + (shrink_factor * 3 << 15)
+#define OFFSET_Y (offset_y << 16) + (shrink_factor * 3 << 15)
+
+#if (BMBYTES == 1)
+BMUNIT bit_masks[9] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff
+};
+#else
+#if (BMBYTES == 2)
+BMUNIT bit_masks[17] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff, 0x1ff, 0x3ff, 0x7ff,
+ 0xfff, 0x1fff, 0x3fff, 0x7fff,
+ 0xffff
+};
+#else /* BMBYTES == 4 */
+BMUNIT bit_masks[33] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff, 0x1ff, 0x3ff, 0x7ff,
+ 0xfff, 0x1fff, 0x3fff, 0x7fff,
+ 0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
+ 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
+ 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
+ 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+#endif
+#endif
+
+#ifdef VMS
+#define off_t int
+#endif
+extern off_t lseek();
+
+#ifndef SEEK_SET /* if <unistd.h> is not provided (or for <X11R5) */
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+static void draw_part();
+static void source_fwd_draw_box();
+
+/*
+ * X routines.
+ */
+
+/*
+ * Put a rectangle on the screen.
+ */
+
+static void
+put_rule(x, y, w, h)
+ int x, y;
+ unsigned int w, h;
+{
+ if (x < max_x && x + (int) w >= min_x
+ && y < max_y && y + (int) h >= min_y) {
+ if (--event_counter == 0)
+ if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE)
+ longjmp(canit_env, 1);
+#if COLOR
+ if (fg_active != fg_current) do_color_change();
+#endif
+ XFillRectangle(DISP, currwin.win, ruleGC,
+ x - currwin.base_x, y - currwin.base_y, w ? w : 1, h ? h : 1);
+ }
+}
+
+static void
+put_bitmap(bitmap, x, y)
+ struct bitmap *bitmap;
+ int x, y;
+{
+
+ if (debug & DBG_BITMAP)
+ Printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y);
+ if (x < max_x && x + (int) bitmap->w >= min_x
+ && y < max_y && y + (int) bitmap->h >= min_y) {
+ if (--event_counter == 0)
+ if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE)
+ longjmp(canit_env, 1);
+#if COLOR
+ if (fg_active != fg_current) do_color_change();
+#endif
+ image->width = bitmap->w;
+ image->height = bitmap->h;
+ image->data = bitmap->bits;
+ image->bytes_per_line = bitmap->bytes_wide;
+ XPutImage(DISP, currwin.win, foreGC, image,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ bitmap->w, bitmap->h);
+ if (foreGC2)
+ XPutImage(DISP, currwin.win, foreGC2, image,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ bitmap->w, bitmap->h);
+ }
+}
+
+#if GREY
+
+static void shrink_glyph_grey ARGS((struct glyph *));
+
+static void
+put_image(g, x, y)
+ struct glyph *g;
+ int x, y;
+{
+ XImage *img = g->image2;
+
+ if (x < max_x && x + img->width >= min_x &&
+ y < max_y && y + img->height >= min_y) {
+
+ if (--event_counter == 0)
+ if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE)
+ longjmp(canit_env, 1);
+
+#if COLOR
+ if (g->fg != fg_current) /* if color change since last use */
+ shrink_glyph_grey(g);
+ else if (fg_active != fg_current) /* if GCs need updating */
+ do_color_change();
+#endif
+ XPutImage(DISP, currwin.win, foreGC, img,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ (unsigned int) img->width, (unsigned int) img->height);
+ if (foreGC2 != NULL) {
+ img->data = g->pixmap2_t;
+ XPutImage(DISP, currwin.win, foreGC2, img,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ (unsigned int) img->width, (unsigned int) img->height);
+ img->data = g->pixmap2;
+ }
+ }
+}
+#endif /* GREY */
+
+/*
+ * Byte reading routines for dvi file.
+ */
+
+#define xtell(pos) (lseek(fileno(dvi_file), 0L, SEEK_CUR) - \
+ (currinf.end - (pos)))
+
+static ubyte
+xxone()
+{
+ if (currinf.virtual) {
+ ++currinf.pos;
+ return EOP;
+ }
+ currinf.end = dvi_buffer +
+ read(fileno(dvi_file), (char *) (currinf.pos = dvi_buffer),
+ DVI_BUFFER_LEN);
+ return currinf.end > dvi_buffer ? *(currinf.pos)++ : EOF;
+}
+
+#define xone() (currinf.pos < currinf.end ? *(currinf.pos)++ : xxone())
+
+static unsigned long
+xnum(size)
+ ubyte size;
+{
+ long x = 0;
+
+ while (size--) x = (x << 8) | xone();
+ return x;
+}
+
+static long
+xsnum(size)
+ ubyte size;
+{
+ long x;
+
+#if __STDC__
+ x = (signed char) xone();
+#else
+ x = xone();
+ if (x & 0x80) x -= 0x100;
+#endif
+ while (--size) x = (x << 8) | xone();
+ return x;
+}
+
+#define xsfour() xsnum(4)
+
+static void
+xskip(offset)
+ long offset;
+{
+ currinf.pos += offset;
+ if (!currinf.virtual && currinf.pos > currinf.end)
+ (void) lseek(fileno(dvi_file), (long) (currinf.pos - currinf.end),
+ SEEK_CUR);
+}
+
+#if NeedVarargsPrototypes
+static void tell_oops(_Xconst char *, ...) NORETURN;
+
+static void
+tell_oops(_Xconst char *message, ...)
+#else
+/* VARARGS */
+static void
+tell_oops(va_alist)
+ va_dcl
+#endif
+{
+#if !NeedVarargsPrototypes
+ _Xconst char *message;
+#endif
+ va_list args;
+
+ Fprintf(stderr, "%s: ", prog);
+#if NeedVarargsPrototypes
+ va_start(args, message);
+#else
+ va_start(args);
+ message = va_arg(args, _Xconst char *);
+#endif
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ if (currinf.virtual)
+ Fprintf(stderr, " in virtual font %s\n", currinf.virtual->fontname);
+ else
+ Fprintf(stderr, ", offset %ld\n", xtell(currinf.pos - 1));
+ xdvi_exit(1);
+}
+
+
+/*
+ * Code for debugging options.
+ */
+
+static void
+print_bitmap(bitmap)
+ struct bitmap *bitmap;
+{
+ BMUNIT *ptr = (BMUNIT *) bitmap->bits;
+ int x, y, i;
+
+ if (ptr == NULL) oops("print_bitmap called with null pointer.");
+ Printf("w = %d, h = %d, bytes wide = %d\n",
+ bitmap->w, bitmap->h, bitmap->bytes_wide);
+ for (y = 0; y < (int) bitmap->h; ++y) {
+ for (x = bitmap->bytes_wide; x > 0; x -= BMBYTES) {
+#ifndef WORDS_BIGENDIAN
+ for (i = 0; i < BMBITS; ++i)
+#else
+ for (i = BMBITS - 1; i >= 0; --i)
+#endif
+ Putchar((*ptr & (1 << i)) ? '@' : ' ');
+ ++ptr;
+ }
+ Putchar('\n');
+ }
+}
+
+static void
+print_char(ch, g)
+ ubyte ch;
+ struct glyph *g;
+{
+ Printf("char %d", ch);
+ if (isprint(ch))
+ Printf(" (%c)", ch);
+ Putchar('\n');
+ Printf("x = %d, y = %d, dvi = %ld\n", g->x, g->y, g->dvi_adv);
+ print_bitmap(&g->bitmap);
+}
+
+static _Xconst char *dvi_table1[] = {
+ "SET1", NULL, NULL, NULL, "SETRULE", "PUT1", NULL, NULL,
+ NULL, "PUTRULE", "NOP", "BOP", "EOP", "PUSH", "POP", "RIGHT1",
+ "RIGHT2", "RIGHT3", "RIGHT4", "W0", "W1", "W2", "W3", "W4",
+ "X0", "X1", "X2", "X3", "X4", "DOWN1", "DOWN2", "DOWN3",
+ "DOWN4", "Y0", "Y1", "Y2", "Y3", "Y4", "Z0", "Z1",
+ "Z2", "Z3", "Z4"};
+
+static _Xconst char *dvi_table2[] = {
+ "FNT1", "FNT2", "FNT3", "FNT4", "XXX1", "XXX2", "XXX3", "XXX4",
+ "FNTDEF1", "FNTDEF2", "FNTDEF3", "FNTDEF4", "PRE", "POST", "POSTPOST",
+ "SREFL", "EREFL", NULL, NULL, NULL, NULL};
+
+static void
+print_dvi(ch)
+ ubyte ch;
+{
+ _Xconst char *s;
+
+ Printf("%4d %4d ", PXL_H, PXL_V);
+ if (ch <= (ubyte) (SETCHAR0 + 127)) {
+ Printf("SETCHAR%-3d", ch - SETCHAR0);
+ if (isprint(ch))
+ Printf(" (%c)", ch);
+ Putchar('\n');
+ return;
+ }
+ else if (ch < FNTNUM0) s = dvi_table1[ch - 128];
+ else if (ch <= (ubyte) (FNTNUM0 + 63)) {
+ Printf("FNTNUM%d\n", ch - FNTNUM0);
+ return;
+ }
+ else s = dvi_table2[ch - (FNTNUM0 + 64)];
+ if (s) Puts(s);
+ else
+ tell_oops("unknown op-code %d", ch);
+}
+
+
+/*
+ * Count the number of set bits in a given region of the bitmap
+ */
+
+static char sample_count[] = {0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4};
+
+static int
+sample(bits, bytes_wide, bit_skip, w, h)
+ BMUNIT *bits;
+ int bytes_wide, bit_skip, w, h;
+{
+ BMUNIT *ptr, *endp;
+ BMUNIT *cp;
+ int bits_left;
+ int n, bit_shift, wid;
+
+ ptr = bits + bit_skip / BMBITS;
+ endp = ADD(bits, h * bytes_wide);
+ bits_left = w;
+#ifndef WORDS_BIGENDIAN
+ bit_shift = bit_skip % BMBITS;
+#else
+ bit_shift = BMBITS - bit_skip % BMBITS;
+#endif
+ n = 0;
+ while (bits_left) {
+#ifndef WORDS_BIGENDIAN
+ wid = BMBITS - bit_shift;
+#else
+ wid = bit_shift;
+#endif
+ if (wid > bits_left) wid = bits_left;
+ if (wid > 4) wid = 4;
+#ifdef WORDS_BIGENDIAN
+ bit_shift -= wid;
+#endif
+ for (cp = ptr; cp < endp; cp = ADD(cp, bytes_wide))
+ n += sample_count[(*cp >> bit_shift) & bit_masks[wid]];
+#ifndef WORDS_BIGENDIAN
+ bit_shift += wid;
+ if (bit_shift == BMBITS) {
+ bit_shift = 0;
+ ++ptr;
+ }
+#else
+ if (bit_shift == 0) {
+ bit_shift = BMBITS;
+ ++ptr;
+ }
+#endif
+ bits_left -= wid;
+ }
+ return n;
+}
+
+static void
+shrink_glyph(g)
+ struct glyph *g;
+{
+ int shrunk_bytes_wide, shrunk_height;
+ int rows_left, rows, init_cols;
+ int cols_left;
+ int cols;
+ BMUNIT *old_ptr, *new_ptr;
+ BMUNIT m, *cp;
+ int min_sample = shrink_factor * shrink_factor * density / 100;
+ int rtmp;
+
+ /* These machinations ensure that the character is shrunk according to
+ its hot point, rather than its upper left-hand corner. */
+ g->x2 = g->x / shrink_factor;
+ init_cols = g->x - g->x2 * shrink_factor;
+ if (init_cols <= 0) init_cols += shrink_factor;
+ else ++g->x2;
+ g->bitmap2.w = g->x2 + ROUNDUP((int) g->bitmap.w - g->x, shrink_factor);
+ /* include row zero with the positively numbered rows */
+ rtmp = g->y + 1;
+ g->y2 = rtmp / shrink_factor;
+ rows = rtmp - g->y2 * shrink_factor;
+ if (rows <= 0) {
+ rows += shrink_factor;
+ --g->y2;
+ }
+ g->bitmap2.h = shrunk_height = g->y2 +
+ ROUNDUP((int) g->bitmap.h - rtmp, shrink_factor) + 1;
+ alloc_bitmap(&g->bitmap2);
+ old_ptr = (BMUNIT *) g->bitmap.bits;
+ new_ptr = (BMUNIT *) g->bitmap2.bits;
+ shrunk_bytes_wide = g->bitmap2.bytes_wide;
+ rows_left = g->bitmap.h;
+ bzero((char *) new_ptr, shrunk_bytes_wide * shrunk_height);
+ while (rows_left) {
+ if (rows > rows_left) rows = rows_left;
+ cols_left = g->bitmap.w;
+#ifndef WORDS_BIGENDIAN
+ m = (1 << 0);
+#else
+ m = ((BMUNIT) 1 << (BMBITS-1));
+#endif
+ cp = new_ptr;
+ cols = init_cols;
+ while (cols_left) {
+ if (cols > cols_left) cols = cols_left;
+ if (sample(old_ptr, g->bitmap.bytes_wide,
+ (int) g->bitmap.w - cols_left, cols, rows)
+ >= min_sample)
+ *cp |= m;
+#ifndef WORDS_BIGENDIAN
+ if (m == ((BMUNIT)1 << (BMBITS-1))) {
+ m = (1 << 0);
+ ++cp;
+ }
+ else m <<= 1;
+#else
+ if (m == (1 << 0)) {
+ m = ((BMUNIT) 1 << (BMBITS-1));
+ ++cp;
+ }
+ else m >>= 1;
+#endif
+ cols_left -= cols;
+ cols = shrink_factor;
+ }
+ *((char **) &new_ptr) += shrunk_bytes_wide;
+ *((char **) &old_ptr) += rows * g->bitmap.bytes_wide;
+ rows_left -= rows;
+ rows = shrink_factor;
+ }
+ g->y2 = g->y / shrink_factor;
+ if (debug & DBG_BITMAP)
+ print_bitmap(&g->bitmap2);
+}
+
+#ifdef GREY
+static void
+shrink_glyph_grey(g)
+ struct glyph *g;
+{
+ int rows_left, rows, init_cols;
+ int cols_left;
+ int cols;
+ int x, y;
+ long thesample;
+ BMUNIT *old_ptr;
+ unsigned int size;
+ int rtmp;
+
+#if COLOR
+ if (fg_active != fg_current) do_color_change();
+#endif
+
+ /* These machinations ensure that the character is shrunk according to
+ its hot point, rather than its upper left-hand corner. */
+ g->x2 = g->x / shrink_factor;
+ init_cols = g->x - g->x2 * shrink_factor;
+ if (init_cols <= 0) init_cols += shrink_factor;
+ else ++g->x2;
+ g->bitmap2.w = g->x2 + ROUNDUP((int) g->bitmap.w - g->x, shrink_factor);
+ /* include row zero with the positively numbered rows */
+ rtmp = g->y + 1;
+ g->y2 = rtmp / shrink_factor;
+ rows = rtmp - g->y2 * shrink_factor;
+ if (rows <= 0) {
+ rows += shrink_factor;
+ --g->y2;
+ }
+ g->bitmap2.h = g->y2 + ROUNDUP((int) g->bitmap.h - rtmp, shrink_factor)
+ + 1;
+
+ if (g->pixmap2 == NULL) {
+ g->image2 = XCreateImage(DISP, our_visual, our_depth, ZPixmap,
+ 0, (char *) NULL, g->bitmap2.w, g->bitmap2.h, BMBITS, 0);
+ size = g->image2->bytes_per_line * g->bitmap2.h;
+ g->pixmap2 = g->image2->data = xmalloc(size != 0 ? size : 1);
+ }
+ if (foreGC2 != NULL && g->pixmap2_t == NULL) {
+ size = g->image2->bytes_per_line * g->bitmap2.h;
+ g->pixmap2_t = xmalloc(size != 0 ? size : 1);
+ }
+
+ old_ptr = (BMUNIT *) g->bitmap.bits;
+ rows_left = g->bitmap.h;
+ y = 0;
+ while (rows_left) {
+ x = 0;
+ if (rows > rows_left) rows = rows_left;
+ cols_left = g->bitmap.w;
+ cols = init_cols;
+ while (cols_left) {
+ if (cols > cols_left) cols = cols_left;
+
+ thesample = sample(old_ptr, g->bitmap.bytes_wide,
+ (int) g->bitmap.w - cols_left, cols, rows);
+ XPutPixel(g->image2, x, y, pixeltbl[thesample]);
+ if (foreGC2 != NULL) {
+ g->image2->data = g->pixmap2_t;
+ XPutPixel(g->image2, x, y, pixeltbl_t[thesample]);
+ g->image2->data = g->pixmap2;
+ }
+
+ cols_left -= cols;
+ cols = shrink_factor;
+ x++;
+ }
+ *((char **) &old_ptr) += rows * g->bitmap.bytes_wide;
+ rows_left -= rows;
+ rows = shrink_factor;
+ y++;
+ }
+
+ while (y < (int) g->bitmap2.h) {
+ for (x = 0; x < (int) g->bitmap2.w; x++) {
+ XPutPixel(g->image2, x, y, *pixeltbl);
+ if (foreGC2 != NULL) {
+ g->image2->data = g->pixmap2_t;
+ XPutPixel(g->image2, x, y, *pixeltbl_t);
+ g->image2->data = g->pixmap2;
+ }
+ }
+ y++;
+ }
+
+ g->y2 = g->y / shrink_factor;
+#if COLOR
+ g->fg = fg_current;
+#endif
+}
+#endif /* GREY */
+
+/*
+ * Find font #n.
+ */
+
+static void
+change_font(n)
+ unsigned long n;
+{
+ struct tn *tnp;
+
+ if (n < currinf.tn_table_len) currinf.fontp = currinf.tn_table[n];
+ else {
+ currinf.fontp = NULL;
+ for (tnp = currinf.tn_head; tnp != NULL; tnp = tnp->next)
+ if (tnp->TeXnumber == n) {
+ currinf.fontp = tnp->fontp;
+ break;
+ }
+ }
+ if (currinf.fontp == NULL) tell_oops("non-existent font #%d", n);
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+}
+
+
+/*
+ * Open a font file.
+ */
+
+void
+open_font_file(fontp)
+ struct font *fontp;
+{
+ if (fontp->file == NULL) {
+ fontp->file = xfopen(fontp->filename, OPEN_MODE);
+ if (fontp->file == NULL)
+ oops("Font file disappeared: %s", fontp->filename);
+ }
+}
+
+/*
+ * Read special string.
+ */
+
+static char *
+read_special(nbytes)
+ long nbytes;
+{
+ static char *spcl = NULL;
+ static long spcl_len = -1;
+ char *p;
+
+ if (spcl_len < nbytes) {
+ if (spcl != NULL) free(spcl);
+ spcl = xmalloc((unsigned) nbytes + 1);
+ spcl_len = nbytes;
+ }
+ p = spcl;
+ for (;;) {
+ int i = currinf.end - currinf.pos;
+
+ if (i > nbytes) i = nbytes;
+ bcopy((char *) currinf.pos, p, i);
+ currinf.pos += i;
+ p += i;
+ nbytes -= i;
+ if (nbytes == 0) break;
+ (void) xxone();
+ --currinf.pos;
+ }
+ *p = '\0';
+ return spcl;
+}
+
+
+/*
+ * Table used for scanning. If >= 0, then skip that many bytes.
+ * M1 means end of page, M2 means special, M3 means FNTDEF,
+ * M4 means unrecognizable, and M5 means doesn't belong here.
+ */
+
+#define M1 255
+#define M2 254
+#define M3 253
+#define M4 252
+#define M5 251
+#define MM 251
+
+static ubyte scantable[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* chars 0 - 127 */
+ 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,
+ 1,M4, /* SET1,- (128,129) */
+ /* -,-,SETRULE,PUT1,-,-,-,PUTRULE,NOP,BOP (130-139) */
+ M4,M4,8,1,M4,M4,M4,8,0,44,
+ M1,0,0,1,2,3,4,0,1,2, /* EOP,PUSH,POP,RIGHT1-4,W0M2 (140-149) */
+ 3,4,0,1,2,3,4,1,2,3, /* W3-4,X0-4,DOWN1-3 (150-159) */
+ 4,0,1,2,3,4,0,1,2,3, /* DOWN4,Y0-4,Z0-3 (160-169) */
+ 4, /* Z4 (170) */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* change font 171 - 234 */
+ 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,
+ 1,2,3,4,M2, /* FNT1-4,XXX1 (235-239) */
+ /* XXX2-4,FNTDEF1-4,PRE,POST,POSTPOST (240-249) */
+ M2,M2,M2,M3,M3,M3,M3,M5,M5,M5,
+ 0,0,M4,M4,M4,M4}; /* SREFL,EREFL,-,-,-,- (250-255) */
+
+/*
+ * This is the generic scanning routine. It assumes that currinf, etc.
+ * are ready to go at the start of the page to be scanned.
+ */
+
+static void
+spcl_scan(spcl_proc)
+ void (*spcl_proc) ARGS((char *));
+{
+ ubyte ch;
+ ubyte n;
+ long a;
+
+ for (;;) {
+ ch = xone();
+ n = scantable[ch];
+ if (n < MM)
+ while (n-- != 0)
+ (void) xone();
+ else if (n == M1) break; /* end of page */
+ else switch (n) {
+ case M2: /* special */
+ a = xnum(ch - XXX1 + 1);
+ if (a > 0)
+ spcl_proc(read_special(a));
+ break;
+ case M3: /* FNTDEF */
+ xskip((long) (12 + ch - FNTDEF1 + 1));
+ ch = xone();
+ xskip((long) ch + (long) xone());
+ break;
+ case M4: /* unrecognizable */
+ tell_oops("unknown op-code %d", ch);
+ break;
+ case M5: /* doesn't belong */
+ tell_oops("shouldn't happen: %s encountered",
+ dvi_table2[ch - (FNTNUM0 + 64)]);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Size of page interval for "Scanning pages xx-xx" message.
+ */
+
+#ifndef REPORT_INCR
+#define REPORT_INCR 50
+#endif
+
+/*
+ * Prescanning routine for dvi file. This looks for specials like
+ * `header=' and `!'.
+ */
+
+#if TOOLKIT
+
+static void show_status ARGS((struct xtimer *));
+
+static struct xtimer pst = TIMER_INIT(show_status);
+
+struct prescan_rec {
+ Boolean timer_active;
+ Boolean popup_active;
+ struct status_popup *pp;
+ char *scanmsg;
+};
+
+static struct prescan_rec *psrp = NULL;
+
+/* Window manager destroy callback */
+/* ARGSUSED */
+static void
+status_cb_destroy(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ psrp->popup_active = False;
+ simple_popdown(psrp->pp);
+}
+
+static void
+show_status(arg)
+ struct xtimer *arg;
+{
+ psrp->timer_active = False;
+ psrp->popup_active = True;
+ simple_popup(psrp->pp, psrp->scanmsg, status_cb_destroy);
+}
+
+#endif /* TOOLKIT */
+
+void
+prescan()
+{
+ int nextreportpage;
+ char scanmsg[40];
+#if TOOLKIT
+ static struct status_popup popup = {NULL, NULL, 0, False, False};
+ struct prescan_rec pr;
+#endif
+
+ dvi_file_ready = False;
+
+ nextreportpage = scanned_page;
+ (void) lseek(fileno(dvi_file), page_info[scanned_page + 1].offset,
+ SEEK_SET);
+ currinf.pos = currinf.end = dvi_buffer;
+
+#if TOOLKIT
+ pr.timer_active = True;
+ pr.popup_active = False;
+ pr.pp = &popup;
+ pr.scanmsg = scanmsg;
+ psrp = ≺
+ set_timer(&pst, 1000);
+#endif
+ for (;;) {
+ page_info[scanned_page + 1].pw = page_info[scanned_page].pw;
+ page_info[scanned_page + 1].ph = page_info[scanned_page].ph;
+ page_info[scanned_page + 1].ww = page_info[scanned_page].ww;
+ page_info[scanned_page + 1].wh = page_info[scanned_page].wh;
+
+ if (debug & DBG_PS)
+ Printf("Scanning page %d\n", scanned_page + 1);
+ if (scanned_page >= nextreportpage) {
+ nextreportpage += REPORT_INCR;
+ if (nextreportpage > current_page)
+ nextreportpage = current_page;
+ Sprintf(scanmsg, "Scanning pages %d-%d",
+ scanned_page + 1 + pageno_correct,
+ nextreportpage + pageno_correct);
+#if XAW
+ if (pr.popup_active)
+ XtVaSetValues(popup.label, XtNlabel, scanmsg, NULL);
+#elif MOTIF
+ if (pr.popup_active) {
+ XmString str;
+
+ str = XmStringCreateLocalized((char *) scanmsg);
+ XtVaSetValues(popup.label, XmNlabelString, str, NULL);
+ XmStringFree(str);
+ }
+#else /* no toolkit */
+ if (top_level != 0) {
+ showmessage(scanmsg);
+ XFlush(DISP);
+ }
+#endif
+ }
+
+ if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE) break;
+#if PS
+ /* NOTE: longjmp(canit_env) should not be done within
+ read_events(). */
+ if (!setjmp(canit_env))
+ spcl_scan(scan_special);
+ else { /* if interrupted */
+ psp.interrupt();
+ break;
+ }
+ if (ev_flags & EV_GE_NEWPAGE) break;
+#else
+ /* No calls to read_events() occur in this case. */
+ spcl_scan(scan_special);
+#endif
+
+ ++scanned_page;
+#if COLOR
+ if (scanned_page_color < scanned_page) {
+ scan_color_eop();
+ scanned_page_color = scanned_page;
+ }
+#endif
+#if PS
+ if (scanned_page_ps < scanned_page)
+ scanned_page_ps = scanned_page;
+#endif
+
+ if (scanned_page >= current_page) break;
+ }
+
+#if TOOLKIT
+ if (pr.popup_active)
+ simple_popdown(&popup);
+ else if (pr.timer_active)
+ cancel_timer(&pst);
+#else /* !TOOLKIT */
+ if (top_level != 0)
+ XClearWindow(DISP, mane.win);
+#endif
+
+#if PS
+ if (!(ev_flags & EV_GE_NEWPAGE))
+ psp.endheader();
+#endif
+}
+
+/*
+ * Routines to print characters.
+ */
+
+#ifndef TEXXET
+#define ERRVAL 0L
+#else
+#define ERRVAL
+#endif
+
+#ifndef TEXXET
+long
+set_char P1C(wide_ubyte, ch)
+#else
+void
+set_char P2C(wide_ubyte, cmd, wide_ubyte, ch)
+#endif
+{
+ struct glyph *g;
+#ifdef TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar) realloc_font(currinf.fontp, WIDENINT ch);
+ if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
+ if (g->addr == 0) {
+ if (!hush_chars)
+ Fprintf(stderr, "Character %d not defined in font %s\n", ch,
+ currinf.fontp->fontname);
+ g->addr = -1;
+ return ERRVAL;
+ }
+ if (g->addr == -1)
+ return ERRVAL; /* previously flagged missing char */
+#if FREETYPE
+ if (currinf.fontp->ft == NULL) /* if not freetype font */
+#endif
+ {
+ open_font_file(currinf.fontp);
+ Fseek(currinf.fontp->file, g->addr, 0);
+ }
+ (*currinf.fontp->read_char)(currinf.fontp, ch);
+ if (debug & DBG_BITMAP) print_char((ubyte) ch, g);
+ currinf.fontp->timestamp = ++current_timestamp;
+ }
+
+#ifdef TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0) DVI_H -= g->dvi_adv;
+ if (scan_frame == NULL) {
+#endif
+ if (shrink_factor == 1)
+ put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
+ else {
+#ifdef GREY
+ if (use_grey) {
+ if (g->pixmap2 == NULL) {
+ shrink_glyph_grey(g);
+ }
+ put_image(g, PXL_H - g->x2, PXL_V - g->y2);
+ } else {
+ if (g->bitmap2.bits == NULL) {
+ shrink_glyph(g);
+ }
+ put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
+ }
+#else
+ if (g->bitmap2.bits == NULL) {
+ shrink_glyph(g);
+ }
+ put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
+#endif
+ }
+#ifndef TEXXET
+ return g->dvi_adv;
+#else
+ }
+ if (cmd == PUT1)
+ DVI_H = dvi_h_sav;
+ else
+ if (currinf.dir > 0) DVI_H += g->dvi_adv;
+#endif
+}
+
+
+ /* ARGSUSED */
+#ifndef TEXXET
+static long
+set_empty_char P1C(wide_ubyte, ch)
+#else
+static void
+set_empty_char P2C(wide_ubyte, cmd, wide_ubyte, ch)
+#endif
+{
+#ifndef TEXXET
+ return 0;
+#else
+ return;
+#endif
+}
+
+
+#ifndef TEXXET
+long
+load_n_set_char P1C(wide_ubyte, ch)
+#else
+void
+load_n_set_char P2C(wide_ubyte, cmd, wide_ubyte, ch)
+#endif
+{
+ if (!load_font(currinf.fontp)) { /* if not found */
+ if (ev_flags & EV_GE_NEWDOC) /* if abort */
+ longjmp(canit_env, 1);
+ Fputs("Character(s) will be left blank.\n", stderr);
+ currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
+#ifndef TEXXET
+ return 0;
+#else
+ return;
+#endif
+ }
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+#ifndef TEXXET
+ return (*currinf.set_char_p)(ch);
+#else
+ (*currinf.set_char_p)(cmd, ch);
+ return;
+#endif
+}
+
+
+#ifndef TEXXET
+long
+set_vf_char P1C(wide_ubyte, ch)
+#else
+void
+set_vf_char P2C(wide_ubyte, cmd, wide_ubyte, ch)
+#endif
+{
+ struct macro *m;
+ struct drawinf oldinfo;
+ ubyte oldmaxchar;
+ static ubyte c;
+#ifdef TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar) realloc_virtual_font(currinf.fontp, ch);
+ if ((m = &currinf.fontp->macro[ch])->pos == NULL) {
+ if (!hush_chars)
+ Fprintf(stderr, "Character %d not defined in font %s\n", ch,
+ currinf.fontp->fontname);
+ m->pos = m->end = &c;
+ return ERRVAL;
+ }
+#ifdef TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0) DVI_H -= m->dvi_adv;
+ if (scan_frame == NULL) {
+#endif
+ oldinfo = currinf;
+ if (!currinf.virtual)
+ dvi_pointer_frame = &oldinfo;
+ oldmaxchar = maxchar;
+ WW = XX = YY = ZZ = 0;
+ currinf.tn_table_len = VFTABLELEN;
+ currinf.tn_table = currinf.fontp->vf_table;
+ currinf.tn_head = currinf.fontp->vf_chain;
+ currinf.pos = m->pos;
+ currinf.end = m->end;
+ currinf.virtual = currinf.fontp;
+ draw_part(current_frame, currinf.fontp->dimconv);
+ if (currinf.pos != currinf.end + 1)
+ tell_oops("virtual character macro does not end correctly");
+ currinf = oldinfo;
+ if (!currinf.virtual)
+ dvi_pointer_frame = &currinf;
+ maxchar = oldmaxchar;
+#ifndef TEXXET
+ return m->dvi_adv;
+#else
+ }
+ if (cmd == PUT1)
+ DVI_H = dvi_h_sav;
+ else
+ if (currinf.dir > 0) DVI_H += m->dvi_adv;
+#endif
+}
+
+
+#if FREETYPE
+
+/*
+ * set_ft_char() is used as a set_char routine to handle delayed loading
+ * of freetype fonts. See more details in ft.c.
+ */
+
+static void
+do_load_freetype_font()
+{
+ if (!load_ft_font(currinf.fontp)) {
+ /* Revert to non-scalable font */
+ struct ftfont *ftp;
+
+ if (debug & DBG_OPEN)
+ Printf(
+ "Font %s is not loadable; reverting to non-scalable font\n",
+ currinf.fontp->fontname);
+
+ ftp = currinf.fontp->ft;
+ ftp->t1->bad = True;
+ if (currinf.fontp == ftp->first_size) {
+ if (currinf.fontp->next_size == NULL) {
+ /* if this is the only size of this font face */
+ ftp->t1->ft = NULL;
+ free(ftp);
+ }
+ else {
+ struct font *fontp2;
+
+ ftp->first_size = fontp2 = currinf.fontp->next_size;
+ /*
+ * Opening the file might have succeeded at some other size,
+ * so we need to transfer that information to the next
+ * record in case it was put here.
+ */
+ fontp2->file = currinf.fontp->file;
+ currinf.fontp->file = NULL;
+ fontp2->filename = currinf.fontp->filename;
+ currinf.fontp->filename = NULL;
+ fontp2->timestamp = currinf.fontp->timestamp;
+ }
+ }
+ else {
+ struct font *fontp2;
+
+ fontp2 = ftp->first_size;
+ while (fontp2->next_size != currinf.fontp)
+ fontp2 = fontp2->next_size;
+ fontp2->next_size = currinf.fontp->next_size;
+ }
+ currinf.fontp->ft = NULL;
+ /* The virtual font machinery will take it from here. */
+ /* That will call load_font(), but it won't take us back to the */
+ /* freetype font, because that font will have been marked bad. */
+ currinf.set_char_p = load_n_set_char;
+ }
+ else
+ currinf.set_char_p = currinf.fontp->set_char_p = set_char;
+}
+
+# if !TEXXET
+long
+set_ft_char P1C(wide_ubyte, ch)
+# else
+void
+set_ft_char P2C(wide_ubyte, cmd, wide_ubyte, ch)
+# endif
+{
+ do_load_freetype_font();
+
+# if !TEXXET
+ return (*currinf.set_char_p)(ch);
+# else
+ (*currinf.set_char_p)(cmd, ch);
+ return;
+# endif
+}
+
+#endif /* FREETYPE */
+
+
+#ifndef TEXXET
+static long
+set_no_char P1C(wide_ubyte, ch)
+#else
+static void
+set_no_char P2C(wide_ubyte, cmd, wide_ubyte, ch)
+#endif
+{
+ if (currinf.virtual) {
+ currinf.fontp = currinf.virtual->first_font;
+ if (currinf.fontp != NULL) {
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+#ifndef TEXXET
+ return (*currinf.set_char_p)(ch);
+#else
+ (*currinf.set_char_p)(cmd, ch);
+ return;
+#endif
+ }
+ }
+ tell_oops("attempt to set character of unknown font");
+ /* NOTREACHED */
+}
+
+
+/*
+ * Set rule. Arguments are coordinates of lower left corner.
+ */
+
+static void
+set_rule(h, w)
+ int h, w;
+{
+#ifndef TEXXET
+ put_rule(PXL_H, PXL_V - h + 1, (unsigned int) w, (unsigned int) h);
+#else
+ put_rule(PXL_H - (currinf.dir < 0 ? w - 1 : 0), PXL_V - h + 1,
+ (unsigned int) w, (unsigned int) h);
+#endif
+}
+
+
+/*
+ * Interpret a sequence of dvi bytes (either the page from the dvi file,
+ * or a character from a virtual font).
+ */
+
+#define xspell_conv(n) spell_conv0(n, current_dimconv)
+
+static void
+draw_part(minframe, current_dimconv)
+ struct frame *minframe;
+ double current_dimconv;
+{
+ ubyte ch;
+#ifdef TEXXET
+ struct drawinf oldinfo;
+ ubyte oldmaxchar;
+ off_t file_pos;
+ int refl_count;
+#endif
+
+ currinf.fontp = NULL;
+ currinf.set_char_p = set_no_char;
+#ifdef TEXXET
+ currinf.dir = 1;
+ scan_frame = NULL; /* indicates we're not scanning */
+#endif
+ for (;;) {
+ ch = xone();
+ if (debug & DBG_DVI)
+ print_dvi(ch);
+ if (ch <= (ubyte) (SETCHAR0 + 127))
+#ifndef TEXXET
+ DVI_H += (*currinf.set_char_p)(ch);
+#else
+ (*currinf.set_char_p)(ch, ch);
+#endif
+ else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63))
+ change_font((unsigned long) (ch - FNTNUM0));
+ else {
+ long a, b;
+
+ switch (ch) {
+ case SET1:
+ case PUT1:
+#ifndef TEXXET
+ a = (*currinf.set_char_p)(xone());
+ if (ch != PUT1) DVI_H += a;
+#else
+ (*currinf.set_char_p)(ch, xone());
+#endif
+ break;
+
+ case SETRULE:
+ /* Be careful, dvicopy outputs rules with
+ height = 0x80000000. We don't want any
+ SIGFPE here. */
+ a = xsfour();
+ b = xspell_conv(xsfour());
+#ifndef TEXXET
+ if (a > 0 && b > 0)
+#else
+ if (a > 0 && b > 0 && scan_frame == NULL)
+#endif
+ set_rule(pixel_round(xspell_conv(a)),
+ pixel_round(b));
+ DVI_H += DIR * b;
+ break;
+
+ case PUTRULE:
+ a = xspell_conv(xsfour());
+ b = xspell_conv(xsfour());
+#ifndef TEXXET
+ if (a > 0 && b > 0)
+#else
+ if (a > 0 && b > 0 && scan_frame == NULL)
+#endif
+ set_rule(pixel_round(a), pixel_round(b));
+ break;
+
+ case NOP:
+ break;
+
+ case BOP:
+ xskip((long) 11 * 4);
+ DVI_H = OFFSET_X;
+ DVI_V = OFFSET_Y;
+ PXL_V = pixel_conv(DVI_V);
+ WW = XX = YY = ZZ = 0;
+ break;
+
+ case EOP:
+ if (current_frame != minframe)
+ tell_oops("stack not empty at EOP");
+ return;
+
+ case PUSH:
+ if (current_frame->next == NULL) {
+ struct frame *newp = xmalloc(sizeof(struct frame));
+
+ current_frame->next = newp;
+ newp->prev = current_frame;
+ newp->next = NULL;
+ }
+ current_frame = current_frame->next;
+ current_frame->data = currinf.data;
+ break;
+
+ case POP:
+ if (current_frame == minframe)
+ tell_oops("more POPs than PUSHes");
+ currinf.data = current_frame->data;
+ current_frame = current_frame->prev;
+ break;
+
+#ifdef TEXXET
+ case SREFL:
+ if (scan_frame == NULL) {
+ /* we're not scanning: save some info. */
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ if (!currinf.virtual)
+ file_pos = xtell(currinf.pos);
+ scan_frame = current_frame; /* now we're scanning */
+ refl_count = 0;
+ break;
+ }
+ /* we are scanning */
+ if (current_frame == scan_frame) ++refl_count;
+ break;
+
+ case EREFL:
+ if (scan_frame != NULL) { /* if we're scanning */
+ if (current_frame == scan_frame && --refl_count < 0)
+ {
+ /* we've hit the end of our scan */
+ scan_frame = NULL;
+ /* first: push */
+ if (current_frame->next == NULL) {
+ struct frame *newp =
+ xmalloc(sizeof(struct frame));
+
+ current_frame->next = newp;
+ newp->prev = current_frame;
+ newp->next = NULL;
+ }
+ current_frame = current_frame->next;
+ current_frame->data = currinf.data;
+ /* next: restore old file position, XX, etc. */
+ if (!currinf.virtual) {
+ off_t bgn_pos = xtell(dvi_buffer);
+
+ if (file_pos >= bgn_pos) {
+ oldinfo.pos = dvi_buffer
+ + (file_pos - bgn_pos);
+ oldinfo.end = currinf.end;
+ }
+ else {
+ (void) lseek(fileno(dvi_file), file_pos,
+ SEEK_SET);
+ oldinfo.pos = oldinfo.end;
+ }
+ }
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+ /* and then: recover position info. */
+ DVI_H = current_frame->data.dvi_h;
+ DVI_V = current_frame->data.dvi_v;
+ PXL_V = current_frame->data.pxl_v;
+ /* and finally, reverse direction */
+ currinf.dir = -currinf.dir;
+ }
+ break;
+ }
+ /* we're not scanning, */
+ /* so just reverse direction and then pop */
+ currinf.dir = -currinf.dir;
+ currinf.data = current_frame->data;
+ current_frame = current_frame->prev;
+ break;
+#endif /* TEXXET */
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ DVI_H += DIR * xspell_conv(xsnum(ch - RIGHT1 + 1));
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ WW = xspell_conv(xsnum(ch - W0));
+ case W0:
+ DVI_H += DIR * WW;
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ XX = xspell_conv(xsnum(ch - X0));
+ case X0:
+ DVI_H += DIR * XX;
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ DVI_V += xspell_conv(xsnum(ch - DOWN1 + 1));
+ PXL_V = pixel_conv(DVI_V);
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ YY = xspell_conv(xsnum(ch - Y0));
+ case Y0:
+ DVI_V += YY;
+ PXL_V = pixel_conv(DVI_V);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ ZZ = xspell_conv(xsnum(ch - Z0));
+ case Z0:
+ DVI_V += ZZ;
+ PXL_V = pixel_conv(DVI_V);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ case FNT4:
+ change_font(xnum(ch - FNT1 + 1));
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ a = xnum(ch - XXX1 + 1);
+ if (a > 0)
+ applicationDoSpecial(read_special(a));
+ break;
+
+ case FNTDEF1:
+ case FNTDEF2:
+ case FNTDEF3:
+ case FNTDEF4:
+ xskip((long) (12 + ch - FNTDEF1 + 1));
+ a = (long) xone();
+ xskip(a + (long) xone());
+ break;
+
+#ifndef TEXXET
+ case SREFL:
+ case EREFL:
+#endif
+ case PRE:
+ case POST:
+ case POSTPOST:
+ tell_oops("shouldn't happen: %s encountered",
+ dvi_table2[ch - (FNTNUM0 + 64)]);
+ break;
+
+ default:
+ tell_oops("unknown op-code %d", ch);
+ } /* end switch*/
+ } /* end else (ch not a SETCHAR or FNTNUM) */
+ } /* end for */
+}
+
+#undef xspell_conv
+
+void
+draw_page()
+{
+ /* Check for changes in dvi file. */
+ if (!check_dvi_file()) return;
+
+#if COLOR
+ color_bottom = &fg_initial;
+ color_bot_size = 1;
+ if (page_colors != NULL && current_page > 0) {
+ color_bottom = page_colors[current_page - 1].colorstack;
+ color_bot_size = page_colors[current_page - 1].stacksize;
+ }
+ rcs_top = NULL;
+ set_fg_color(&color_bottom[color_bot_size - 1]);
+#endif
+
+ /* draw border */
+ XDrawRectangle(DISP, currwin.win, highGC,
+ -currwin.base_x, -currwin.base_y,
+ ROUNDUP(page_info[current_page].pw, shrink_factor) + 1,
+ ROUNDUP(page_info[current_page].ph, shrink_factor) + 1);
+
+ (void) lseek(fileno(dvi_file), page_info[current_page].offset,
+ SEEK_SET);
+
+ bzero((char *) &currinf.data, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+ dvi_pointer_frame = &currinf;
+ psfig_begun = False;
+ drawing_mag = (currwin.win == alt.win);
+
+ /* NOTE: longjmp(canit_env) should not be done within read_events(). */
+ if (!setjmp(canit_env))
+ draw_part(current_frame = &frame0, dimconv);
+ else { /* if interrupted */
+ /* If we were interrupted, put the expose event back, so that the
+ * region gets redrawn. The if statement is necessary because the
+ * magnifier may have been destroyed as part of the interrupt. */
+ if (currwin.win == mane.win || currwin.win == alt.win)
+ expose(currwin.win == mane.win ? &mane : &alt,
+ min_x - currwin.base_x, min_y - currwin.base_y,
+ max_x - min_x, max_y - min_y);
+#if PS
+ psp.interrupt();
+#endif
+ ev_flags &= ~EV_MAG_GONE;
+ }
+
+ drawing_mag = False;
+ dvi_pointer_frame = NULL;
+ if (currwin.win == mane.win && source_fwd_box_page >= 0)
+ source_fwd_draw_box(); /* draw box showing found source line */
+#if PS
+ psp.endpage();
+#endif
+ currwin.win = (Window) 0;
+}
+
+
+/*
+ * General dvi scanning routines. These are used for:
+ * o source special lookups and
+ * o finding the dimensions of links (if compiling with support for
+ * hypertext specials).
+ * This routine can be a bit slower than draw_page()/draw_part(), since
+ * it is not run that often; that is why it is a separate routine in
+ * spite of much duplication.
+ *
+ * Note that it does not use a separate copy of define_font().
+ */
+
+/*
+ * All calculations are done with shrink factor = 1, so we re-do some
+ * macros accordingly. Many of these are also defined in special.c.
+ */
+
+#define xspell_conv(n) spell_conv0(n, current_dimconv)
+#define xpixel_conv(x) ((int) ((x) >> 16))
+#define xpixel_round(x) ((int) ROUNDUP(x, 1 << 16))
+
+#define G_PXL_H xpixel_conv(currinf.data.dvi_h)
+#define G_OFFSET_X (offset_x << 16) + (3 << 15)
+#define G_OFFSET_Y (offset_y << 16) + (3 << 15)
+
+#if TOOLKIT
+# define mane_base_x 0
+# define mane_base_y 0
+#else
+# define mane_base_x mane.base_x
+# define mane_base_y mane.base_y
+#endif
+
+/*
+ * This set of routines can be called while draw_part() is active,
+ * so the global variables must be separate.
+ */
+
+static struct frame geom_frame0; /* dummy head of list */
+#if TEXXET
+static struct frame *geom_scan_frame; /* head frame for scanning */
+#endif
+static struct frame *geom_current_frame;
+
+static void geom_scan_part ARGS((struct geom_info *,
+ struct frame *, double));
+
+/*
+ * Handle a character in geometric scanning routine.
+ */
+
+static long
+geom_do_char(g_info, ch)
+ struct geom_info *g_info;
+ wide_ubyte ch;
+{
+ if (currinf.set_char_p == set_no_char) {
+ if (currinf.virtual == NULL
+ || (currinf.fontp = currinf.virtual->first_font) == NULL)
+ return 0; /* error; we'll catch it later */
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ }
+
+ if (currinf.set_char_p == set_empty_char)
+ return 0; /* error; we'll catch it later */
+
+#if FREETYPE
+ if (currinf.set_char_p == set_ft_char)
+ do_load_freetype_font();
+#endif
+
+ if (currinf.set_char_p == load_n_set_char) {
+ if (ev_flags & EV_GE_NEWDOC) /* if abort */
+ return 0;
+ if (!load_font(currinf.fontp)) { /* if not found */
+ if (ev_flags & EV_GE_NEWDOC) /* if abort */
+ return 0;
+ Fputs("Character(s) will be left blank.\n", stderr);
+ currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
+ return 0;
+ }
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ }
+
+ if (currinf.set_char_p == set_char) {
+ struct glyph *g;
+ long x, y;
+
+ if (ch > maxchar)
+ return 0; /* catch the error later */
+ if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
+ if (g->addr == 0)
+ return 0; /* catch the error later */
+ if (g->addr == -1)
+ return 0; /* previously flagged missing char */
+#if FREETYPE
+ if (currinf.fontp->ft == NULL)
+#endif
+ {
+ open_font_file(currinf.fontp);
+ Fseek(currinf.fontp->file, g->addr, 0);
+ }
+ (*currinf.fontp->read_char)(currinf.fontp, ch);
+ if (debug & DBG_BITMAP) print_char((ubyte) ch, g);
+ currinf.fontp->timestamp = ++current_timestamp;
+ }
+#if TEXXET
+ if (geom_scan_frame == NULL) {
+ long dvi_h_sav = DVI_H;
+ if (currinf.dir < 0) DVI_H -= g->dvi_adv;
+#endif
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ g_info->geom_box(g_info, x, y,
+ x + g->bitmap.w - 1, y + g->bitmap.h - 1);
+
+#if TEXXET
+ DVI_H = dvi_h_sav;
+ }
+#endif
+ return DIR * g->dvi_adv;
+ }
+ else if (currinf.set_char_p == set_vf_char) {
+ struct macro *m;
+ struct drawinf oldinfo;
+ ubyte oldmaxchar;
+#if TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar)
+ return 0; /* catch the error later */
+ if ((m = &currinf.fontp->macro[ch])->pos == NULL)
+ return 0; /* catch the error later */
+#if TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0) DVI_H -= m->dvi_adv;
+ if (geom_scan_frame == NULL) {
+#endif
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ WW = XX = YY = ZZ = 0;
+ currinf.tn_table_len = VFTABLELEN;
+ currinf.tn_table = currinf.fontp->vf_table;
+ currinf.tn_head = currinf.fontp->vf_chain;
+ currinf.pos = m->pos;
+ currinf.end = m->end;
+ currinf.virtual = currinf.fontp;
+ geom_scan_part(g_info, geom_current_frame,
+ currinf.fontp->dimconv);
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+#if TEXXET
+ DVI_H = dvi_h_sav;
+ }
+#endif
+ return DIR * m->dvi_adv;
+ }
+ else {
+ oops("internal error -- currinf.set_char_p = 0x%x",
+ currinf.set_char_p);
+ /* NOTREACHED */
+ }
+}
+
+/*
+ * Do a rule in the geometry-scanning routine.
+ */
+
+static void
+geom_do_rule(g_info, h, w)
+ struct geom_info *g_info;
+ long h, w;
+{
+ long x, y;
+#if TEXXET
+ long dvi_h_save = DVI_H;
+#endif
+
+#if TEXXET
+ if (currinf.dir < 0) DVI_H -= w - 1;
+#endif
+ x = G_PXL_H;
+ y = PXL_V;
+ g_info->geom_box(g_info, x, y - xpixel_round(h) + 1,
+ x + xpixel_round(w) - 1, y);
+#if TEXXET
+ DVI_H = dvi_h_save;
+#endif
+}
+
+
+/*
+ * Geometric dvi scanner work routine. This does most of the work
+ * (a) reading from a page, and (b) executing vf macros.
+ */
+
+static void
+geom_scan_part(g_info, minframe, current_dimconv)
+ struct geom_info *g_info;
+ struct frame *minframe;
+ double current_dimconv;
+{
+ ubyte ch;
+#if TEXXET
+ struct drawinf oldinfo;
+ ubyte oldmaxchar;
+ off_t file_pos;
+ int refl_count;
+#endif
+
+ currinf.fontp = NULL;
+ currinf.set_char_p = set_no_char;
+#if TEXXET
+ currinf.dir = 1;
+ geom_scan_frame = NULL; /* indicates we're not scanning */
+#endif
+ for (;;) {
+ ch = xone();
+ if (ch <= (ubyte) (SETCHAR0 + 127))
+ DVI_H += geom_do_char(g_info, ch);
+ else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63))
+ change_font((unsigned long) (ch - FNTNUM0));
+ else {
+ long a, b;
+
+ switch (ch) {
+ case SET1:
+ case PUT1:
+ a = geom_do_char(g_info, xone());
+ if (ch != PUT1) DVI_H += a;
+ break;
+
+ case SETRULE:
+ /* Be careful, dvicopy outputs rules with
+ height = 0x80000000. We don't want any
+ SIGFPE here. */
+ a = xsfour();
+ b = xspell_conv(xsfour());
+#if TEXXET
+ if (a >= 0 && b >= 0 && geom_scan_frame == NULL)
+#else
+ if (a >= 0 && b >= 0)
+#endif
+ geom_do_rule(g_info, xspell_conv(a), b);
+ DVI_H += DIR * b;
+ break;
+
+ case PUTRULE:
+ a = xspell_conv(xsfour());
+ b = xspell_conv(xsfour());
+#if TEXXET
+ if (a >= 0 && b >= 0 && geom_scan_frame == NULL)
+#else
+ if (a >= 0 && b >= 0)
+#endif
+ geom_do_rule(g_info, a, b);
+ break;
+
+ case NOP:
+ break;
+
+ case BOP:
+ xskip((long) 11 * 4);
+ DVI_H = G_OFFSET_X;
+ DVI_V = G_OFFSET_Y;
+ PXL_V = xpixel_conv(DVI_V);
+ WW = XX = YY = ZZ = 0;
+ break;
+
+ case PUSH:
+ if (geom_current_frame->next == NULL) {
+ struct frame *newp = xmalloc(sizeof(struct frame));
+
+ geom_current_frame->next = newp;
+ newp->prev = geom_current_frame;
+ newp->next = NULL;
+ }
+ geom_current_frame = geom_current_frame->next;
+ geom_current_frame->data = currinf.data;
+ break;
+
+ case POP:
+ if (geom_current_frame == minframe)
+ tell_oops("more POPs than PUSHes");
+ currinf.data = geom_current_frame->data;
+ geom_current_frame = geom_current_frame->prev;
+ break;
+
+#if TEXXET
+ case SREFL:
+ if (geom_scan_frame == NULL) {
+ /* we're not scanning: save some info. */
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ if (!currinf.virtual)
+ file_pos = xtell(currinf.pos);
+ geom_scan_frame = geom_current_frame; /* start scanning*/
+ refl_count = 0;
+ break;
+ }
+ /* we are scanning */
+ if (geom_current_frame == geom_scan_frame) ++refl_count;
+ break;
+
+ case EREFL:
+ if (geom_scan_frame != NULL) { /* if we're scanning */
+ if (geom_current_frame == geom_scan_frame
+ && --refl_count < 0)
+ {
+ /* we've hit the end of our scan */
+ geom_scan_frame = NULL;
+ /* first: push */
+ if (geom_current_frame->next == NULL) {
+ struct frame *newp =
+ xmalloc(sizeof(struct frame));
+
+ geom_current_frame->next = newp;
+ newp->prev = geom_current_frame;
+ newp->next = NULL;
+ }
+ geom_current_frame = geom_current_frame->next;
+ geom_current_frame->data = currinf.data;
+ /* next: restore old file position, XX, etc. */
+ if (!currinf.virtual) {
+ off_t bgn_pos = xtell(dvi_buffer);
+
+ if (file_pos >= bgn_pos) {
+ oldinfo.pos = dvi_buffer
+ + (file_pos - bgn_pos);
+ oldinfo.end = currinf.end;
+ }
+ else {
+ (void) lseek(fileno(dvi_file), file_pos,
+ SEEK_SET);
+ oldinfo.pos = oldinfo.end;
+ }
+ }
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+ /* and then: recover position info. */
+ DVI_H = geom_current_frame->data.dvi_h;
+ DVI_V = geom_current_frame->data.dvi_v;
+ PXL_V = geom_current_frame->data.pxl_v;
+ /* and finally, reverse direction */
+ currinf.dir = -currinf.dir;
+ }
+ break;
+ }
+ /* we're not scanning, */
+ /* so just reverse direction and then pop */
+ currinf.dir = -currinf.dir;
+ currinf.data = geom_current_frame->data;
+ geom_current_frame = geom_current_frame->prev;
+ break;
+#endif /* TEXXET */
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ DVI_H += DIR * xspell_conv(xsnum(ch - RIGHT1 + 1));
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ WW = xspell_conv(xsnum(ch - W0));
+ case W0:
+ DVI_H += DIR * WW;
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ XX = xspell_conv(xsnum(ch - X0));
+ case X0:
+ DVI_H += DIR * XX;
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ DVI_V += xspell_conv(xsnum(ch - DOWN1 + 1));
+ PXL_V = xpixel_conv(DVI_V);
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ YY = xspell_conv(xsnum(ch - Y0));
+ case Y0:
+ DVI_V += YY;
+ PXL_V = xpixel_conv(DVI_V);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ ZZ = xspell_conv(xsnum(ch - Z0));
+ case Z0:
+ DVI_V += ZZ;
+ PXL_V = xpixel_conv(DVI_V);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ case FNT4:
+ change_font(xnum(ch - FNT1 + 1));
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ a = xnum(ch - XXX1 + 1);
+ if (a > 0) {
+ char *str = read_special(a);
+
+ /* process the bounding box */
+ geom_do_special(g_info, str, current_dimconv);
+
+ /* process the specials we're looking for */
+ g_info->geom_special(g_info, str);
+ }
+ break;
+
+ case FNTDEF1:
+ case FNTDEF2:
+ case FNTDEF3:
+ case FNTDEF4:
+ xskip((long) (12 + ch - FNTDEF1 + 1));
+ a = (long) xone();
+ xskip(a + (long) xone());
+ break;
+
+#if !TEXXET
+ case SREFL:
+ case EREFL:
+#endif
+ case PRE:
+ case POST:
+ case POSTPOST:
+ case EOP:
+ default:
+ return;
+
+ } /* end switch*/
+ } /* end else (ch not a SETCHAR or FNTNUM) */
+ } /* end for */
+}
+
+
+/*
+ * Main scanning routine.
+ */
+
+static void
+geom_scan(g_info)
+ struct geom_info *g_info;
+{
+ off_t pos_save;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+
+#if PS
+ if (scanned_page < current_page) return; /* should not happen */
+#endif
+
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(dvi_file), 0L, SEEK_CUR)
+ - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+ (void) lseek(fileno(dvi_file), page_info[current_page].offset,
+ SEEK_SET);
+
+ currinf_save = currinf;
+ maxchar_save = maxchar;
+
+ bzero((char *) &currinf.data, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ if (!setjmp(g_info->done_env))
+ geom_scan_part(g_info, geom_current_frame = &geom_frame0, dimconv);
+
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void) lseek(fileno(dvi_file), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
+ }
+}
+
+
+/*
+ * Routines for source special lookup
+ */
+
+static void
+src_spec_box ARGS((struct geom_info *, long, long, long, long));
+
+static void
+src_spec_special ARGS((struct geom_info *, _Xconst char *));
+
+struct src_parsed_special {
+ int line;
+ int col;
+ char *filename;
+ size_t filename_len;
+};
+
+struct src_spec_data {
+ long x, y; /* coordinates we're looking for */
+ unsigned long distance; /* best distance so far */
+ Boolean recent_in_best; /* most recent string == XXX->best */
+ struct src_parsed_special /* best special so far */
+ best;
+ struct src_parsed_special /* most recent special */
+ recent;
+};
+
+static void
+src_parse(str, parsed)
+ _Xconst char *str;
+ struct src_parsed_special *parsed;
+{
+ _Xconst char *p;
+
+ p = str + 4; /* skip "src:" */
+
+ if (*p >= '0' && *p <= '9') {
+ parsed->line = atoi(p);
+ do ++p;
+ while (*p >= '0' && *p <= '9');
+ }
+
+ parsed->col = 0;
+ if (*p == ':') {
+ ++p;
+ parsed->col = atoi(p);
+ while (*p >= '0' && *p <= '9') ++p;
+ }
+
+ if (*p == ' ') ++p;
+
+ if (*p != '\0') {
+ size_t len = strlen(p) + 1;
+
+ if (len > parsed->filename_len) {
+ if (parsed->filename_len != 0)
+ free(parsed->filename);
+ parsed->filename_len = (len & -8) + 64;
+ parsed->filename = xmalloc(parsed->filename_len);
+ }
+ memcpy(parsed->filename, p, len);
+ }
+}
+
+static void
+src_spec_box(g_info, ulx, uly, lrx, lry)
+ struct geom_info *g_info;
+ long ulx, uly, lrx, lry;
+{
+ struct src_spec_data *data = g_info->geom_data;
+ unsigned long distance;
+
+ distance = 0;
+
+ if (data->x < ulx) distance += (ulx - data->x) * (ulx - data->x);
+ else if (data->x > lrx) distance += (data->x - lrx) * (data->x - lrx);
+
+ if (data->y < uly) distance += (uly - data->y) * (uly - data->y);
+ else if (data->y > lry) distance += (data->y - lry) * (data->y - lry);
+
+ if (distance < data->distance) {
+ data->distance = distance;
+
+ /* Copy it over */
+ if (!data->recent_in_best) {
+ data->best.line = data->recent.line;
+ data->best.col = data->recent.col;
+ if (data->recent.filename_len != 0) {
+ if (data->best.filename_len < data->recent.filename_len) {
+ if (data->best.filename_len != 0)
+ free(data->best.filename);
+ data->best.filename_len = data->recent.filename_len;
+ data->best.filename = xmalloc(data->best.filename_len);
+ }
+ memcpy(data->best.filename, data->recent.filename,
+ data->recent.filename_len);
+ }
+
+ data->recent_in_best = True;
+ }
+
+ /* Quit early if we've found our glyph. */
+ if (distance == 0 && data->best.filename_len != 0)
+ longjmp(g_info->done_env, 1);
+ }
+}
+
+static void
+src_spec_special(g_info, str)
+ struct geom_info *g_info;
+ _Xconst char *str;
+{
+ struct src_spec_data *data = g_info->geom_data;
+
+ if (memcmp(str, "src:", 4) != 0)
+ return;
+
+ src_parse(str, &data->recent);
+
+ /*
+ * If this is the first special on the page, we may already have
+ * spotted the nearest box.
+ */
+
+ if (data->best.filename_len == 0) {
+ data->best.line = data->recent.line;
+ data->best.col = data->recent.col;
+ if (data->recent.filename_len != 0) {
+ if (data->best.filename_len < data->recent.filename_len) {
+ if (data->best.filename_len != 0)
+ free(data->best.filename);
+ data->best.filename_len = data->recent.filename_len;
+ data->best.filename = xmalloc(data->best.filename_len);
+ }
+ memcpy(data->best.filename, data->recent.filename,
+ data->recent.filename_len);
+
+ data->recent_in_best = True;
+ }
+
+ if (data->distance == 0)
+ longjmp(g_info->done_env, 1);
+ }
+ else
+ data->recent_in_best = False;
+}
+
+/*
+ * Routines for reverse searches on other pages.
+ */
+
+static struct src_parsed_special found;
+static jmp_buf scan_env;
+
+static void
+scan_first_src_spcl(str)
+ char *str;
+{
+ if (memcmp(str, "src:", 4) != 0)
+ return;
+
+ src_parse(str, &found);
+
+ longjmp(scan_env, 1);
+}
+
+static void
+scan_last_src_spcl(str)
+ char *str;
+{
+ if (memcmp(str, "src:", 4) != 0)
+ return;
+
+ src_parse(str, &found);
+}
+
+/*
+ * Information on how to search for source files.
+ */
+
+#include "filf-app.h" /* application-related defs, etc. */
+#include "filefind.h"
+
+static _Xconst char no_f_str_tex[] = "/%f";
+
+static struct findrec search_tex = {
+ /* path1 */ no_f_str_tex, /* flag value: uninitialized */
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ DEFAULT_SOURCE_PATH,
+ /* type */ "source",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f',
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_tex,
+ /* no_f_str_end */ no_f_str_tex + sizeof(no_f_str_tex) - 1,
+ /* abs_str */ "%f",
+#if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f',
+ /* pk_gf_addr */ NULL,
+#endif
+ /* pct_s_str */ "%qtex//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+
+static void
+src_spawn_editor(parsed)
+ _Xconst struct src_parsed_special *parsed;
+{
+ char scr_str[5 * sizeof(int) / 2];
+ _Xconst char *filename2;
+ Boolean found_filename = False;
+ size_t buffer_pos;
+ int argc;
+ char **argv;
+ _Xconst char *p, *p1;
+ char *q;
+ FILE *f;
+ int i;
+
+ /* Used to store argv[] text. */
+ static char *buffer;
+ static size_t buffer_len = 0;
+
+ /* first, determine the editor if necessary */
+ if (resource.editor == NULL || *resource.editor == '\0') {
+ p = getenv("XEDITOR");
+ if (p != NULL)
+ resource.editor = xstrdup(p);
+ else {
+
+ p = getenv("VISUAL");
+ if (p == NULL) {
+ p = getenv("EDITOR");
+ if (p == NULL)
+ p = "vi";
+ }
+ q = xmalloc(strlen(p) + 10);
+ memcpy(q, "xterm -e ", 9);
+ strcpy(q + 9, p);
+ resource.editor = q;
+ }
+ }
+
+ /* Now search for the file (same algorithm as PS files). */
+ f = NULL;
+ /* first try the same path as the dvi file */
+ if (parsed->filename[0] != '/') {
+ p = rindex(dvi_name, '/');
+ if (p == NULL) filename2 = parsed->filename;
+ else {
+ unsigned len1, len2;
+
+ len1 = ++p - dvi_name;
+ len2 = strlen(parsed->filename) + 1;
+ if (len1 + len2 > ffline_len)
+ expandline(len1 + len2);
+ bcopy(dvi_name, ffline, len1);
+ bcopy(parsed->filename, ffline + len1, len2);
+ filename2 = ffline;
+ }
+ if (debug & DBG_OPEN) Printf("Trying source special file %s\n",
+ filename2);
+ f = xfopen(filename2, OPEN_MODE);
+ }
+
+ if (f == NULL) {
+
+ /*
+ * Set up the paths, if necessary.
+ */
+
+ if (search_tex.path1 == no_f_str_tex) { /* if uninitialized */
+#if CFGFILE
+ if ((search_tex.path1 = getenv("XDVISOURCES")) == NULL)
+ search_tex.path1 = getenv("TEXINPUTS");
+ search_tex.envptr = ffgetenv("TEXINPUTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_tex.envptr != NULL
+ && search_tex.envptr->value == NULL)
+ search_tex.envptr = NULL;
+#else /* not CFGFILE */
+ if ((search_tex.path1 = getenv("XDVISOURCES")) == NULL
+ && (search_tex.path1 = getenv("TEXINPUTS")) == NULL) {
+ search_tex.path1 = search_tex.path2;
+ search_tex.path2 = NULL;
+ }
+#endif /* not CFGFILE */
+ }
+
+ f = filefind(parsed->filename, &search_tex, (_Xconst char **) NULL);
+ filename2 = ffline;
+ }
+
+ /* if still no luck, complain */
+ if (f == NULL)
+ WARN1(XmDIALOG_ERROR, "Cannot find source special file\n`%s'",
+ parsed->filename);
+ else {
+ struct stat buf;
+
+ if (fstat(fileno(f), &buf) == -1) {
+ perror(parsed->filename);
+ }
+ else {
+ if (buf.st_mtime > dvi_time)
+ WARN1(XmDIALOG_ERROR,
+ "Source file\n%s\nis newer than dvi file",
+ parsed->filename);
+ }
+
+ Fclose(f);
+ ++n_files_left;
+
+ if (buffer_len == 0)
+ buffer = xmalloc(buffer_len = 128);
+ buffer_pos = 0;
+ argc = 0;
+
+ p = resource.editor;
+ while (*p == ' ' || *p == '\t') ++p;
+
+ for (;;) {
+ size_t len;
+
+ if (*p == '%') {
+ p1 = p;
+ switch (p[1]) {
+ case '\0':
+ --p; /* partially undo p += 2 later */
+ /* control falls through */
+ case '%':
+ len = 1;
+ break;
+ case 'l':
+ p1 = scr_str;
+#if HAVE_VSNPRINTF
+ len = snprintf(scr_str, sizeof scr_str, "%d",
+ parsed->line);
+#else
+ len = sprintf(scr_str, "%d", parsed->line);
+#endif
+ break;
+ case 'c':
+ if (parsed->col == 0) {
+ p += 2;
+ continue;
+ }
+ p1 = scr_str;
+#if HAVE_VSNPRINTF
+ len = snprintf(scr_str, sizeof scr_str, "%d",
+ parsed->col);
+#else
+ len = sprintf(scr_str, "%d", parsed->col);
+#endif
+ break;
+ case 'f':
+ p1 = filename2;
+ len = strlen(filename2);
+ found_filename = True;
+ break;
+ default:
+ len = 2;
+ }
+ p += 2;
+ }
+ else if (*p == '\0' || *p == ' ' || *p == '\t') {
+ buffer[buffer_pos++] = '\0';
+ ++argc;
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p == '\0') {
+ if (found_filename)
+ break; /* done */
+ p = "+%l %f";
+ }
+ continue; /* don't copy anything over */
+ }
+ else {
+ p1 = p;
+ len = strcspn(p, "% \t");
+ p += len;
+ }
+
+ /* copy over len bytes starting at p1 into the buffer, */
+ /* leaving at least one byte free */
+ if (buffer_pos + len >= buffer_len) {
+ buffer_len = ((buffer_pos + len) / 128 + 1) * 128;
+ buffer = xrealloc(buffer, buffer_len);
+ }
+ memcpy(buffer + buffer_pos, p1, len);
+ buffer_pos += len;
+ }
+
+ argv = xmalloc((argc + 1) * sizeof(char *));
+ q = buffer;
+ for (i = 0; i < argc; ++i) {
+ argv[i] = q;
+ q += strlen(q) + 1;
+ }
+
+ /* NULL-terminate argument list */
+ argv[argc] = NULL;
+
+ Fflush(stdout); /* to avoid double buffering */
+ Fflush(stderr);
+
+ switch (vfork()) {
+ case -1:
+ perror("[xdvi] vfork");
+ break;
+ case 0: /* child */
+ execvp(argv[0], argv);
+
+ Fprintf(stderr, "%s: Execvp of %s failed.\n", prog,
+ argv[0]);
+ Fflush(stderr);
+ _exit(1);
+ }
+
+ free(argv);
+ }
+}
+
+
+/*
+ * The main routine for source specials (reverse search).
+ */
+
+void
+source_reverse_search(x, y)
+ int x, y;
+{
+ struct geom_info g_info;
+ struct src_spec_data data;
+ struct src_parsed_special *foundp;
+
+ g_info.geom_box = src_spec_box;
+ g_info.geom_special = src_spec_special;
+ g_info.geom_data = &data;
+
+ data.x = x;
+ data.y = y;
+ data.distance = 0xffffffff;
+ data.recent_in_best = True;
+ data.best.filename_len = data.recent.filename_len = 0;
+ foundp = &data.best;
+
+ geom_scan(&g_info);
+
+ if (data.best.filename_len == 0) {
+ /*
+ * nothing found on current page;
+ * scan next and previous pages with increasing offset
+ */
+ int upper, lower;
+ off_t pos_save;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+
+ /* Save file position */
+
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(dvi_file), 0L, SEEK_CUR)
+ - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+
+ currinf_save = currinf;
+ maxchar_save = maxchar;
+
+ upper = lower = current_page;
+ found.filename_len = 0; /* mark it as empty */
+ for (;;) {
+
+ if (++upper < total_pages) {
+ (void) lseek(fileno(dvi_file), page_info[upper].offset,
+ SEEK_SET);
+ bzero((char *) &currinf.data, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ if (setjmp(scan_env) == 0) {
+ /* find first src special */
+ spcl_scan(scan_first_src_spcl);
+ }
+ else { /* found it */
+ lower = upper;
+ break;
+ }
+ }
+ else if (lower < 0)
+ break;
+
+ if (--lower >= 0) {
+ (void) lseek(fileno(dvi_file), page_info[lower].offset,
+ SEEK_SET);
+ bzero((char *) &currinf.data, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ spcl_scan(scan_last_src_spcl);
+ if (found.filename_len != 0)
+ break;
+ }
+ }
+
+ if (found.filename_len != 0)
+ WARN1(XmDIALOG_WARNING,
+ "No source specials on this page - nearest on page %d",
+ lower + pageno_correct);
+ else {
+ /* nothing found at all; complain */
+ XBell(DISP, 0);
+ WARN(XmDIALOG_ERROR, "No source specials in this .dvi file");
+ }
+
+ /* Restore file status. */
+
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void) lseek(fileno(dvi_file), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
+ }
+
+ foundp = &found;
+ }
+
+ if (data.recent.filename_len != 0)
+ free(data.recent.filename);
+
+ if (foundp->filename_len != 0) {
+ src_spawn_editor(foundp);
+ free(foundp->filename);
+ }
+}
+
+
+/*
+ * Debug routines for source special display (highlight the first box
+ * after each source special, or highlight each box).
+ */
+
+static void
+src_spec_show_box ARGS((struct geom_info *, long, long, long, long));
+
+static void
+src_spec_show_special ARGS((struct geom_info *, _Xconst char *));
+
+struct src_spec_show_data {
+ Boolean do_this_one; /* flag set after source special */
+ Boolean do_them_all; /* flag to reset the above to */
+};
+
+static void
+src_spec_show_box(g_info, ulx, uly, lrx, lry)
+ struct geom_info *g_info;
+ long ulx, uly, lrx, lry;
+{
+ struct src_spec_show_data *data = g_info->geom_data;
+
+ if (data->do_this_one) {
+ long x = ulx / mane.shrinkfactor;
+ long y = uly / mane.shrinkfactor;
+
+ XDrawRectangle(DISP, mane.win, highGC,
+ x - mane_base_x, y - mane_base_y,
+ lrx / mane.shrinkfactor - x, lry / mane.shrinkfactor - y);
+
+ data->do_this_one = data->do_them_all;
+ }
+}
+
+ /* ARGSUSED */
+static void
+src_spec_show_special(g_info, str)
+ struct geom_info *g_info;
+ _Xconst char *str;
+{
+ if (memcmp(str, "src:", 4) != 0)
+ return;
+
+ ((struct src_spec_show_data *)g_info->geom_data)->do_this_one = True;
+}
+
+void
+source_special_show(do_them_all)
+ wide_bool do_them_all;
+{
+ struct geom_info g_info;
+ struct src_spec_show_data data;
+
+ g_info.geom_box = src_spec_show_box;
+ g_info.geom_special = src_spec_show_special;
+ g_info.geom_data = &data;
+
+ data.do_this_one = data.do_them_all = do_them_all;
+
+ geom_scan(&g_info);
+}
+
+
+/*
+ * Routines for forward search (look up a source line).
+ *
+ * The general procedure is:
+ * (1) Use spcl_scan() to find the page containing the line (or at
+ * least the closest line). This could be optimized further.
+ * (2) Use geom_scan_part() to find the exact location of the source
+ * special, and the box to highlight.
+ */
+
+/* These variables are referenced by src_scan_special(). */
+
+static int src_this_line;
+static size_t src_this_file_strcmp;
+static int src_line;
+static int src_col;
+static _Xconst char *src_file;
+static int src_page;
+static jmp_buf src_env;
+static Boolean found_src;
+static unsigned long best_distance;
+static unsigned long best_col_dist;
+static int best_line;
+static int best_page;
+static off_t best_offset;
+static off_t max_offset;
+
+/* Some of the above, plus these below, are used by geom_scan_part(). */
+
+static Boolean src_fwd_active;
+static long src_fwd_min_x, src_fwd_max_x;
+static long src_fwd_min_y, src_fwd_max_y;
+static long src_fwd_min_x2, src_fwd_max_x2; /* hot point for spcl */
+static long src_fwd_min_y2, src_fwd_max_y2;
+
+static void
+src_scan_special(str)
+ char *str;
+{
+ char *p;
+ int col = 0;
+ unsigned long distance;
+ unsigned long col_dist;
+
+ if (memcmp(str, "src:", 4) != 0)
+ return;
+
+ found_src = True;
+
+ p = str + 4;
+ if (*p >= '0' && *p <= '9') {
+ src_this_line = atoi(p);
+ do ++p;
+ while (*p >= '0' && *p <= '9');
+ }
+
+ if (*p == ':') {
+ ++p;
+ col = atoi(p);
+ while (*p >= '0' && *p <= '9') ++p;
+ }
+
+ if (*p == ' ') ++p;
+
+ if (*p == '.' && p[1] == '/') /* ignore leading ./ path component */
+ p += 2;
+
+ if (*p != '\0')
+ src_this_file_strcmp = strcmp(p, src_file);
+
+ if (src_this_file_strcmp != 0)
+ return;
+
+ distance = (src_line > src_this_line
+ ? src_line - src_this_line
+ : 2 * (src_this_line - src_line)); /* favor earlier lines */
+
+ if (distance < best_distance) { /* found a better line */
+ best_distance = distance;
+ best_line = src_this_line;
+ best_page = src_page;
+ max_offset = best_offset = xtell(currinf.pos);
+ }
+ else if (distance == best_distance) /* if still on a good line */
+ max_offset = xtell(currinf.pos);
+
+ if (distance == 0 && best_distance == 0) { /* found a better col */
+ col_dist = (src_col > col
+ ? src_col - col
+ : 2 * (col - src_col));
+
+ if (col_dist < best_col_dist) {
+ best_col_dist = col_dist;
+ best_page = src_page;
+ max_offset = best_offset = xtell(currinf.pos);
+ }
+ else if (col_dist == best_col_dist)
+ max_offset = xtell(currinf.pos);
+ }
+}
+
+static void
+src_spec_fwd_box ARGS((struct geom_info *, long, long, long, long));
+
+static void
+src_spec_fwd_special ARGS((struct geom_info *, _Xconst char *));
+
+ /* ARGSUSED */
+static void
+src_spec_fwd_box(g_info, ulx, uly, lrx, lry)
+ struct geom_info *g_info;
+ long ulx, uly, lrx, lry;
+{
+ if (src_fwd_active) {
+ if (ulx < src_fwd_min_x) src_fwd_min_x = ulx;
+ if (uly < src_fwd_min_y) src_fwd_min_y = uly;
+ if (lrx > src_fwd_max_x) src_fwd_max_x = lrx;
+ if (lry > src_fwd_max_y) src_fwd_max_y = lry;
+ }
+}
+
+static void
+src_spec_fwd_special(g_info, str)
+ struct geom_info *g_info;
+ _Xconst char *str;
+{
+ long pos;
+
+ if (memcmp(str, "src:", 4) != 0) /* if not "src:" */
+ return;
+
+ pos = xtell(currinf.pos);
+ if (pos >= best_offset)
+ src_fwd_active = True;
+
+ if (src_fwd_active) {
+ if (G_PXL_H < src_fwd_min_x2) src_fwd_min_x2 = G_PXL_H;
+ if (G_PXL_H > src_fwd_max_x2) src_fwd_max_x2 = G_PXL_H;
+ if (PXL_V < src_fwd_min_y2) src_fwd_min_y2 = PXL_V;
+ if (PXL_V > src_fwd_max_y2) src_fwd_max_y2 = PXL_V;
+
+ if (pos > max_offset)
+ longjmp(g_info->done_env, 1);
+ }
+}
+
+/*
+ * Routine to actually draw the box.
+ */
+
+static void
+source_fwd_draw_box()
+{
+ long x, y;
+
+ if (source_fwd_box_page != current_page)
+ source_fwd_box_page = -1; /* different page---clear it */
+ else {
+ if (src_fwd_min_x == 0x7fffffff) {
+ /* If no glyphs or rules, use hot point of special instead. */
+ src_fwd_min_x = src_fwd_min_x2;
+ src_fwd_min_y = src_fwd_min_y2;
+ src_fwd_max_x = src_fwd_max_x2;
+ src_fwd_max_y = src_fwd_max_y2;
+ }
+#define PAD 10
+ x = (src_fwd_min_x - PAD) / mane.shrinkfactor;
+ y = (src_fwd_min_y - PAD) / mane.shrinkfactor;
+
+ XDrawRectangle(DISP, mane.win, highGC,
+ x - mane_base_x, y - mane_base_y,
+ (src_fwd_max_x + PAD) / mane.shrinkfactor - x,
+ (src_fwd_max_y + PAD) / mane.shrinkfactor - y);
+ }
+}
+
+void
+source_forward_search(str)
+ _Xconst char *str;
+{
+ off_t pos_save;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+ struct geom_info g_info;
+
+ if (debug & DBG_CLIENT)
+ printf("Entering source_forward_search(%s)\n", str);
+
+ src_file = str;
+ while (*src_file == '0') ++src_file;
+ if (*src_file < '1' || *src_file > '9') {
+ fprintf(stderr,
+ "Badly formatted source special; ignoring: \"%s\"\n", str);
+ return;
+ }
+ src_line = atoi(src_file);
+ while (*src_file >= '0' && *src_file <= '9') ++src_file;
+
+ src_col = 0;
+ if (*src_file == ':') {
+ ++src_file;
+ src_col = atoi(src_file);
+ while (*src_file >= '0' && *src_file <= '9') ++src_file;
+ }
+
+ if (*src_file == ' ') ++src_file;
+
+ if (debug & DBG_CLIENT)
+ printf("File = \"%s\", line = %d, col = %d\n", src_file, src_line,
+ src_col);
+
+ /* Save status of dvi_file reading (in case we hit an error and resume
+ drawing). */
+
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(dvi_file), 0L, SEEK_CUR)
+ - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+ (void) lseek(fileno(dvi_file), page_info[0].offset, SEEK_SET);
+
+ currinf_save = currinf;
+ maxchar_save = maxchar;
+
+ bzero((char *) &currinf.data, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ /* Start search over pages */
+
+ found_src = False;
+ best_distance = best_col_dist = 0xffffffff;
+ src_this_line = 0; /* initialize things that are kept as defaults*/
+ src_this_file_strcmp = 1;
+ if (setjmp(src_env) == 0) {
+
+ /* These two lines do the actual scanning (first pass). */
+ for (src_page = 0; src_page < total_pages; ++src_page)
+ spcl_scan(src_scan_special);
+
+ if (best_distance == 0xffffffff) {
+ if (!found_src)
+ WARN(XmDIALOG_ERROR, "No source specials in the dvi file");
+ else
+ WARN1(XmDIALOG_ERROR,
+ "No references to source file \"%s\" in dvi file",
+ src_file);
+
+ /* Restore file position. */
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void) lseek(fileno(dvi_file), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end
+ = dvi_buffer;
+ }
+
+ return;
+ }
+ if (debug & DBG_CLIENT)
+ printf("Found close match: line %d on page %d, offset %lu\n",
+ best_line, best_page + pageno_correct, best_offset);
+ }
+ else {
+ if (debug & DBG_CLIENT)
+ printf("Found exact match on page %d, offset %lu\n",
+ best_page + pageno_correct, best_offset);
+ }
+
+ /*
+ * In this case we don't need to restore maxchar and currinf, since
+ * we won't resume drawing -- we'll jump to a new page instead.
+ */
+
+ /* Move to that page. */
+
+ if (current_page != best_page)
+ goto_page(best_page, home);
+ ev_flags |= EV_NEWPAGE;
+ XMapRaised(DISP, XtWindow(top_level));
+
+ /* Now search that particular page. */
+
+ g_info.geom_box = src_spec_fwd_box;
+ g_info.geom_special = src_spec_fwd_special;
+ g_info.geom_data = NULL;
+
+ src_fwd_active = False;
+ src_fwd_min_x = src_fwd_min_x2 = src_fwd_min_y = src_fwd_min_y2 =
+ 0x7fffffff;
+ src_fwd_max_x = src_fwd_max_x2 = src_fwd_max_y = src_fwd_max_y2 =
+ -0x7fffffff;
+ source_fwd_box_page = -1; /* in case of error, suppress box */
+
+ (void) lseek(fileno(dvi_file), page_info[best_page].offset, SEEK_SET);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ if (!setjmp(g_info.done_env))
+ geom_scan_part(&g_info, geom_current_frame = &geom_frame0, dimconv);
+
+ if (!src_fwd_active) {
+ if (debug & DBG_CLIENT)
+ fprintf(stderr,
+ "geom_scan_part() failed to re-find the special!\n");
+ }
+ else
+ source_fwd_box_page = current_page;
+}
diff --git a/dvi-init.c b/dvi-init.c
@@ -0,0 +1,1030 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi.h"
+#include "dvi.h"
+#include <sys/stat.h>
+
+#if FREETYPE
+# include <ft2build.h>
+# include FT_SIZES_H
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if XAW
+# include <X11/Shell.h> /* defines XtNtitle and XtNiconName */
+#endif
+
+#define PK_PRE 247
+#define PK_ID 89
+#define PK_MAGIC ((PK_PRE << 8) | PK_ID)
+#define GF_PRE 247
+#define GF_ID 131
+#define GF_MAGIC ((GF_PRE << 8) | GF_ID)
+#define VF_PRE 247
+#define VF_ID_BYTE 202
+#define VF_MAGIC ((VF_PRE << 8) | VF_ID_BYTE)
+
+static jmp_buf dvi_env; /* mechanism to relay dvi file errors */
+static _Xconst char *dvi_oops_msg; /* error message */
+
+#define dvi_oops(str) (dvi_oops_msg = (str), longjmp(dvi_env, 1))
+
+static Boolean font_not_found;
+static Boolean dvi_is_valid = False; /* if not initializing */
+
+/*
+ * DVI preamble and postamble information.
+ */
+static char job_id[300];
+static long numerator, denominator;
+static unsigned int dvi_unshrunk_page_w, dvi_unshrunk_page_h;
+
+/*
+ * Offset in DVI file of last page, set in read_postamble().
+ */
+static long last_page_offset;
+
+
+/*
+ * free_vf_chain frees the vf_chain structure.
+ */
+
+static void
+free_vf_chain(tnp)
+ struct tn *tnp;
+{
+ while (tnp != NULL) {
+ struct tn *tnp1 = tnp->next;
+ free((char *) tnp);
+ tnp = tnp1;
+ }
+}
+
+
+/*
+ * Release all shrunken bitmaps for all fonts.
+ */
+
+void
+reset_fonts()
+{
+ struct font *f;
+ struct glyph *g;
+
+ for (f = font_head; f != NULL; f = f->next)
+ if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL))
+ for (g = f->glyph; g <= f->glyph + f->maxchar; ++g) {
+ if (g->bitmap2.bits) {
+ free(g->bitmap2.bits);
+ g->bitmap2.bits = NULL;
+ }
+#ifdef GREY
+ if (g->pixmap2) {
+ XDestroyImage(g->image2);
+ g->pixmap2 = NULL;
+ if (g->pixmap2_t != NULL) {
+ free(g->pixmap2_t);
+ g->pixmap2_t = NULL;
+ }
+ }
+#if COLOR
+ g->fg = NULL;
+#endif
+#endif /* GREY */
+ }
+}
+
+
+#if COLOR
+
+/*
+ * Release all allocated pixels, and (in greyscale mode) invalidate
+ * all shrunken glyphs.
+ */
+
+void
+reset_colors()
+{
+ if (color_list_len != 0) {
+ XFreeColors(DISP, our_colormap, color_list, color_list_len, 0);
+ color_list_len = 0;
+ }
+ while (bg_head != NULL) {
+ struct bgrec *bgp;
+ struct fgrec *fgp;
+
+ for (fgp = bg_head->fg_head; fgp != NULL;) {
+ struct fgrec *fgp1 = fgp->next;
+ free(fgp);
+ fgp = fgp1;
+ }
+ bgp = bg_head->next;
+ free(bg_head);
+ bg_head = bgp;
+ }
+#if GREY
+ if (use_grey) {
+ struct font *f;
+ struct glyph *g;
+
+ for (f = font_head; f != NULL; f = f->next)
+ if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL))
+ for (g = f->glyph; g <= f->glyph + f->maxchar; ++g)
+ g->fg = NULL;
+ }
+#endif /* GREY */
+ bg_current = NULL;
+ fg_active = NULL;
+ color_warned = False;
+}
+
+/*
+ * All of the above, plus discard all scanned information.
+ */
+
+void
+full_reset_colors()
+{
+ if (page_colors != NULL) {
+ int i;
+ _Xconst struct rgb *last_freed = &fg_initial;
+
+ for (i = 0; i < total_pages; ++i) {
+ if (page_colors[i].colorstack != last_freed) {
+ last_freed = page_colors[i].colorstack;
+ if (last_freed != NULL)
+ free((char *) last_freed);
+ }
+ }
+ free((char *) page_colors);
+ page_colors = NULL;
+ }
+ reset_colors();
+}
+
+#endif /* COLOR */
+
+
+/*
+ * realloc_font allocates the font structure to contain (newsize + 1)
+ * characters.
+ */
+
+void
+realloc_font(fontp, newsize)
+ struct font *fontp;
+ wide_ubyte newsize;
+{
+ struct glyph *glyph;
+
+ glyph = fontp->glyph = xrealloc(fontp->glyph,
+ (unsigned int) (newsize + 1) * sizeof(struct glyph));
+ if (newsize > fontp->maxchar)
+ bzero((char *) (glyph + fontp->maxchar + 1),
+ (int) (newsize - fontp->maxchar) * sizeof(struct glyph));
+ maxchar = fontp->maxchar = newsize;
+}
+
+
+/*
+ * realloc_virtual_font does the same thing for virtual fonts.
+ */
+
+void
+realloc_virtual_font(fontp, newsize)
+ struct font *fontp;
+ wide_ubyte newsize;
+{
+ struct macro *macro;
+
+ macro = fontp->macro = xrealloc(fontp->macro,
+ (unsigned int) (newsize + 1) * sizeof(struct macro));
+ if (newsize > fontp->maxchar)
+ bzero((char *) (macro + fontp->maxchar + 1),
+ (int) (newsize - fontp->maxchar) * sizeof(struct macro));
+ maxchar = fontp->maxchar = newsize;
+}
+
+
+/*
+ * load_font locates the raster file and reads the index of characters,
+ * plus whatever other preprocessing is done (depending on the format).
+ * Returns True if successful; False if not.
+ */
+
+Boolean
+load_font(fontp)
+ struct font *fontp;
+{
+ double fsize = fontp->fsize;
+ int dpi = fsize + 0.5;
+ char *font_found;
+ int size_found;
+ int magic;
+ Boolean hushcs = hush_chk;
+
+ if (!font_open(fontp, &font_found, &size_found)) {
+ if (ev_flags & EV_GE_NEWDOC)
+ return False;
+ fontp->flags |= FONT_LOADED; /* as loaded as it'll get */
+ Fprintf(stderr, "%s: can't find font %s.\n", prog, fontp->fontname);
+ return False;
+ }
+ fontp->flags |= FONT_LOADED;
+ if (font_found != NULL) {
+ Fprintf(stderr,
+ "%s: can't find font %s; using %s instead at %d dpi.\n",
+ prog, fontp->fontname, font_found, dpi);
+ free(fontp->fontname);
+ fontp->fontname = font_found;
+ hushcs = True;
+ }
+ else if (size_found > (int) (1.002 * fsize + 0.5) ||
+ size_found < (int) (0.998 * fsize + 0.5))
+ Fprintf(stderr,
+ "%s: can't find font %s at %d dpi; using %d dpi instead.\n",
+ prog, fontp->fontname, dpi, size_found);
+ fontp->timestamp = ++current_timestamp;
+ fontp->maxchar = maxchar = 255;
+ fontp->set_char_p = set_char;
+#if FREETYPE
+ if (fontp->ft != NULL) { /* if freetype font */
+ fontp->set_char_p = set_ft_char;
+ fontp->glyph = xmalloc(256 * sizeof(struct glyph));
+ bzero((char *) fontp->glyph, 256 * sizeof(struct glyph));
+ return True;
+ }
+#endif
+ fontp->fsize = size_found;
+ magic = two(fontp->file);
+ if (magic == PK_MAGIC) read_PK_index(fontp, WIDENINT hushcs);
+ else
+#if USE_GF
+ if (magic == GF_MAGIC) read_GF_index(fontp, WIDENINT hushcs);
+ else
+#endif
+ if (magic == VF_MAGIC) read_VF_index(fontp, WIDENINT hushcs);
+ else
+ oops("Cannot recognize format for font file %s", fontp->filename);
+
+ if (fontp->flags & FONT_VIRTUAL) {
+ while (maxchar > 0 && fontp->macro[maxchar].pos == NULL) --maxchar;
+ if (maxchar < 255)
+ realloc_virtual_font(fontp, WIDENINT maxchar);
+ }
+ else {
+ while (maxchar > 0 && fontp->glyph[maxchar].addr == 0) --maxchar;
+ if (maxchar < 255)
+ realloc_font(fontp, WIDENINT maxchar);
+ }
+ return True;
+}
+
+
+/*
+ * MAGSTEPVALUE - If the given magnification is close to a \magstep
+ * or a \magstephalf, then return twice the number of \magsteps.
+ * Otherwise return NOMAGSTP.
+ */
+
+#define NOMAGSTP (-29999)
+#define NOBUILD 29999
+
+static int
+magstepvalue(mag)
+ float *mag;
+{
+ int m = 0;
+ double fmag = *mag;
+ double xmag = pixels_per_inch;
+ float margin = fmag * 0.002;
+
+ if (fmag < pixels_per_inch)
+ for (;;) {
+ if (xmag - fmag < margin && -(xmag - fmag) < margin) {
+ *mag = xmag;
+ return m;
+ }
+ if (xmag < fmag) break;
+ xmag *= 0.9128709292;
+ --m;
+ }
+ else
+ for (;;) {
+ if (xmag - fmag < margin && -(xmag - fmag) < margin) {
+ *mag = xmag;
+ return m;
+ }
+ if (xmag > fmag) break;
+ xmag *= 1.095445115;
+ ++m;
+ }
+ return NOMAGSTP;
+}
+
+
+/*
+ * reuse_font recursively sets the flags for font structures being reused.
+ */
+
+static void
+reuse_font(fontp)
+ struct font *fontp;
+{
+ struct font **fp;
+ struct tn *tnp;
+
+ if (fontp->flags & FONT_IN_USE) return;
+
+ fontp->flags |= FONT_IN_USE;
+ if (list_fonts)
+ Printf("(reusing) %s at %d dpi\n", fontp->fontname,
+ (int) (fontp->fsize + 0.5));
+ if (fontp->flags & FONT_VIRTUAL) {
+ for (fp = fontp->vf_table; fp < fontp->vf_table + VFTABLELEN; ++fp)
+ if (*fp != NULL) reuse_font(*fp);
+ for (tnp = fontp->vf_chain; tnp != NULL; tnp = tnp->next)
+ reuse_font(tnp->fontp);
+ }
+}
+
+
+/*
+ * define_font reads the rest of the fntdef command and then reads in
+ * the specified pixel file, adding it to the global linked-list holding
+ * all of the fonts used in the job.
+ */
+struct font *
+define_font(file, cmnd, vfparent, tntable, tn_table_len, tn_headpp)
+ FILE *file;
+ wide_ubyte cmnd;
+ struct font *vfparent; /* vf parent of this font, or NULL */
+ struct font **tntable; /* table for low TeXnumbers */
+ unsigned int tn_table_len; /* length of table for TeXnumbers */
+ struct tn **tn_headpp; /* addr of head of list of TeXnumbers */
+{
+ int TeXnumber;
+ struct font *fontp;
+ float fsize;
+ double scale_dimconv;
+ long checksum;
+ int scale;
+ int design;
+ int magstepval;
+ int len;
+ char *fontname;
+ int size;
+
+ TeXnumber = num(file, (int) cmnd - FNTDEF1 + 1);
+ checksum = four(file);
+ scale = four(file);
+ design = four(file);
+ len = one(file); len += one(file); /* sequence point in the middle */
+ fontname = xmalloc((unsigned) len + 1);
+ Fread(fontname, sizeof(char), len, file);
+ fontname[len] = '\0';
+ if(debug & DBG_PK)
+ Printf("Define font \"%s\" scale=%d design=%d\n",
+ fontname, scale, design);
+ if (vfparent == NULL) {
+ fsize = 0.001 * scale / design * magnification * pixels_per_inch;
+ scale_dimconv = dimconv;
+ }
+ else {
+ /*
+ * The scaled size is given in units of vfparent->scale * 2 ** -20
+ * SPELL units, so we convert it into SPELL units by multiplying by
+ * vfparent->dimconv.
+ * The design size is given in units of 2 ** -20 pt, so we convert
+ * into SPELL units by multiplying by
+ * (pixels_per_inch * 2**16) / (72.27 * 2**20).
+ */
+ fsize = (72.27 * (1<<4)) * vfparent->dimconv * scale / design;
+ scale_dimconv = vfparent->dimconv;
+ }
+ magstepval = magstepvalue(&fsize);
+ size = fsize + 0.5;
+ /*
+ * reuse font if possible
+ */
+ for (fontp = font_head;; fontp = fontp->next) {
+ if (fontp == NULL) { /* if font doesn't exist yet */
+ if (list_fonts)
+ Printf("%s at %d dpi\n", fontname, (int) (fsize + 0.5));
+ fontp = (struct font *) xmalloc((unsigned) sizeof(struct font));
+ fontp->fontname = fontname;
+ fontp->fsize = fsize;
+ fontp->magstepval = magstepval;
+ fontp->file = NULL; /* needed for virtual/freetype fonts */
+ fontp->filename = NULL; /* needed for freetype fonts */
+ fontp->checksum = checksum;
+ fontp->flags = FONT_IN_USE;
+ fontp->dimconv = scale * scale_dimconv / (1<<20);
+ fontp->set_char_p = load_n_set_char;
+#if FREETYPE
+ fontp->ft = NULL;
+ /* spsize = scaled size of the font in spell units,
+ * = scale * [vfparent->]dimconv.
+ */
+ fontp->spsize =
+ (vfparent != NULL ? vfparent->dimconv : dimconv) * scale;
+#endif
+ if (vfparent == NULL)
+ if (!load_font(fontp)) {
+ if (ev_flags & EV_GE_NEWDOC) { /* if aborting */
+ free(fontname);
+ free(fontp);
+ return NULL;
+ }
+ font_not_found = True;
+ }
+ fontp->next = font_head;
+ font_head = fontp;
+ break;
+ }
+ if (strcmp(fontname, fontp->fontname) == 0
+ && size == (int) (fontp->fsize + 0.5)) {
+ /* if font already in use */
+ reuse_font(fontp);
+ free(fontname);
+ break;
+ }
+ }
+ if (TeXnumber < tn_table_len)
+ tntable[TeXnumber] = fontp;
+ else {
+ struct tn *tnp;
+ tnp = xmalloc((unsigned) sizeof(struct tn));
+ tnp->next = *tn_headpp;
+ *tn_headpp = tnp;
+ tnp->TeXnumber = TeXnumber;
+ tnp->fontp = fontp;
+ }
+ return fontp;
+}
+
+
+/*
+ * process_preamble reads the information in the preamble and stores
+ * it into global variables for later use.
+ */
+static void
+process_preamble()
+{
+ ubyte k;
+
+ if (one(dvi_file) != PRE)
+ dvi_oops("Not a DVI file");
+ if (one(dvi_file) != 2)
+ dvi_oops("Wrong version of DVI output for this program");
+ numerator = four(dvi_file);
+ denominator = four(dvi_file);
+ magnification = four(dvi_file);
+ dimconv = (((double) numerator * magnification)
+ / ((double) denominator * 1000.));
+ dimconv = dimconv * (((long) pixels_per_inch)<<16) / 254000;
+ tpic_conv = pixels_per_inch * magnification / 1000000.0;
+ k = one(dvi_file);
+ Fread(job_id, sizeof(char), (int) k, dvi_file);
+ job_id[k] = '\0';
+}
+
+/*
+ * find_postamble locates the beginning of the postamble
+ * and leaves the file ready to start reading at that location.
+ */
+#define TMPSIZ 516 /* 4 trailer bytes + 512 junk bytes allowed */
+static void
+find_postamble()
+{
+ long pos;
+ ubyte temp[TMPSIZ];
+ ubyte *p;
+ ubyte *p1;
+ ubyte byte;
+
+ Fseek(dvi_file, (long) 0, 2);
+ pos = ftell(dvi_file) - TMPSIZ;
+ if (pos < 0) pos = 0;
+ Fseek(dvi_file, pos, 0);
+ p = temp + fread((char *) temp, sizeof(char), TMPSIZ, dvi_file);
+ for (;;) {
+ p1 = p;
+ while (p1 > temp && *(--p1) != TRAILER) ;
+ p = p1;
+ while (p > temp && *(--p) == TRAILER) ;
+ if (p <= p1 - 4) break; /* found 4 TRAILER bytes */
+ if (p <= temp) dvi_oops("DVI file corrupted");
+ }
+ pos += p - temp;
+ byte = *p;
+ while (byte == TRAILER) {
+ Fseek(dvi_file, --pos, 0);
+ byte = one(dvi_file);
+ }
+ if (byte != 2)
+ dvi_oops("Wrong version of DVI output for this program");
+ Fseek(dvi_file, pos - 4, 0);
+ Fseek(dvi_file, sfour(dvi_file), 0);
+}
+
+
+/*
+ * read_postamble reads the information in the postamble,
+ * storing it into global variables.
+ * It also takes care of reading in all of the pixel files for the fonts
+ * used in the job.
+ */
+static Boolean
+read_postamble()
+{
+ ubyte cmnd;
+ struct font *fontp;
+ struct font **fontpp;
+
+ if (one(dvi_file) != POST)
+ dvi_oops("Postamble doesn't begin with POST");
+ last_page_offset = four(dvi_file);
+ if (numerator != four(dvi_file)
+ || denominator != four(dvi_file)
+ || magnification != four(dvi_file))
+ dvi_oops("Postamble doesn't match preamble");
+ /* read largest box height and width */
+ dvi_unshrunk_page_h = (spell_conv(sfour(dvi_file)) >> 16) + offset_y;
+ if (dvi_unshrunk_page_h < unshrunk_paper_h)
+ dvi_unshrunk_page_h = unshrunk_paper_h;
+ dvi_unshrunk_page_w = (spell_conv(sfour(dvi_file)) >> 16) + offset_x;
+ if (dvi_unshrunk_page_w < unshrunk_paper_w)
+ dvi_unshrunk_page_w = unshrunk_paper_w;
+ (void) two(dvi_file); /* max stack size */
+ total_pages = two(dvi_file);
+ font_not_found = False;
+ while ((cmnd = one(dvi_file)) >= FNTDEF1 && cmnd <= FNTDEF4)
+ if (define_font(dvi_file, cmnd, (struct font *) NULL,
+ tn_table, TNTABLELEN, &tn_head) == NULL)
+ return False;
+ if (cmnd != POSTPOST)
+ dvi_oops("Non-fntdef command found in postamble");
+ if (font_not_found)
+ dvi_oops("Not all pixel files were found");
+ /*
+ * free up fonts no longer in use
+ */
+ fontpp = &font_head;
+ while ((fontp = *fontpp) != NULL)
+ if (fontp->flags & FONT_IN_USE)
+ fontpp = &fontp->next;
+ else {
+ if (debug & DBG_PK)
+ Printf("Discarding font \"%s\" at %d dpi\n",
+ fontp->fontname, (int) (fontp->fsize + 0.5));
+ *fontpp = fontp->next; /* remove from list */
+ free(fontp->fontname);
+ if (fontp->flags & FONT_LOADED) {
+#if FREETYPE
+ if (fontp->ft != NULL) { /* if FreeType font */
+ struct ftfont *ft;
+
+ ft = fontp->ft;
+ if (fontp->size != NULL)
+ FT_Done_Size(fontp->size);
+ if (fontp == ft->first_size) {
+ if (fontp->next_size == NULL) {
+ /* if this is the only size of this font face */
+ FT_Done_Face(ft->face);
+ ft->t1->ft = NULL;
+ free(ft);
+ }
+ else {
+ struct font *fp2;
+
+ ft->first_size = fp2 = fontp->next_size;
+ fp2->file = fontp->file;
+ fontp->file = NULL;
+ fp2->filename = fontp->filename;
+ fontp->filename = NULL;
+ fp2->timestamp = fontp->timestamp;
+ }
+ }
+ else {
+ struct font *fp2;
+
+ fp2 = ft->first_size;
+ while (fp2->next_size != fontp)
+ fp2 = fp2->next_size;
+ fp2->next_size = fontp->next_size;
+ }
+ }
+#endif
+ if (fontp->file != NULL) {
+ Fclose(fontp->file);
+ ++n_files_left;
+ }
+#if FREETYPE
+ if (fontp->filename != NULL)
+#endif
+ free((void *) fontp->filename);
+
+ if (fontp->flags & FONT_VIRTUAL) {
+ struct macro *m;
+
+ for (m = fontp->macro;
+ m <= fontp->macro + fontp->maxchar; ++m)
+ if (m->free_me) free((char *) m->pos);
+ free((char *) fontp->macro);
+ free((char *) fontp->vf_table);
+ free_vf_chain(fontp->vf_chain);
+ }
+ else {
+ struct glyph *g;
+
+ for (g = fontp->glyph;
+ g <= fontp->glyph + fontp->maxchar; ++g) {
+ if (g->bitmap.bits != NULL) free(g->bitmap.bits);
+ if (g->bitmap2.bits != NULL) free(g->bitmap2.bits);
+#ifdef GREY
+ if (g->pixmap2 != NULL) {
+ XDestroyImage(g->image2);
+ if (g->pixmap2_t != NULL)
+ free(g->pixmap2_t);
+ }
+#endif
+ }
+ free((char *) fontp->glyph);
+ }
+ free((char *) fontp);
+ }
+ }
+ return True;
+}
+
+static void
+prepare_pages()
+{
+ int i;
+
+ page_info = xmalloc((unsigned) (total_pages + 1) * sizeof *page_info);
+ page_info->pw = unshrunk_paper_w;
+ page_info->ph = unshrunk_paper_h;
+ page_info->ww = dvi_unshrunk_page_w;
+ page_info->wh = dvi_unshrunk_page_h;
+ ++page_info; /* this is indexed starting with -1 */
+
+ i = total_pages;
+ page_info[--i].offset = last_page_offset;
+ Fseek(dvi_file, last_page_offset, 0);
+ /*
+ * Follow back pointers through pages in the DVI file,
+ * storing the offsets in the page_info[].offset table.
+ */
+ while (i > 0) {
+ Fseek(dvi_file, (long) (1+4+(9*4)), 1);
+ Fseek(dvi_file, page_info[--i].offset = four(dvi_file), 0);
+ }
+
+ /* If not prescanning, initialize page sizes. */
+ if (!resource.prescan)
+ for (i = 0; i < total_pages; ++i) {
+ page_info[i].pw = unshrunk_paper_w;
+ page_info[i].ph = unshrunk_paper_h;
+ page_info[i].ww = dvi_unshrunk_page_w;
+ page_info[i].wh = dvi_unshrunk_page_h;
+ }
+}
+
+void
+init_page()
+{
+ unshrunk_page_w = page_info[current_page].ww;
+ page_w = ROUNDUP(unshrunk_page_w, mane.shrinkfactor) + 2;
+ unshrunk_page_h = page_info[current_page].wh;
+ page_h = ROUNDUP(unshrunk_page_h, mane.shrinkfactor) + 2;
+}
+
+/**
+ ** form_dvi_property forms the property used to exhibit the dvi file name
+ ** used as a window property (used for source specials).
+ **/
+
+void
+form_dvi_property(inode)
+ ino_t inode;
+{
+ size_t len;
+ char *p;
+ unsigned long ino;
+ int i;
+
+ if (dvi_file == NULL)
+ return;
+
+ if (dvi_property != NULL)
+ free(dvi_property);
+
+ p = rindex(dvi_name, '/');
+ if (p != NULL) ++p; else p = dvi_name;
+ len = strlen(p);
+
+ dvi_property_length = len + 8;
+ dvi_property = xmalloc(dvi_property_length);
+
+ /* Do it this way because different copies of xdvi might be running on
+ machines with different endiannesses. */
+ ino = dvi_inode = inode;
+ for (i = 0; i < 8; ++i) {
+ dvi_property[i] = ino;
+ ino >>= 8;
+ }
+ memcpy(dvi_property + 8, p, len);
+}
+
+#if TOOLKIT
+ /* For non-toolkit compiles, this code appears in xdvi.c. */
+
+static void
+set_titles()
+{
+ char *title_name;
+ char *icon_name;
+ size_t baselen;
+ Boolean icon_name_malloced = False;
+
+ icon_name = rindex(dvi_name, '/');
+ if (icon_name != NULL) ++icon_name;
+ else icon_name = dvi_name;
+ baselen = strlen(icon_name);
+ if (baselen > 4 && memcmp(icon_name + baselen - 4, ".dvi", 4) == 0) {
+ /* remove the .dvi */
+ char *p;
+
+ baselen -= 4;
+ p = xmalloc(baselen + 1);
+ memcpy(p, icon_name, baselen);
+ p[baselen] = '\0';
+ icon_name = p;
+ icon_name_malloced = True;
+ }
+
+ title_name = xmalloc(baselen + 8);
+ memcpy(title_name, "Xdvi: ", 7);
+ memcpy(title_name + 7, icon_name, baselen + 1);
+
+ XtVaSetValues(top_level,
+ XtNtitle, title_name,
+ XtNiconName, icon_name,
+ NULL);
+
+ free(title_name);
+ if (icon_name_malloced)
+ free(icon_name);
+
+ titles_are_stale = False;
+}
+
+#endif
+
+
+/**
+ ** open_dvi_file opens the dvi file (if present), checks that it's not
+ ** a directory, saves its time stamp, and forms its dvi property.
+ ** Returns True if the operation succeeds. Upon failure, returns False
+ ** and dvi_file == NULL.
+ **/
+
+Boolean
+open_dvi_file(path)
+ _Xconst char *path;
+{
+ struct stat buf;
+ ino_t old_inode;
+
+ dvi_file = fopen(path, OPEN_MODE);
+ if (dvi_file == NULL)
+ return False;
+
+ if (fstat(fileno(dvi_file), &buf) != 0
+ || S_ISDIR(buf.st_mode)) { /* if it's a directory */
+ fclose(dvi_file);
+ dvi_file = NULL;
+ return False;
+ }
+
+ dvi_time = buf.st_mtime;
+
+ old_inode = dvi_inode;
+ form_dvi_property(buf.st_ino);
+ if (dvi_inode != old_inode && mane.win != (Window) 0)
+ set_dvi_property();
+
+ return True;
+}
+
+/*
+ * internal_init_dvi is the main subroutine for reading the startup
+ * information from the dvi file.
+ */
+
+static Boolean
+internal_init_dvi()
+{
+ process_preamble();
+ find_postamble();
+ if (!read_postamble()) {
+ Fclose(dvi_file);
+ dvi_file = NULL;
+ return False;
+ }
+ prepare_pages();
+ if (current_page >= total_pages) current_page = total_pages - 1;
+ warn_spec_now = warn_spec;
+ source_fwd_box_page = -1;
+ init_prescan();
+#if TOOLKIT
+ if (titles_are_stale)
+ set_titles();
+#endif
+ dvi_is_valid = True;
+ return True;
+}
+
+/**
+ ** init_dvi_file initializes the dvi file. Called only from main().
+ **/
+
+void
+init_dvi_file()
+{
+ if (setjmp(dvi_env)) oops(dvi_oops_msg);
+
+ (void) internal_init_dvi();
+}
+
+/**
+ ** set_dvi_property sets the appropriate property for the main
+ ** window (used in source special handoff).
+ **/
+
+void
+set_dvi_property()
+{
+ XChangeProperty(DISP, XtWindow(top_level), ATOM_DVI_FILE, ATOM_DVI_FILE,
+ 8, PropModeReplace, dvi_property, dvi_property_length);
+}
+
+#if TOOLKIT
+
+static Widget dvi_popup = NULL; /* warning popup for corrupt dvi file */
+
+/* ARGSUSED */
+static void
+dvi_callback(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ ev_flags |= EV_NEWDOC;
+ if (dvi_popup != NULL) {
+ XtDestroyWidget(dvi_popup);
+ dvi_popup = NULL;
+ }
+}
+
+#endif /* TOOLKIT */
+
+/**
+ ** Check for changes in dvi file. Return True if it's OK.
+ **/
+
+Boolean
+check_dvi_file()
+{
+ struct stat buf;
+
+ if (!dvi_is_valid)
+ return False;
+
+ if (dvi_file == NULL) {
+ /* check if file exists and has changed */
+ if (!(ev_flags & EV_NEWDOC) && stat(dvi_name, &buf) == 0
+ && buf.st_mtime != dvi_time)
+ ev_flags |= EV_NEWDOC;
+ return False;
+ }
+ else if (fstat(fileno(dvi_file), &buf) != 0
+ || buf.st_mtime != dvi_time) {
+ ev_flags |= EV_NEWDOC;
+ Fclose(dvi_file);
+ dvi_file = NULL;
+ dvi_file_ready = False;
+ return False;
+ }
+
+ return True;
+}
+
+/**
+ ** Reload the dvi file (unconditionally). Called only from do_pages().
+ **/
+
+void
+reload_dvi_file()
+{
+ struct font *fontp;
+
+ dvi_is_valid = dvi_file_ready = False;
+ if (page_info != NULL) {
+ free((char *) (page_info - 1));
+ page_info = NULL;
+#if COLOR
+ full_reset_colors();
+#endif /* COLOR */
+ }
+#if TOOLKIT
+ if (dvi_popup != NULL) {
+ int i;
+
+ for (i = 0;; ++i) {
+ if (i >= n_init_popups) {
+ XtDestroyWidget(dvi_popup);
+ break;
+ }
+ if (XtParent(init_popups[i]) == dvi_popup) {
+ while (++i < n_init_popups)
+ init_popups[i - 1] = init_popups[i];
+ --n_init_popups;
+ break;
+ }
+ }
+ dvi_popup = NULL;
+ }
+#endif /* TOOLKIT */
+ bzero((char *) tn_table, (int) sizeof(tn_table));
+ free_vf_chain(tn_head);
+ tn_head = NULL;
+ for (fontp = font_head; fontp != NULL; fontp = fontp->next)
+ fontp->flags &= ~FONT_IN_USE;
+
+ if (!setjmp(dvi_env)) {
+ if (dvi_file == NULL) {
+ if (!open_dvi_file(dvi_name))
+ dvi_oops("Cannot reopen dvi file.");
+ }
+ else {
+ struct stat buf;
+
+ if (fstat(fileno(dvi_file), &buf) == 0)
+ dvi_time = buf.st_mtime;
+ Fseek(dvi_file, (long) 0, 0);
+ }
+ if (!internal_init_dvi())
+ return;
+ if (list_fonts) Putchar('\n');
+ }
+ else { /* if error */
+ XClearWindow(DISP, mane.win);
+#if TOOLKIT
+ dvi_popup = warning_popup_long(
+ "Xdvi cannot read the DVI file\n%s\nReason: %s",
+# if MOTIF
+ XmDIALOG_ERROR,
+# endif
+ "Reload", dvi_callback, dvi_name, dvi_oops_msg);
+#else /* no toolkit */
+ showmessage(dvi_oops_msg);
+#endif
+ if (dvi_file != NULL) {
+ Fclose(dvi_file);
+ dvi_file = NULL;
+ }
+ }
+}
diff --git a/dvi.h b/dvi.h
@@ -0,0 +1,62 @@
+/*
+ * Mnemonics for bytes in dvi file.
+ */
+
+#define SETCHAR0 0
+#define SET1 128
+#define SETRULE 132
+#define PUT1 133
+#define PUTRULE 137
+#define NOP 138
+#define BOP 139
+#define EOP 140
+#define PUSH 141
+#define POP 142
+#define RIGHT1 143
+#define RIGHT2 144
+#define RIGHT3 145
+#define RIGHT4 146
+#define W0 147
+#define W1 148
+#define W2 149
+#define W3 150
+#define W4 151
+#define X0 152
+#define X1 153
+#define X2 154
+#define X3 155
+#define X4 156
+#define DOWN1 157
+#define DOWN2 158
+#define DOWN3 159
+#define DOWN4 160
+#define Y0 161
+#define Y1 162
+#define Y2 163
+#define Y3 164
+#define Y4 165
+#define Z0 166
+#define Z1 167
+#define Z2 168
+#define Z3 169
+#define Z4 170
+#define FNTNUM0 171
+#define FNT1 235
+#define FNT2 236
+#define FNT3 237
+#define FNT4 238
+#define XXX1 239
+#define XXX2 240
+#define XXX3 241
+#define XXX4 242
+#define FNTDEF1 243
+#define FNTDEF2 244
+#define FNTDEF3 245
+#define FNTDEF4 246
+#define PRE 247
+#define POST 248
+#define POSTPOST 249
+#define SREFL 250
+#define EREFL 251
+
+#define TRAILER 223 /* Trailing bytes at end of file */
diff --git a/events.c b/events.c
@@ -0,0 +1,5064 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2004 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi.h"
+#include <ctype.h>
+
+/* Xlib and Xutil are already included */
+
+#ifdef TOOLKIT
+
+#ifdef OLD_X11_TOOLKIT
+#include <X11/Atoms.h>
+#else /* not OLD_X11_TOOLKIT */
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#endif /* not OLD_X11_TOOLKIT */
+
+#include <X11/Shell.h> /* needed for def. of XtNiconX */
+
+#if XtSpecificationRelease >= 4
+
+#if XAW
+# if XAW3D
+# include <X11/Xaw3d/Viewport.h>
+# else
+# include <X11/Xaw/Viewport.h>
+# endif
+# include <X11/cursorfont.h>
+#else /* MOTIF */
+#include <Xm/MainW.h>
+#include <Xm/ToggleB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/MenuShell.h>
+#endif /* MOTIF */
+
+#ifdef BUTTONS
+#if XAW
+# if XAW3D
+# include <X11/Xaw3d/Command.h>
+# else
+# include <X11/Xaw/Command.h>
+# endif
+#define PANEL_WIDGET_CLASS compositeWidgetClass
+#define BUTTON_WIDGET_CLASS commandWidgetClass
+#else /* MOTIF */
+#include <Xm/Form.h>
+#include <Xm/BulletinB.h>
+#include <Xm/PushB.h>
+#define PANEL_WIDGET_CLASS xmBulletinBoardWidgetClass
+#define BUTTON_WIDGET_CLASS xmPushButtonWidgetClass
+#endif /* MOTIF */
+#endif /* BUTTONS */
+
+#else /* XtSpecificationRelease < 4 */
+
+#if NeedFunctionPrototypes
+typedef void *XtPointer;
+#else
+typedef char *XtPointer;
+#endif
+
+#include <X11/Viewport.h>
+#ifdef BUTTONS
+#include <X11/Command.h>
+#define PANEL_WIDGET_CLASS compositeWidgetClass
+#define BUTTON_WIDGET_CLASS commandWidgetClass
+#endif
+
+#endif /* XtSpecificationRelease */
+
+#else /* not TOOLKIT */
+
+typedef int Position;
+#define XtPending() XPending(DISP)
+
+#endif /* not TOOLKIT */
+
+#if HAVE_XKB_BELL_EXT
+# include <X11/XKBlib.h>
+# define XBell(dpy, percent) XkbBell(dpy, mane.win, percent, (Atom) None)
+#endif
+
+#include <signal.h>
+#include <sys/file.h> /* this defines FASYNC */
+#include <sys/ioctl.h> /* this defines SIOCSPGRP and FIOASYNC */
+#include <sys/wait.h> /* ignore HAVE_SYS_WAIT_H -- we always need WNOHANG */
+
+/* Linux prefers O_ASYNC over FASYNC; SGI IRIX does the opposite. */
+#if !defined(FASYNC) && defined(O_ASYNC)
+#define FASYNC O_ASYNC
+#endif
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+#if !defined(SIOCSPGRP) || !defined(FIOASYNC)
+#define FLAKY_SIGPOLL 1
+#endif
+#endif
+
+#ifndef FLAKY_SIGPOLL
+
+#ifndef SIGPOLL
+#define SIGPOLL SIGIO
+#endif
+
+#ifndef SA_RESTART
+#define SA_RESTART 0
+#endif
+
+#if HAVE_STREAMS
+#include <stropts.h>
+
+#ifndef S_RDNORM
+#define S_RDNORM S_INPUT
+#endif
+
+#ifndef S_RDBAND
+#define S_RDBAND 0
+#endif
+
+#ifndef S_HANGUP
+#define S_HANGUP 0
+#endif
+
+#ifndef S_WRNORM
+#define S_WRNORM S_OUTPUT
+#endif
+#endif /* HAVE_STREAMS */
+
+#endif /* not FLAKY_SIGPOLL */
+
+#if HAVE_SIGACTION && !defined SA_RESETHAND
+# ifdef SA_ONESHOT
+# define SA_RESETHAND SA_ONESHOT
+# else
+# undef HAVE_SIGACTION /* Needed for Mac OS X < 10.2 (9/2002) */
+# endif
+#endif
+
+#if HAVE_POLL
+# include <poll.h>
+#else
+# if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# else
+# if HAVE_SELECT_H
+# include <select.h>
+# endif
+# endif
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifndef X11HEIGHT
+#define X11HEIGHT 8 /* Height of server default font */
+#endif
+
+#define MAGBORD 1 /* border size for magnifier */
+
+/*
+ * Command line flags.
+ */
+
+#define fore_Pixel resource._fore_Pixel
+#define back_Pixel resource._back_Pixel
+#ifdef TOOLKIT
+extern struct _resource resource;
+#define brdr_Pixel resource._brdr_Pixel
+#endif /* TOOLKIT */
+
+#define clip_w mane.width
+#define clip_h mane.height
+static Position main_x, main_y;
+static Position mag_x, mag_y, new_mag_x, new_mag_y;
+#if TOOLKIT && !MOTIF
+static int mag_conv_x, mag_conv_y;
+#else
+#define mag_conv_x 0
+#define mag_conv_y 0
+#endif
+static Boolean dragcurs = False;
+
+static sigset_t all_signals;
+
+static void xdvi_normal_exit();
+
+/*
+ * The cursor shape in the magnifying glass is determined by which
+ * window received the button press event. Under XAW, that is a parent
+ * of mane.win, so we have to define the cursor of that window instead
+ * of mane.win in that case.
+ */
+
+#if XAW
+# if BUTTONS
+# define CURSORWIN XtWindow(form_widget)
+# else
+# define CURSORWIN XtWindow(vport_widget)
+# endif
+#else
+# define CURSORWIN mane.win
+#endif
+
+#if COLOR
+static XColor bg_Color;
+#endif
+
+#if TOOLKIT
+
+#define ACTION_DECL(name) \
+ void name ARGS((Widget, XEvent *, String *, Cardinal *))
+
+#define ACTION(name) \
+ void \
+ name P4C(Widget, w, \
+ XEvent *, event, \
+ String *, params, \
+ Cardinal *, num_params)
+
+#else /* not TOOLKIT */
+
+#define ACTION_DECL(name) \
+ void name ARGS((XEvent *))
+
+#define ACTION(name) \
+ void \
+ name P1C(XEvent *, event)
+
+#endif /* not TOOLKIT */
+
+/* ARGSUSED */
+void
+null_mouse P1C(XEvent *, event)
+{
+}
+
+static ACTION_DECL(Act_digit);
+static ACTION_DECL(Act_minus);
+static ACTION_DECL(Act_quit);
+static ACTION_DECL(Act_goto_page);
+static ACTION_DECL(Act_forward_page);
+static ACTION_DECL(Act_back_page);
+static ACTION_DECL(Act_declare_page_number);
+static ACTION_DECL(Act_home);
+static ACTION_DECL(Act_center);
+static ACTION_DECL(Act_set_keep_flag);
+static ACTION_DECL(Act_left);
+static ACTION_DECL(Act_right);
+static ACTION_DECL(Act_up);
+static ACTION_DECL(Act_down);
+static ACTION_DECL(Act_up_or_previous);
+static ACTION_DECL(Act_down_or_next);
+static ACTION_DECL(Act_set_margins);
+static ACTION_DECL(Act_show_display_attributes);
+static ACTION_DECL(Act_set_shrink_factor);
+static ACTION_DECL(Act_shrink_to_dpi);
+static ACTION_DECL(Act_set_density);
+#if GREY
+static ACTION_DECL(Act_set_greyscaling);
+#endif
+#if COLOR
+static ACTION_DECL(Act_set_color);
+#endif
+#if PS
+static ACTION_DECL(Act_set_ps);
+#endif
+#if PS_GS
+static ACTION_DECL(Act_set_gs_alpha);
+#endif
+#if BUTTONS
+static ACTION_DECL(Act_set_expert_mode);
+#endif
+#if !TOOLKIT
+static ACTION_DECL(Act_redraw);
+#endif
+static ACTION_DECL(Act_reread_dvi_file);
+static ACTION_DECL(Act_discard_number);
+
+static ACTION_DECL(Act_magnifier);
+static ACTION_DECL(Act_drag);
+static ACTION_DECL(Act_wheel);
+static ACTION_DECL(Act_hwheel);
+#if TOOLKIT
+static ACTION_DECL(Act_wheel_actions);
+#endif
+static ACTION_DECL(Act_motion);
+static ACTION_DECL(Act_release);
+ACTION_DECL(Act_source_special);
+ACTION_DECL(Act_show_source_specials);
+ACTION_DECL(Act_show_all_boxes);
+
+#if TOOLKIT
+
+XtActionsRec Actions[] = {
+ {"digit", Act_digit},
+ {"minus", Act_minus},
+ {"quit", Act_quit},
+ {"goto-page", Act_goto_page},
+ {"forward-page", Act_forward_page},
+ {"back-page", Act_back_page},
+ {"declare-page-number", Act_declare_page_number},
+ {"home", Act_home},
+ {"center", Act_center},
+ {"set-keep-flag", Act_set_keep_flag},
+ {"left", Act_left},
+ {"right", Act_right},
+ {"up", Act_up},
+ {"down", Act_down},
+ {"up-or-previous", Act_up_or_previous},
+ {"down-or-next", Act_down_or_next},
+ {"set-margins", Act_set_margins},
+ {"show-display-attributes", Act_show_display_attributes},
+ {"set-shrink-factor", Act_set_shrink_factor},
+ {"shrink-to-dpi", Act_shrink_to_dpi},
+ {"set-density", Act_set_density},
+ {"print", Act_print},
+ {"open-dvi-file", Act_open_dvi_file},
+#if GREY
+ {"set-greyscaling", Act_set_greyscaling},
+#endif
+#if COLOR
+ {"set-color", Act_set_color},
+#endif
+#if PS
+ {"set-ps", Act_set_ps},
+#endif
+#if PS_GS
+ {"set-gs-alpha", Act_set_gs_alpha},
+#endif
+#if BUTTONS
+ {"set-expert-mode", Act_set_expert_mode},
+#endif
+ {"reread-dvi-file", Act_reread_dvi_file},
+ {"discard-number", Act_discard_number},
+ {"magnifier", Act_magnifier},
+ {"drag", Act_drag},
+ {"wheel", Act_wheel},
+ {"hwheel", Act_hwheel},
+ {"wheel-actions", Act_wheel_actions},
+ {"motion", Act_motion},
+ {"release", Act_release},
+ {"source-special", Act_source_special},
+ {"show-source-specials",Act_show_source_specials},
+ {"show-all-boxes", Act_show_all_boxes},
+};
+
+Cardinal num_actions = XtNumber(Actions);
+
+
+Bool
+compile_action(str, app)
+ _Xconst char *str;
+ struct xdvi_action **app;
+{
+ _Xconst char *p, *p1, *p2;
+ XtActionsRec *actp;
+ struct xdvi_action *ap;
+
+ for (;;) {
+ while (*str == ' ' || *str == '\t') ++str;
+
+ if (*str == '\0' || *str == '\n')
+ break;
+
+ p = str;
+ while (((*p | ('a' ^ 'A')) >= 'a' && (*p | ('a' ^ 'A')) <= 'z')
+ || (*p >= '0' && *p <= '9') || *p == '-' || *p == '_')
+ ++p;
+
+ for (actp = Actions;; ++actp) {
+ if (actp >= Actions + XtNumber(Actions)) {
+ fprintf(stderr, "%s: cannot compile action %.*s\n", prog,
+ (int) (p - str), str);
+ *app = NULL;
+ return False;
+ }
+ if (memcmp(str, actp->string, p - str) == 0
+ && actp->string[p - str] == '\0')
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p != '(') {
+ while (*p != '\0' && *p != '\n') ++p;
+ fprintf(stderr, "%s: syntax error in action %.*s\n", prog,
+ (int) (p - str), str);
+ *app = NULL;
+ return False;
+ }
+ ++p;
+ while (*p == ' ' || *p == '\t') ++p;
+ for (p1 = p;; ++p1) {
+ if (*p1 == '\0' || *p1 == '\n') {
+ fprintf(stderr, "%s: syntax error in action %.*s\n", prog,
+ (int) (p1 - str), str);
+ *app = NULL;
+ return False;
+ }
+ if (*p1 == ')') break;
+ }
+
+ ap = xmalloc(sizeof *ap);
+ ap->proc = actp->proc;
+ for (p2 = p1;; --p2)
+ if (p2 <= p) { /* if no args */
+ ap->num_params = 0;
+ ap->param = NULL;
+ break;
+ }
+ else if (p2[-1] != ' ' && p2[-1] != '\t') {
+ char *arg;
+
+ arg = xmalloc(p2 - p + 1);
+ bcopy(p, arg, p2 - p);
+ arg[p2 - p] = '\0';
+ ap->num_params = 1;
+ ap->param = arg;
+ break;
+ }
+
+ *app = ap;
+ app = &ap->next;
+
+ str = p1 + 1;
+ }
+
+ *app = NULL;
+ return True;
+}
+
+
+#if BUTTONS
+static Widget line_widget;
+static int destroy_count = 0;
+# if MOTIF
+static Widget panel_widget; /* otherwise it's defined in xdvi.h */
+# endif
+#endif /* BUTTONS */
+
+#ifndef MOTIF
+static Widget x_bar, y_bar; /* horizontal and vertical scroll bars */
+#endif
+
+static Arg resize_args[] = {
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal) 0},
+};
+
+#define XdviResizeWidget(widget, w, h) \
+ (width_arg.value = (XtArgVal) (w), \
+ resize_args[1].value = (XtArgVal) (h), \
+ XtSetValues(widget, resize_args, XtNumber(resize_args)) )
+
+#define width_arg (resize_args[0])
+#define height_arg (resize_args[1])
+
+#if BUTTONS
+
+#ifndef MOTIF
+static Arg resizable_on[] = {
+ {XtNresizable, (XtArgVal) True},
+};
+
+static Arg resizable_off[] = {
+ {XtNresizable, (XtArgVal) False},
+};
+#endif
+
+static Arg line_args[] = {
+ {XtNbackground, (XtArgVal) 0},
+ {XtNwidth, (XtArgVal) 1},
+#if !MOTIF
+ {XtNfromHoriz, (XtArgVal) NULL},
+ {XtNborderWidth, (XtArgVal) 0},
+ {XtNtop, (XtArgVal) XtChainTop},
+ {XtNbottom, (XtArgVal) XtChainBottom},
+ {XtNleft, (XtArgVal) XtChainRight},
+ {XtNright, (XtArgVal) XtChainRight},
+#else /* MOTIF */
+ {XmNleftWidget, (XtArgVal) NULL},
+ {XmNleftAttachment, (XtArgVal) XmATTACH_WIDGET},
+ {XmNtopAttachment, (XtArgVal) XmATTACH_FORM},
+ {XmNbottomAttachment, (XtArgVal) XmATTACH_FORM},
+#endif /* MOTIF */
+};
+
+static Arg panel_args[] = {
+#if !MOTIF
+ {XtNborderWidth, (XtArgVal) 0},
+ {XtNfromHoriz, (XtArgVal) NULL},
+ {XtNtranslations, (XtArgVal) NULL},
+ {XtNtop, (XtArgVal) XtChainTop},
+ {XtNbottom, (XtArgVal) XtChainBottom},
+ {XtNleft, (XtArgVal) XtChainRight},
+ {XtNright, (XtArgVal) XtChainRight},
+#else /* MOTIF */
+ {XmNleftAttachment, (XtArgVal) XmATTACH_FORM},
+ {XmNtopAttachment, (XtArgVal) XmATTACH_FORM},
+ {XmNbottomAttachment, (XtArgVal) XmATTACH_FORM},
+#endif /* MOTIF */
+};
+
+static void handle_command();
+
+static XtCallbackRec command_call[] = {
+ {handle_command, NULL},
+ {NULL, NULL},
+};
+
+static Arg command_args[] = {
+#ifndef MOTIF
+ {XtNlabel, (XtArgVal) NULL},
+#else
+ {XmNlabelString, (XtArgVal) NULL},
+#endif
+ {XtNx, (XtArgVal) 0},
+ {XtNy, (XtArgVal) 0},
+ {XtNborderWidth,(XtArgVal) 0},
+#ifndef MOTIF
+ {XtNcallback, (XtArgVal) command_call},
+#else
+ {XmNactivateCallback, (XtArgVal) command_call},
+#endif
+};
+
+struct button_info {
+ struct button_info *next;
+ char *label;
+ struct xdvi_action *action;
+ Widget widget;
+};
+
+static struct button_info *b_head;
+
+_Xconst char default_button_config[] =
+#if PS
+ "Quit:quit()\n\
+Open:open-dvi-file()\n\n\
+Full size:set-shrink-factor(1)\n\
+$%%:shrink-to-dpi(150)\n\
+$%%:shrink-to-dpi(100)\n\
+$%%:shrink-to-dpi(75)\n\n\
+Page-10:back-page(10)\n\
+Page-5:back-page(5)\n\
+Prev:back-page(1)\n\n\
+Next:forward-page(1)\n\
+Page+5:forward-page(5)\n\
+Page+10:forward-page(10)\n\n\
+View PS:set-ps(toggle)\n\
+Print:print()";
+#else
+ "Quit:quit()\n\
+Open:open-dvi-file()\n\n\
+Full size:set-shrink-factor(1)\n\
+$%%:shrink-to-dpi(150)\n\
+$%%:shrink-to-dpi(100)\n\
+$%%:shrink-to-dpi(75)\n\n\
+Page-10:back-page(10)\n\
+Page-5:back-page(5)\n\
+Prev:back-page(1)\n\n\
+Next:forward-page(1)\n\
+Page+5:forward-page(5)\n\
+Page+10:forward-page(10)\n\n\
+Print:print()";
+#endif
+
+void
+create_buttons()
+{
+ Dimension max_button_width;
+ Dimension y_pos;
+ struct button_info **bipp;
+ struct button_info *bp;
+ _Xconst char *cspos;
+ int button_number;
+ int shrink_button_number;
+ int shrink_arg;
+ struct xdvi_action *action;
+
+ line_args[0].value = (XtArgVal) resource._fore_Pixel;
+#if XAW
+ line_args[2].value = (XtArgVal) vport_widget;
+ line_widget = XtCreateWidget("line", widgetClass, form_widget,
+ line_args, XtNumber(line_args));
+ panel_args[1].value = (XtArgVal) line_widget;
+ if (panel_args[2].value == (XtArgVal) NULL)
+ panel_args[2].value =
+ (XtArgVal) XtParseTranslationTable("<ButtonPress>:");
+ panel_widget = XtCreateWidget("panel", PANEL_WIDGET_CLASS,
+ form_widget, panel_args, XtNumber(panel_args));
+#else
+ panel_widget = XtCreateManagedWidget("panel", PANEL_WIDGET_CLASS,
+ form_widget, panel_args, XtNumber(panel_args));
+ if (wheel_trans_table != NULL)
+ XtOverrideTranslations(panel_widget, wheel_trans_table);
+#endif
+
+ button_number = shrink_button_number = 0;
+ b_head = NULL;
+ bipp = &b_head;
+ command_args[1].value = resource.btn_side_spacing;
+ command_args[3].value = resource.btn_border_width;
+ max_button_width = 0;
+ y_pos = resource.btn_top_spacing;
+
+ for (cspos = resource.button_translations;; ++cspos) {
+ Dimension w, h;
+ _Xconst char *p1, *p2;
+ char *label, *q;
+ char name[9];
+ Widget widget;
+ size_t len;
+
+ while (*cspos == ' ' || *cspos == '\t') ++cspos;
+ if (*cspos == '\0') break;
+
+ if (*cspos == '\n') {
+ y_pos += resource.btn_between_extra;
+ continue;
+ }
+
+ len = 0; /* find length of actual label string */
+ shrink_arg = 0;
+ for (p2 = p1 = cspos; *p1 != '\0' && *p1 != ':'; ) {
+ if (*p1 == '\\' && p1[1] != '\0') {
+ p1 += 2;
+ p2 = p1;
+ --len;
+ }
+ else if (*p1 == '$'
+ && (p1[1] == '#' || p1[1] == '%' || p1[1] == '_')) {
+ shrink_arg = 1;
+ ++p1;
+ if (*p1 == '%') len += 2;
+ else if (*p1 == '_') len -= 2;
+ }
+ else {
+ ++p1;
+ if (p1[-1] != ' ' && p1[-1] != '\t') p2 = p1;
+ }
+ }
+ len += p2 - cspos;
+
+ if (*p1 == '\0') break; /* if premature end of string */
+
+ if (!compile_action(p1 + 1, &action)) break;
+
+ if (shrink_arg) {
+ for (;; action = action->next) {
+ if (action == NULL) {
+ fprintf(stderr, "Warning: label on button number %d \
+refers to non-existent shrink action.\n", button_number + 1);
+ break;
+ }
+ if (action->proc == Act_set_shrink_factor
+ || action->proc == Act_shrink_to_dpi) {
+ if (shrink_button_number < 9
+ && resource.shrinkbutton[shrink_button_number] != 0) {
+ shrink_arg
+ = resource.shrinkbutton[shrink_button_number];
+ if (shrink_arg < 1) shrink_arg = 1;
+ else if (shrink_arg > 99) shrink_arg = 99;
+ if (action->num_params > 0) free(action->param);
+ action->proc = Act_set_shrink_factor;
+ action->num_params = 1;
+ action->param = xmalloc(4);
+ sprintf(action->param, "%d", shrink_arg);
+ }
+ else {
+ if (action->num_params > 0) {
+ shrink_arg = atoi(action->param);
+ if (action->proc == Act_shrink_to_dpi)
+ shrink_arg = (double) pixels_per_inch
+ / shrink_arg + 0.5;
+ if (shrink_arg < 1) shrink_arg = 1;
+ else if (shrink_arg > 99) shrink_arg = 99;
+ }
+ }
+ break;
+ }
+ }
+ ++shrink_button_number;
+ }
+
+ label = xmalloc(len + 1);
+ for (q = label; cspos < p2; ++cspos) {
+ if (*cspos == '\\') {
+ if (++cspos < p2)
+ *q++ = *cspos;
+ }
+ else if (*cspos == '$'
+ && (cspos[1] == '#' || cspos[1] == '%' || cspos[1] == '_')) {
+ ++cspos;
+ if (*cspos == '#') {
+ sprintf(q, "%d", shrink_arg);
+ }
+ else if (*cspos == '%') {
+ if (shrink_arg <= 15)
+ sprintf(q, "%d", (int) (100.0 / shrink_arg + .5));
+ else
+ sprintf(q, "%.2f", 100.0 / shrink_arg);
+ }
+ q += strlen(q);
+ }
+ else
+ *q++ = *cspos;
+ }
+ *q = '\0';
+ if (q > label + len)
+ oops("Internal error computing button labels");
+
+#if !MOTIF
+ command_args[0].value = (XtArgVal) label;
+#else /* MOTIF */
+ command_args[0].value = (XtArgVal) XmCvtCTToXmString(label);
+#endif /* MOTIF */
+ command_args[2].value = (XtArgVal) y_pos;
+ command_call[0].closure = (XtPointer) action;
+ if (++button_number > 99) break; /* if too many buttons */
+ sprintf(name, "button%d", button_number);
+ widget = XtCreateWidget(name, BUTTON_WIDGET_CLASS, panel_widget,
+ command_args, XtNumber(command_args));
+ resize_args[0].value = (XtArgVal) &w;
+ resize_args[1].value = (XtArgVal) &h;
+ XtGetValues(widget, resize_args, 2);
+ if (w > max_button_width) max_button_width = w;
+ y_pos += h + resource.btn_between_spacing
+ + 2 * resource.btn_border_width;
+
+ bp = xmalloc(sizeof *bp);
+ bp->label = label;
+ bp->action = action;
+ bp->widget = widget;
+ *bipp = bp;
+ bipp = &bp->next;
+
+ cspos = index(p1 + 1, '\n');
+ if (cspos == NULL)
+ break;
+ }
+ *bipp = NULL;
+
+ xtra_wid = max_button_width
+ + 2 * (resource.btn_side_spacing + resource.btn_border_width);
+
+ width_arg.value = (XtArgVal) xtra_wid;
+ XtSetValues(panel_widget, &width_arg, 1);
+
+#if !MOTIF
+ ++xtra_wid;
+#endif
+
+ width_arg.value = (XtArgVal) max_button_width;
+ for (bp = b_head; bp != NULL; bp = bp->next) {
+ XtSetValues(bp->widget, &width_arg, 1);
+ XtManageChild(bp->widget);
+ }
+
+#if MOTIF
+ line_args[2].value = (XtArgVal) panel_widget;
+ line_widget = XtCreateManagedWidget("line", widgetClass, form_widget,
+ line_args, XtNumber(line_args));
+ XtVaSetValues(vport_widget, XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, line_widget, NULL);
+#endif
+}
+
+#if XAW
+
+void
+set_button_panel_height(h)
+ XtArgVal h;
+{
+ height_arg.value = h;
+ XtSetValues(line_widget, &height_arg, 1);
+ XtManageChild(line_widget);
+ XtSetValues(panel_widget, &height_arg, 1);
+ XtManageChild(panel_widget);
+ if (panel_cursor == (Cursor) 0)
+ panel_cursor = XCreateFontCursor(DISP, XC_left_ptr);
+ if (XtIsRealized(panel_widget))
+ XDefineCursor(DISP, XtWindow(panel_widget), panel_cursor);
+}
+
+#endif /* MOTIF */
+
+#endif /* BUTTONS */
+
+#else /* not TOOLKIT */
+
+static Window x_bar, y_bar;
+static int x_bgn, x_end, y_bgn, y_end; /* scrollbar positions */
+
+static
+ACTION(Act_null)
+{
+}
+
+#if !GREY
+#define Act_set_greyscaling Act_null
+#endif
+
+#if !COLOR
+#define Act_set_color Act_null
+#endif
+
+#if !PS
+#define Act_set_ps Act_null
+#endif
+
+#if !PS_GS
+#define Act_set_gs_alpha Act_null
+#endif
+
+typedef void (*act_proc) ARGS((XEvent *));
+
+static act_proc actions[128] = {
+ Act_null, Act_null, Act_null, Act_quit, /* NUL, ^A-^C */
+ Act_quit, Act_null, Act_null, Act_null, /* ^D-^G */
+ Act_up_or_previous, Act_null, Act_forward_page,
+ Act_null, /* ^H-^K */
+ Act_redraw, Act_forward_page, Act_null, Act_null, /* ^L-^O */
+ Act_show_display_attributes, Act_null, Act_null,
+ Act_null, /* ^P-^S */
+ Act_null, Act_null, Act_null, Act_null, /* ^T-^W */
+ Act_null, Act_null, Act_null,
+ Act_discard_number, /* ^X-^Z, ESC */
+ Act_null, Act_null, Act_null, Act_null, /* ^{\,],^,_} */
+ Act_down_or_next, Act_null, Act_null, Act_null, /* SP,!,",# */
+ Act_null, Act_null, Act_null, Act_null, /* $,%,&,' */
+ Act_null, Act_null, Act_null, Act_null, /* (,),*,+ */
+ Act_null, Act_minus, Act_null, Act_null, /* ,,-,.,/ */
+ Act_digit, Act_digit, Act_digit, Act_digit, /* 0,1,2,3 */
+ Act_digit, Act_digit, Act_digit, Act_digit, /* 4,5,6,7 */
+ Act_digit, Act_digit, Act_null, Act_null, /* 8,9,:,; */
+ Act_null, Act_null, Act_null, Act_null, /* <,=,>,? */
+ Act_null, Act_null, Act_null, Act_set_color, /* @,A,B,C */
+ Act_null, Act_null, Act_null,
+ Act_set_greyscaling, /* D,E,F,G */
+ Act_null, Act_null, Act_null, Act_null, /* H,I,J,K */
+ Act_null, Act_set_margins, Act_null, Act_null, /* L,M,N,O */
+ Act_declare_page_number, Act_null,
+ Act_reread_dvi_file, Act_set_density, /* P,Q,R,S */
+ Act_null, Act_null, Act_set_gs_alpha, Act_null, /* T,U,V,W */
+ Act_null, Act_null, Act_null, Act_null, /* X,Y,Z,[ */
+ Act_null, Act_null, Act_home, Act_null, /* \,],^,_ */
+ Act_null, Act_null, Act_back_page, Act_center, /* `,a,b,c */
+ Act_down, Act_null, Act_forward_page,
+ Act_goto_page, /* d,e,f,g */
+ Act_null, Act_null, Act_null,
+ Act_set_keep_flag, /* h,i,j,k */
+ Act_left, Act_null, Act_forward_page, Act_null, /* l,m,n,o */
+ Act_back_page, Act_quit, Act_right,
+ Act_set_shrink_factor, /* p,q,r,s */
+ Act_null, Act_up, Act_set_ps, Act_null, /* t,u,v,w */
+ Act_null, Act_null, Act_null, Act_null, /* x,y,z,{ */
+ Act_null, Act_null, Act_null, Act_up_or_previous,/* |,},~,DEL */
+};
+
+#endif /* not TOOLKIT */
+
+/*
+ * Mechanism to keep track of the magnifier window. The problems are,
+ * (a) if the button is released while the window is being drawn, this
+ * could cause an X error if we continue drawing in it after it is
+ * destroyed, and
+ * (b) creating and destroying the window too quickly confuses the window
+ * manager, which is avoided by waiting for an expose event before
+ * destroying it.
+ */
+static short alt_stat; /* 1 = wait for expose, */
+ /* -1 = destroy upon expose */
+
+/*
+ * Data for buffered events.
+ */
+
+#if !FLAKY_SIGPOLL
+static VOLATILE int event_freq = 70;
+#else
+#define event_freq 70
+#endif
+
+static void can_exposures();
+
+#if GREY
+
+#define gamma resource._gamma
+
+extern double pow();
+
+static void
+mask_shifts(mask, pshift1, pshift2)
+ Pixel mask;
+ int *pshift1, *pshift2;
+{
+ int k, l;
+
+ for (k = 0; (mask & 1) == 0; ++k)
+ mask >>= 1;
+ for (l = 0; (mask & 1) == 1; ++l)
+ mask >>= 1;
+ *pshift1 = sizeof(short) * 8 - l;
+ *pshift2 = k;
+}
+
+/*
+ * Try to allocate 4 color planes for 16 colors (for GXor drawing).
+ * Not called if the visual type is TrueColor.
+ * When color specials are active, this is called exactly once.
+ * It is used for the first foreground/background pair displayed in
+ * the document. For other documents, we act as if this call had failed.
+ */
+
+void
+init_plane_masks()
+{
+ Pixel pixel;
+
+ if (copy || plane_masks[0] != 0)
+ return;
+
+ if (XAllocColorCells(DISP, our_colormap, False, plane_masks, 4,
+ &pixel, 1)) {
+ /* Make sure fore_Pixel and back_Pixel are a part of the palette */
+ back_Pixel = pixel;
+ fore_Pixel = pixel | plane_masks[0] | plane_masks[1]
+ | plane_masks[2] | plane_masks[3];
+ if (mane.win != (Window) 0)
+ XSetWindowBackground(DISP, mane.win, back_Pixel);
+ }
+ else {
+ copy = True;
+ WARN(XmDIALOG_WARNING, "\
+Greyscaling is running in copy mode.\n\
+Your display can only display a limited number\n\
+of colors at a time (typically 256), and other\n\
+applications (such as netscape) are using\n\
+many of them.\n\
+\n\
+Running in copy mode will cause overstrike\n\
+characters to appear incorrectly,\n\
+and may result in poor display quality.\n\
+\n\
+See the section ``GREYSCALING AND COLORMAPS''\n\
+in the xdvi manual page for more details.");
+#if !TOOLKIT
+ fflush(stdout); /* useful if called by netscape */
+#endif
+ }
+}
+
+#endif /* GREY */
+
+#if COLOR
+
+/*
+ * Warn about overstrike characters.
+ */
+
+static void
+warn_overstrike()
+{
+ static Boolean warned_already = False;
+
+ if (!warned_already) {
+ warned_already = True;
+ WARN(XmDIALOG_WARNING, "Overstrike characters may be incorrect");
+ }
+}
+
+/*
+ * Insert into list of colors to be freed upon opening new document.
+ */
+
+static void
+color_list_insert(pixel)
+ Pixel pixel;
+{
+ if (color_list_len >= color_list_max) {
+ if (color_list_max == 0)
+ color_list = xmalloc(
+ (color_list_max += 16) * sizeof *color_list);
+ else
+ color_list = xrealloc(color_list,
+ (color_list_max += 16) * sizeof *color_list);
+ }
+ color_list[color_list_len++] = pixel;
+}
+
+
+/*
+ * Warn about colors not being correct.
+ */
+
+static void
+color_warn()
+{
+ if (!color_warned) {
+ color_warned = True;
+ WARN(XmDIALOG_WARNING, "\
+Cannot allocate colormap entry;\n\
+displayed colors are not exact.\n\
+Either this document is using too many\n\
+colors, or some other application is.\n\
+In the latter case, close that\n\
+application and re-read the dvi file.");
+ }
+}
+
+
+/*
+ * Allocate a color and add it to our list of pixels to be returned
+ * upon opening a new document.
+ */
+
+#define SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
+
+static int shift1_r, shift1_g, shift1_b;
+static int shift2_r, shift2_g, shift2_b;
+static Boolean shifts_good = False;
+
+Pixel
+alloc_color(colorp, fallback_pixel)
+ _Xconst struct rgb *colorp;
+ Pixel fallback_pixel;
+{
+ XColor xcol;
+
+ if (our_visual->class == TrueColor) {
+ if (!shifts_good) {
+ mask_shifts(our_visual->red_mask, &shift1_r, &shift2_r);
+ mask_shifts(our_visual->green_mask, &shift1_g, &shift2_g);
+ mask_shifts(our_visual->blue_mask, &shift1_b, &shift2_b);
+ shifts_good = True;
+ }
+ return SHIFTIFY(colorp->r, shift1_r, shift2_r) |
+ SHIFTIFY(colorp->g, shift1_g, shift2_g) |
+ SHIFTIFY(colorp->b, shift1_b, shift2_b);
+ }
+ else {
+ xcol.red = colorp->r;
+ xcol.green = colorp->g;
+ xcol.blue = colorp->b;
+ xcol.flags = DoRed | DoGreen | DoBlue;
+ if (XAllocColor(DISP, our_colormap, &xcol)) {
+ color_list_insert(xcol.pixel);
+ if (debug & DBG_DVI)
+ printf("alloc_color%6d%6d%6d --> %ld\n",
+ xcol.red, xcol.green, xcol.blue, xcol.pixel);
+ return xcol.pixel;
+ }
+ else {
+ if (debug & DBG_DVI)
+ printf("alloc_color%6d%6d%6d --> failed\n",
+ xcol.red, xcol.green, xcol.blue);
+ color_warn();
+ return fallback_pixel;
+ }
+ }
+}
+
+#undef SHIFTIFY
+
+
+/*
+ * Switch colors of GCs, etc. Called when we're about to use a GC.
+ */
+
+#define SetGC(gc, fcn, fg, bg) \
+ { \
+ values.function = fcn; \
+ values.foreground = fg; \
+ values.background = bg; \
+ if (gc != NULL) \
+ XChangeGC(DISP, gc, \
+ GCFunction | GCForeground | GCBackground, &values); \
+ else \
+ gc = XCreateGC(DISP, XtWindow(top_level), \
+ GCFunction | GCForeground | GCBackground, &values); \
+ }
+
+void
+do_color_change()
+{
+ static int shrink_allocated_for = 0;
+ static GC foreGC2_bak = NULL;
+ XGCValues values;
+ Pixel set_bits;
+ Pixel clr_bits;
+
+#if GREY
+ if (use_grey) {
+
+ if (our_visual->class == TrueColor) {
+ if (!fg_current->pixel_good) {
+ fg_current->pixel = alloc_color(&fg_current->color,
+ fore_color_data.pixel);
+ fg_current->pixel_good = True;
+ }
+
+ set_bits = fg_current->pixel & ~bg_current->pixel;
+ clr_bits = bg_current->pixel & ~fg_current->pixel;
+
+ if (set_bits & our_visual->red_mask)
+ set_bits |= our_visual->red_mask;
+ if (clr_bits & our_visual->red_mask)
+ clr_bits |= our_visual->red_mask;
+ if (set_bits & our_visual->green_mask)
+ set_bits |= our_visual->green_mask;
+ if (clr_bits & our_visual->green_mask)
+ clr_bits |= our_visual->green_mask;
+ if (set_bits & our_visual->blue_mask)
+ set_bits |= our_visual->blue_mask;
+ if (clr_bits & our_visual->blue_mask)
+ clr_bits |= our_visual->blue_mask;
+
+ /*
+ * Make the GCs
+ */
+
+ SetGC(ruleGC, GXcopy, fg_current->pixel, bg_current->pixel);
+ foreGC2 = NULL;
+
+ if (resource.copy
+ || (set_bits && clr_bits && !resource.thorough)) {
+ if (!resource.copy)
+ warn_overstrike();
+ SetGC(foreGC, GXcopy, fg_current->pixel, bg_current->pixel);
+ }
+ else {
+ if (set_bits) {
+ SetGC(foreGC, GXor, fg_current->pixel & set_bits, 0);
+ if (clr_bits) {
+ SetGC(foreGC2_bak, GXandInverted,
+ ~fg_current->pixel & clr_bits, 0);
+ foreGC2 = foreGC2_bak;
+ }
+ }
+ else
+ SetGC(foreGC, GXandInverted,
+ ~fg_current->pixel & clr_bits, 0);
+ }
+
+ if (debug & DBG_DVI)
+ printf(
+ "do_color_change: fg = %lx, bg = %lx, with%s foreGC2\n",
+ fg_current->pixel, bg_current->pixel,
+ foreGC2 == NULL ? "out" : "");
+
+ if (mane.shrinkfactor > 1) {
+ int i;
+ unsigned int sf_squared;
+
+ sf_squared = mane.shrinkfactor * mane.shrinkfactor;
+
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL) {
+ free((char *) pixeltbl);
+ if (pixeltbl_t != NULL) {
+ free((char *) pixeltbl_t);
+ pixeltbl_t = NULL;
+ }
+ }
+ pixeltbl = xmalloc((sf_squared + 1) * sizeof(Pixel));
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+ if (foreGC2 != NULL && pixeltbl_t == NULL)
+ /* Can't use sf_squared (or mane.shrinkfactor) here */
+ pixeltbl_t = xmalloc((shrink_allocated_for
+ * shrink_allocated_for + 1) * sizeof(Pixel));
+
+ /*
+ * Compute pixel values directly.
+ */
+
+#define SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
+
+ for (i = 0; i <= sf_squared; ++i) {
+ double frac = gamma > 0
+ ? pow((double) i / sf_squared, 1 / gamma)
+ : 1 - pow((double) (sf_squared - i) / sf_squared,
+ -gamma);
+ unsigned int red, green, blue;
+ Pixel pixel;
+
+ red = frac
+ * ((double) fg_current->color.r - bg_current->color.r)
+ + bg_current->color.r;
+ green = frac
+ * ((double) fg_current->color.g - bg_current->color.g)
+ + bg_current->color.g;
+ blue = frac
+ * ((double) fg_current->color.b - bg_current->color.b)
+ + bg_current->color.b;
+
+ pixel = SHIFTIFY(red, shift1_r, shift2_r) |
+ SHIFTIFY(green, shift1_g, shift2_g) |
+ SHIFTIFY(blue, shift1_b, shift2_b);
+
+ if (foreGC2 != NULL) { /* if thorough */
+ pixeltbl[i] = pixel & ~bg_current->pixel;
+ pixeltbl_t[i] = ~pixel & bg_current->pixel;
+ }
+ else if (resource.copy || (set_bits && clr_bits))
+ pixeltbl[i] = pixel;
+ else
+ pixeltbl[i] = set_bits ? pixel & set_bits
+ : ~pixel & clr_bits;
+ }
+
+#undef SHIFTIFY
+ }
+
+ }
+
+ else { /* not TrueColor */
+ int i;
+ Boolean using_planes;
+
+ using_planes = (fg_current == bg_head->fg_head && !copy);
+ if (!fg_current->palette_good) {
+ XColor color;
+
+ for (i = 0; i < 16; ++i) {
+ double frac;
+
+ frac = gamma > 0 ? pow((double) i / 15, 1 / gamma)
+ : 1 - pow((double) (15 - i) / 15, -gamma);
+ color.red = frac
+ * ((double) fg_current->color.r - bg_current->color.r)
+ + bg_current->color.r;
+ color.green = frac
+ * ((double) fg_current->color.g - bg_current->color.g)
+ + bg_current->color.g;
+ color.blue = frac
+ * ((double) fg_current->color.b - bg_current->color.b)
+ + bg_current->color.b;
+
+ color.flags = DoRed | DoGreen | DoBlue;
+
+ if (using_planes) {
+ color.pixel = back_Pixel; /* start of block */
+ if (i & 1) color.pixel |= plane_masks[0];
+ if (i & 2) color.pixel |= plane_masks[1];
+ if (i & 4) color.pixel |= plane_masks[2];
+ if (i & 8) color.pixel |= plane_masks[3];
+ XStoreColor(DISP, our_colormap, &color);
+ fg_current->palette[i] = color.pixel;
+ }
+ else {
+ if (XAllocColor(DISP, our_colormap, &color)) {
+ fg_current->palette[i] = color.pixel;
+ color_list_insert(color.pixel);
+ }
+ else {
+ color_warn();
+ fg_current->palette[i] =
+ (i * 100 >= density * 15)
+ ? fore_Pixel : bg_current->pixel;
+ }
+ }
+ }
+
+ if (using_planes && bg_current->pixel != back_Pixel) {
+ bg_current->pixel = back_Pixel;
+ XSetWindowBackground(DISP, mane.win, bg_current->pixel);
+ XClearWindow(DISP, mane.win);
+ }
+
+ fg_current->palette_good = True;
+ }
+
+ if (debug & DBG_DVI)
+ printf("do_color_change: fg = %ld, bg = %ld, using_planes = %d\n",
+ fg_current->palette[15], bg_current->pixel, using_planes);
+
+ if (using_planes) {
+ SetGC(ruleGC, GXor, fg_current->palette[15],
+ bg_current->pixel);
+ SetGC(foreGC, GXor, fg_current->palette[15],
+ bg_current->pixel);
+ }
+ else {
+ SetGC(ruleGC, GXcopy, fg_current->palette[15],
+ bg_current->pixel);
+ SetGC(foreGC, GXcopy, fg_current->palette[15],
+ bg_current->pixel);
+ }
+
+ foreGC2 = NULL;
+
+ if (mane.shrinkfactor > 1) {
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL) free((char *) pixeltbl);
+ pixeltbl = xmalloc((unsigned)
+ (mane.shrinkfactor * mane.shrinkfactor + 1)
+ * sizeof *pixeltbl);
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+
+ for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i)
+ pixeltbl[i] = fg_current->palette[
+ (i * 30 + mane.shrinkfactor * mane.shrinkfactor)
+ / (2 * mane.shrinkfactor * mane.shrinkfactor)];
+ }
+ }
+
+ } /* end if use_grey */
+ else
+
+#endif /* GREY */
+
+ {
+ static GC foreGC2_bak = NULL;
+
+ if (!fg_current->pixel_good) {
+ fg_current->pixel = alloc_color(&fg_current->color,
+ fore_color_data.pixel);
+ fg_current->pixel_good = True;
+ }
+
+ if (debug & DBG_DVI)
+ printf("do_color_change: fg = %lx, bg = %lx\n",
+ fg_current->pixel, bg_current->pixel);
+
+ SetGC(ruleGC, GXcopy, fg_current->pixel, bg_current->pixel);
+
+ set_bits = (Pixel) (fg_current->pixel & ~bg_current->pixel);
+ clr_bits = (Pixel) (bg_current->pixel & ~fg_current->pixel);
+ foreGC2 = NULL;
+
+ if (resource.copy
+ || (set_bits && clr_bits && !resource.thorough)) {
+ if (!resource.copy)
+ warn_overstrike();
+ SetGC(foreGC, GXcopy, fg_current->pixel, bg_current->pixel);
+ }
+ else {
+ if (set_bits) {
+ SetGC(foreGC, GXor, set_bits, 0);
+ if (clr_bits) {
+ SetGC(foreGC2_bak, GXandInverted, clr_bits, 0);
+ foreGC2 = foreGC2_bak;
+ }
+ }
+ else
+ SetGC(foreGC, GXandInverted, clr_bits, 0);
+ }
+ }
+
+ fg_active = fg_current;
+}
+
+#undef SetGC
+
+#elif GREY /* endif COLOR */
+
+#define MakeGC(fcn, fg, bg) (values.function = fcn, \
+ values.foreground=fg, values.background=bg, \
+ XCreateGC(DISP, XtWindow(top_level), \
+ GCFunction | GCForeground | GCBackground, &values))
+
+void
+init_pix()
+{
+ static int shrink_allocated_for = 0;
+ static float oldgamma = 0.0;
+ static Pixel palette[17];
+ XGCValues values;
+ int i;
+
+ if (our_visual->class == TrueColor) {
+ /* This mirrors the non-grey code in xdvi.c */
+ static int shift1_r, shift1_g, shift1_b;
+ static int shift2_r, shift2_g, shift2_b;
+ static Pixel set_bits;
+ static Pixel clr_bits;
+ unsigned int sf_squared;
+
+ if (oldgamma == 0.0) {
+ mask_shifts(our_visual->red_mask, &shift1_r, &shift2_r);
+ mask_shifts(our_visual->green_mask, &shift1_g, &shift2_g);
+ mask_shifts(our_visual->blue_mask, &shift1_b, &shift2_b);
+
+ set_bits = fore_color_data.pixel & ~back_color_data.pixel;
+ clr_bits = back_color_data.pixel & ~fore_color_data.pixel;
+
+ if (set_bits & our_visual->red_mask)
+ set_bits |= our_visual->red_mask;
+ if (clr_bits & our_visual->red_mask)
+ clr_bits |= our_visual->red_mask;
+ if (set_bits & our_visual->green_mask)
+ set_bits |= our_visual->green_mask;
+ if (clr_bits & our_visual->green_mask)
+ clr_bits |= our_visual->green_mask;
+ if (set_bits & our_visual->blue_mask)
+ set_bits |= our_visual->blue_mask;
+ if (clr_bits & our_visual->blue_mask)
+ clr_bits |= our_visual->blue_mask;
+
+ /*
+ * Make the GCs
+ */
+
+ foreGC = foreGC2 = ruleGC = 0;
+ copyGC = MakeGC(GXcopy, fore_Pixel, back_Pixel);
+ if (copy || (set_bits && clr_bits)) {
+ ruleGC = copyGC;
+ if (!resource.thorough) copy = True;
+ }
+ if (copy) {
+ foreGC = ruleGC;
+ if (!resource.copy)
+ WARN(XmDIALOG_WARNING,
+ "Overstrike characters may be incorrect");
+ }
+ else {
+ if (set_bits)
+ foreGC = MakeGC(GXor,
+ set_bits & fore_color_data.pixel, 0);
+ if (clr_bits || !set_bits)
+ *(foreGC ? &foreGC2 : &foreGC) = MakeGC(GXandInverted,
+ clr_bits & ~fore_color_data.pixel, 0);
+ if (!ruleGC) ruleGC = foreGC;
+ }
+
+ oldgamma = gamma;
+ }
+
+ if (mane.shrinkfactor == 1) return;
+ sf_squared = mane.shrinkfactor * mane.shrinkfactor;
+
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL) {
+ free((char *) pixeltbl);
+ if (pixeltbl_t != NULL)
+ free((char *) pixeltbl_t);
+ }
+ pixeltbl = xmalloc((sf_squared + 1) * sizeof(Pixel));
+ if (foreGC2 != NULL)
+ pixeltbl_t = xmalloc((sf_squared + 1) * sizeof(Pixel));
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+
+ /*
+ * Compute pixel values directly.
+ */
+
+#define SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
+
+ for (i = 0; i <= sf_squared; ++i) {
+ double frac = gamma > 0
+ ? pow((double) i / sf_squared, 1 / gamma)
+ : 1 - pow((double) (sf_squared - i) / sf_squared, -gamma);
+ unsigned int red, green, blue;
+ Pixel pixel;
+
+ red = frac
+ * ((double) fore_color_data.red - back_color_data.red)
+ + back_color_data.red;
+ green = frac
+ * ((double) fore_color_data.green - back_color_data.green)
+ + back_color_data.green;
+ blue = frac
+ * ((double) fore_color_data.blue - back_color_data.blue)
+ + back_color_data.blue;
+
+ pixel = SHIFTIFY(red, shift1_r, shift2_r) |
+ SHIFTIFY(green, shift1_g, shift2_g) |
+ SHIFTIFY(blue, shift1_b, shift2_b);
+
+ if (copy) pixeltbl[i] = pixel;
+ else if (foreGC2 != NULL) { /* if thorough */
+ pixeltbl[i] = pixel & ~back_color_data.pixel;
+ pixeltbl_t[i] = ~pixel & back_color_data.pixel;
+ }
+ else
+ pixeltbl[i] = set_bits ? pixel & set_bits
+ : ~pixel & clr_bits;
+ }
+
+#undef SHIFTIFY
+
+ return;
+ }
+
+ /* if not TrueColor ... */
+
+ if (gamma != oldgamma) {
+ XColor color;
+
+ for (i = 0; i < 16; ++i) {
+ double frac = gamma > 0 ? pow((double) i / 15, 1 / gamma)
+ : 1 - pow((double) (15 - i) / 15, -gamma);
+
+ color.red = frac
+ * ((double) fore_color_data.red - back_color_data.red)
+ + back_color_data.red;
+ color.green = frac
+ * ((double) fore_color_data.green - back_color_data.green)
+ + back_color_data.green;
+ color.blue = frac
+ * ((double) fore_color_data.blue - back_color_data.blue)
+ + back_color_data.blue;
+
+ color.pixel = back_Pixel;
+ color.flags = DoRed | DoGreen | DoBlue;
+
+ if (!copy) {
+ if (i & 1) color.pixel |= plane_masks[0];
+ if (i & 2) color.pixel |= plane_masks[1];
+ if (i & 4) color.pixel |= plane_masks[2];
+ if (i & 8) color.pixel |= plane_masks[3];
+ XStoreColor(DISP, our_colormap, &color);
+ palette[i] = color.pixel;
+ }
+ else {
+ if (XAllocColor(DISP, our_colormap, &color))
+ palette[i] = color.pixel;
+ else
+ palette[i] = (i * 100 >= density * 15)
+ ? fore_Pixel : back_Pixel;
+ }
+ }
+
+ copyGC = MakeGC(GXcopy, fore_Pixel, back_Pixel);
+ foreGC = ruleGC = copy ? copyGC
+ : MakeGC(GXor, fore_Pixel, back_Pixel);
+ foreGC2 = NULL;
+
+ oldgamma = gamma;
+ }
+
+ if (mane.shrinkfactor == 1) return;
+
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL) free((char *) pixeltbl);
+ pixeltbl = xmalloc((unsigned)
+ (mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof(Pixel));
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+
+ for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i)
+ pixeltbl[i] =
+ palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
+ / (2 * mane.shrinkfactor * mane.shrinkfactor)];
+}
+
+#undef MakeGC
+
+#endif /* GREY */
+
+/*
+ * Event-handling routines
+ */
+
+void
+expose(windowrec, x, y, w, h)
+ struct WindowRec *windowrec;
+ int x, y;
+ unsigned int w, h;
+{
+ if (windowrec->min_x > x) windowrec->min_x = x;
+ if (windowrec->max_x < x + w)
+ windowrec->max_x = x + w;
+ if (windowrec->min_y > y) windowrec->min_y = y;
+ if (windowrec->max_y < y + h)
+ windowrec->max_y = y + h;
+ ev_flags |= EV_EXPOSE;
+}
+
+static void
+clearexpose(windowrec, x, y, w, h)
+ struct WindowRec *windowrec;
+ int x, y;
+ unsigned int w, h;
+{
+ XClearArea(DISP, windowrec->win, x, y, w, h, False);
+ expose(windowrec, x, y, w, h);
+}
+
+static void
+scrollwindow(windowrec, x0, y0)
+ struct WindowRec *windowrec;
+ int x0, y0;
+{
+ int x, y;
+ int x2 = 0, y2 = 0;
+ int ww, hh;
+
+ x = x0 - windowrec->base_x;
+ y = y0 - windowrec->base_y;
+ ww = windowrec->width - x;
+ hh = windowrec->height - y;
+ windowrec->base_x = x0;
+ windowrec->base_y = y0;
+ if (currwin.win == windowrec->win) {
+ currwin.base_x = x0;
+ currwin.base_y = y0;
+ }
+ windowrec->min_x -= x;
+ if (windowrec->min_x < 0) windowrec->min_x = 0;
+ windowrec->max_x -= x;
+ if (windowrec->max_x > windowrec->width)
+ windowrec->max_x = windowrec->width;
+ windowrec->min_y -= y;
+ if (windowrec->min_y < 0) windowrec->min_y = 0;
+ windowrec->max_y -= y;
+ if (windowrec->max_y > windowrec->height)
+ windowrec->max_y = windowrec->height;
+ if (x < 0) {
+ x2 = -x;
+ x = 0;
+ ww = windowrec->width - x2;
+ }
+ if (y < 0) {
+ y2 = -y;
+ y = 0;
+ hh = windowrec->height - y2;
+ }
+ if (ww <= 0 || hh <= 0) {
+ XClearWindow(DISP, windowrec->win);
+ windowrec->min_x = windowrec->min_y = 0;
+ windowrec->max_x = windowrec->width;
+ windowrec->max_y = windowrec->height;
+ }
+ else {
+ XCopyArea(DISP, windowrec->win, windowrec->win, copyGC,
+ x, y, (unsigned int) ww, (unsigned int) hh, x2, y2);
+ if (x > 0)
+ clearexpose(windowrec, ww, 0,
+ (unsigned int) x, windowrec->height);
+ if (x2 > 0)
+ clearexpose(windowrec, 0, 0,
+ (unsigned int) x2, windowrec->height);
+ if (y > 0)
+ clearexpose(windowrec, 0, hh,
+ windowrec->width, (unsigned int) y);
+ if (y2 > 0)
+ clearexpose(windowrec, 0, 0,
+ windowrec->width, (unsigned int) y2);
+ }
+}
+
+#ifdef TOOLKIT
+
+/*
+ * routines for X11 toolkit
+ */
+
+static Arg arg_wh[] = {
+ {XtNwidth, (XtArgVal) &window_w},
+ {XtNheight, (XtArgVal) &window_h},
+};
+
+static Position window_x, window_y;
+static Arg arg_xy[] = {
+ {XtNx, (XtArgVal) &window_x},
+ {XtNy, (XtArgVal) &window_y},
+};
+
+#define get_xy() XtGetValues(draw_widget, arg_xy, XtNumber(arg_xy))
+
+#define mane_base_x 0
+#define mane_base_y 0
+
+
+#ifdef MOTIF
+
+static int
+set_bar_value(bar, value, max)
+ Widget bar;
+ int value;
+ int max;
+{
+ XmScrollBarCallbackStruct call_data;
+
+ if (value > max) value = max;
+ if (value < 0) value = 0;
+ call_data.value = value;
+ XtVaSetValues(bar, XmNvalue, value, NULL);
+ XtCallCallbacks(bar, XmNvalueChangedCallback, &call_data);
+ return value;
+}
+
+#endif /* MOTIF */
+
+
+void
+home(scrl)
+ wide_bool scrl;
+{
+ if (!scrl) XUnmapWindow(DISP, mane.win);
+#ifndef MOTIF
+ get_xy();
+ if (x_bar != NULL) {
+ int coord = (page_w - clip_w) / 2;
+
+ if (coord > home_x / mane.shrinkfactor)
+ coord = home_x / mane.shrinkfactor;
+ XtCallCallbacks(x_bar, XtNscrollProc,
+ (XtPointer) (ptrdiff_t) (window_x + coord));
+ }
+ if (y_bar != NULL) {
+ int coord = (page_h - clip_h) / 2;
+
+ if (coord > home_y / mane.shrinkfactor)
+ coord = home_y / mane.shrinkfactor;
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (ptrdiff_t) (window_y + coord));
+ }
+#else /* MOTIF */
+ {
+ int value;
+
+ value = (page_w - clip_w) / 2;
+ if (value > home_x / mane.shrinkfactor)
+ value = home_x / mane.shrinkfactor;
+ (void) set_bar_value(x_bar, value, (int) (page_w - clip_w));
+
+ value = (page_h - clip_h) / 2;
+ if (value > home_y / mane.shrinkfactor)
+ value = home_y / mane.shrinkfactor;
+ (void) set_bar_value(y_bar, value, (int) (page_h - clip_h));
+ }
+#endif /* MOTIF */
+ if (!scrl) {
+ XMapWindow(DISP, mane.win);
+ /* Wait for the server to catch up---this eliminates flicker. */
+ XSync(DISP, False);
+ }
+}
+
+/*
+ * Same as home(), except move to the bottom of the page.
+ */
+
+static void
+home_bottom P1C(wide_bool, scrl)
+{
+ XUnmapWindow(DISP, mane.win);
+#if XAW
+ get_xy();
+ if (x_bar != NULL) {
+ int coord = (page_w - clip_w) / 2;
+
+ if (coord > home_x / mane.shrinkfactor)
+ coord = home_x / mane.shrinkfactor;
+ XtCallCallbacks(x_bar, XtNscrollProc,
+ (XtPointer) (ptrdiff_t) (window_x + coord));
+ }
+ if (y_bar != NULL)
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (ptrdiff_t) (window_y + (page_h - clip_h)));
+#else /* if MOTIF */
+ {
+ int value;
+
+ value = (page_w - clip_w) / 2;
+ if (value > home_x / mane.shrinkfactor)
+ value = home_x / mane.shrinkfactor;
+ (void) set_bar_value(x_bar, value, (int) (page_w - clip_w));
+
+ (void) set_bar_value(y_bar, (int) (page_h - clip_h),
+ (int) (page_h - clip_h));
+ }
+#endif /* MOTIF */
+ XMapWindow(DISP, mane.win);
+ /* Wait for the server to catch up---this eliminates flicker. */
+ XSync(DISP, False);
+}
+
+
+#ifndef MOTIF
+ /*ARGSUSED*/
+static void
+handle_destroy_bar(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ * (Widget *) client_data = NULL;
+}
+#endif
+
+
+static Boolean resized = False;
+
+static void
+get_geom()
+{
+ static Dimension new_clip_w, new_clip_h;
+ static Arg arg_wh_clip[] = {
+ {XtNwidth, (XtArgVal) &new_clip_w},
+ {XtNheight, (XtArgVal) &new_clip_h},
+ };
+ int old_clip_w;
+
+ XtGetValues(vport_widget, arg_wh, XtNumber(arg_wh));
+ XtGetValues(clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
+#ifndef MOTIF
+ /* Note: widgets may be destroyed but not forgotten */
+ if (x_bar == NULL) {
+ x_bar = XtNameToWidget(vport_widget, "horizontal");
+ if (x_bar != NULL)
+ XtAddCallback(x_bar, XtNdestroyCallback, handle_destroy_bar,
+ (XtPointer) &x_bar);
+ }
+ if (y_bar == NULL) {
+ y_bar = XtNameToWidget(vport_widget, "vertical");
+ if (y_bar != NULL)
+ XtAddCallback(y_bar, XtNdestroyCallback, handle_destroy_bar,
+ (XtPointer) &y_bar);
+ }
+#endif
+ old_clip_w = clip_w;
+ /* we need to do this because */
+ /* sizeof(Dimension) != sizeof(int) */
+ clip_w = new_clip_w;
+ clip_h = new_clip_h;
+ if (old_clip_w == 0) ev_flags |= EV_NEWPAGE;
+ resized = False;
+}
+
+/*
+ * callback routines
+ */
+
+ /*ARGSUSED*/
+void
+handle_resize(widget, junk, event, cont)
+ Widget widget;
+ XtPointer junk;
+ XEvent *event;
+ Boolean *cont; /* unused */
+{
+ resized = True;
+}
+
+#ifdef BUTTONS
+ /*ARGSUSED*/
+static void
+handle_command(widget, client_data, call_data)
+ Widget widget;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ struct xdvi_action *actp;
+
+ for (actp = (struct xdvi_action *) client_data;
+ actp != NULL;
+ actp = actp->next)
+ (actp->proc)(widget, NULL, &actp->param, &actp->num_params);
+}
+
+ /*ARGSUSED*/
+static void
+handle_destroy_buttons(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (--destroy_count != 0) return;
+#ifndef MOTIF
+ XtSetValues(vport_widget, resizable_on, XtNumber(resizable_on));
+ if (resource.expert) {
+ /* destroy buttons */
+ XtGetValues(form_widget, arg_wh, XtNumber(arg_wh));
+ XdviResizeWidget(vport_widget, window_w, window_h);
+ }
+ else {
+ create_buttons(); /* this determines xtra_wid */
+ XdviResizeWidget(vport_widget, window_w -= xtra_wid, window_h);
+ set_button_panel_height((XtArgVal) window_h);
+ }
+#else /* MOTIF */
+ if (resource.expert)
+ XtVaSetValues(vport_widget,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ else {
+ create_buttons();
+ window_w -= xtra_wid;
+ }
+#endif /* MOTIF */
+}
+#endif /* BUTTONS */
+
+void
+reconfig()
+{
+#if BUTTONS && !MOTIF
+ XtSetValues(vport_widget, resizable_off, XtNumber(resizable_off));
+#endif
+ XdviResizeWidget(draw_widget, page_w, page_h);
+ get_geom();
+}
+
+#else /* not TOOLKIT */
+
+/*
+ * brute force scrollbar routines
+ */
+
+static void
+paint_x_bar()
+{
+ int new_x_bgn = mane.base_x * clip_w / page_w;
+ int new_x_end = (mane.base_x + clip_w) * clip_w / page_w;
+
+ if (new_x_bgn >= x_end || x_bgn >= new_x_end) { /* no overlap */
+ XClearArea(DISP, x_bar, x_bgn, 1, x_end - x_bgn, BAR_WID, False);
+ XFillRectangle(DISP, x_bar, copyGC,
+ new_x_bgn, 1, new_x_end - new_x_bgn, BAR_WID);
+ }
+ else { /* this stuff avoids flicker */
+ if (x_bgn < new_x_bgn)
+ XClearArea(DISP, x_bar, x_bgn, 1, new_x_bgn - x_bgn,
+ BAR_WID, False);
+ else
+ XFillRectangle(DISP, x_bar, copyGC,
+ new_x_bgn, 1, x_bgn - new_x_bgn, BAR_WID);
+ if (new_x_end < x_end)
+ XClearArea(DISP, x_bar, new_x_end, 1, x_end - new_x_end,
+ BAR_WID, False);
+ else
+ XFillRectangle(DISP, x_bar, copyGC,
+ x_end, 1, new_x_end - x_end, BAR_WID);
+ }
+ x_bgn = new_x_bgn;
+ x_end = new_x_end;
+}
+
+static void
+paint_y_bar()
+{
+ int new_y_bgn = mane.base_y * clip_h / page_h;
+ int new_y_end = (mane.base_y + clip_h) * clip_h / page_h;
+
+ if (new_y_bgn >= y_end || y_bgn >= new_y_end) { /* no overlap */
+ XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, y_end - y_bgn, False);
+ XFillRectangle(DISP, y_bar, copyGC,
+ 1, new_y_bgn, BAR_WID, new_y_end - new_y_bgn);
+ }
+ else { /* this stuff avoids flicker */
+ if (y_bgn < new_y_bgn)
+ XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, new_y_bgn - y_bgn,
+ False);
+ else
+ XFillRectangle(DISP, y_bar, copyGC,
+ 1, new_y_bgn, BAR_WID, y_bgn - new_y_bgn);
+ if (new_y_end < y_end)
+ XClearArea(DISP, y_bar, 1, new_y_end,
+ BAR_WID, y_end - new_y_end, False);
+ else
+ XFillRectangle(DISP, y_bar, copyGC,
+ 1, y_end, BAR_WID, new_y_end - y_end);
+ }
+ y_bgn = new_y_bgn;
+ y_end = new_y_end;
+}
+
+static void
+scrollmane(x, y)
+ int x, y;
+{
+ int old_base_x = mane.base_x;
+ int old_base_y = mane.base_y;
+
+ if (x > (int) (page_w - clip_w)) x = page_w - clip_w;
+ if (x < 0) x = 0;
+ if (y > (int) (page_h - clip_h)) y = page_h - clip_h;
+ if (y < 0) y = 0;
+ scrollwindow(&mane, x, y);
+ if (old_base_x != mane.base_x && x_bar) paint_x_bar();
+ if (old_base_y != mane.base_y && y_bar) paint_y_bar();
+}
+
+void
+reconfig()
+{
+ int x_thick = 0;
+ int y_thick = 0;
+
+ /* determine existence of scrollbars */
+ if (window_w < page_w) x_thick = BAR_THICK;
+ if (window_h - x_thick < page_h) y_thick = BAR_THICK;
+ clip_w = window_w - y_thick;
+ if (clip_w < page_w) x_thick = BAR_THICK;
+ clip_h = window_h - x_thick;
+
+ /* process drawing (clip) window */
+ if (mane.win == (Window) 0) { /* initial creation */
+ XWindowAttributes attrs;
+
+ mane.win = XCreateSimpleWindow(DISP, top_level, y_thick, x_thick,
+ (unsigned int) clip_w, (unsigned int) clip_h, 0,
+ brdr_Pixel, back_Pixel);
+ XSelectInput(DISP, mane.win, ExposureMask |
+ ButtonPressMask | ButtonMotionMask | ButtonReleaseMask);
+ (void) XGetWindowAttributes(DISP, mane.win, &attrs);
+ backing_store = attrs.backing_store;
+ XMapWindow(DISP, mane.win);
+ }
+ else
+ XMoveResizeWindow(DISP, mane.win, y_thick, x_thick, clip_w, clip_h);
+
+ /* process scroll bars */
+ if (x_thick) {
+ if (x_bar) {
+ XMoveResizeWindow(DISP, x_bar,
+ y_thick - 1, -1, clip_w, BAR_THICK - 1);
+ paint_x_bar();
+ }
+ else {
+ x_bar = XCreateSimpleWindow(DISP, top_level, y_thick - 1, -1,
+ (unsigned int) clip_w, BAR_THICK - 1, 1,
+ brdr_Pixel, back_Pixel);
+ XSelectInput(DISP, x_bar,
+ ExposureMask | ButtonPressMask | Button2MotionMask);
+ XMapWindow(DISP, x_bar);
+ }
+ x_bgn = mane.base_x * clip_w / page_w;
+ x_end = (mane.base_x + clip_w) * clip_w / page_w;
+ }
+ else
+ if (x_bar) {
+ XDestroyWindow(DISP, x_bar);
+ x_bar = (Window) 0;
+ }
+
+ if (y_thick) {
+ if (y_bar) {
+ XMoveResizeWindow(DISP, y_bar,
+ -1, x_thick - 1, BAR_THICK - 1, clip_h);
+ paint_y_bar();
+ }
+ else {
+ y_bar = XCreateSimpleWindow(DISP, top_level, -1, x_thick - 1,
+ BAR_THICK - 1, (unsigned int) clip_h, 1,
+ brdr_Pixel, back_Pixel);
+ XSelectInput(DISP, y_bar,
+ ExposureMask | ButtonPressMask | Button2MotionMask);
+ XMapWindow(DISP, y_bar);
+ }
+ y_bgn = mane.base_y * clip_h / page_h;
+ y_end = (mane.base_y + clip_h) * clip_h / page_h;
+ }
+ else
+ if (y_bar) {
+ XDestroyWindow(DISP, y_bar);
+ y_bar = (Window) 0;
+ }
+}
+
+void
+home(scrl)
+ wide_bool scrl;
+{
+ int x = 0, y = 0;
+
+ if (page_w > clip_w) {
+ x = (page_w - clip_w) / 2;
+ if (x > home_x / mane.shrinkfactor)
+ x = home_x / mane.shrinkfactor;
+ }
+ if (page_h > clip_h) {
+ y = (page_h - clip_h) / 2;
+ if (y > home_y / mane.shrinkfactor)
+ y = home_y / mane.shrinkfactor;
+ }
+ if (scrl)
+ scrollmane(x, y);
+ else {
+ mane.base_x = x;
+ mane.base_y = y;
+ if (currwin.win == mane.win) {
+ currwin.base_x = x;
+ currwin.base_y = y;
+ }
+ if (x_bar) paint_x_bar();
+ if (y_bar) paint_y_bar();
+ }
+}
+
+/*
+ * Same as home(), except move to the bottom of the page.
+ */
+
+static void
+home_bottom P1C(wide_bool, scrl)
+{
+ int x = 0, y = 0;
+
+ if (page_w > clip_w) {
+ x = (page_w - clip_w) / 2;
+ if (x > home_x / mane.shrinkfactor)
+ x = home_x / mane.shrinkfactor;
+ }
+ if (page_h > clip_h)
+ y = page_h - clip_h;
+ mane.base_x = x;
+ mane.base_y = y;
+ if (currwin.win == mane.win) {
+ currwin.base_x = x;
+ currwin.base_y = y;
+ }
+ if (x_bar) paint_x_bar();
+ if (y_bar) paint_y_bar();
+}
+
+#define get_xy()
+#define window_x 0
+#define window_y 0
+#define mane_base_x mane.base_x
+#define mane_base_y mane.base_y
+#endif /* not TOOLKIT */
+
+
+/*
+ * goto_page is the only place where current_page should be set,
+ * other than when reading a new dvi file.
+ */
+
+static home_proc home_action = home;
+
+void
+goto_page(n, proc)
+ int n;
+ home_proc proc;
+{
+ current_page = n;
+ home_action = proc;
+ warn_spec_now = warn_spec;
+}
+
+
+#if MOTIF
+
+struct pd_act {
+ XtActionProc proc;
+ Cardinal num_params;
+ String param;
+};
+
+static void
+do_pulldown_action(actp)
+ struct pd_act *actp;
+{
+ (actp->proc)(/* widget */ NULL, NULL, &actp->param, &actp->num_params);
+}
+
+static struct pd_act file_pulldown_actions[] = {
+ {Act_open_dvi_file, 0, NULL},
+ {Act_reread_dvi_file, 0, NULL},
+ {Act_print, 0, NULL},
+ {Act_quit, 0, NULL}};
+
+/* ARGSUSED */
+void
+file_pulldown_callback(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ do_pulldown_action(file_pulldown_actions + (ptrdiff_t) client_data);
+}
+
+static struct pd_act navigate_pulldown_actions[] = {
+ {Act_back_page, 1, "10"},
+ {Act_back_page, 1, "5"},
+ {Act_back_page, 0, NULL},
+ {Act_forward_page, 0, NULL},
+ {Act_forward_page, 1, "5"},
+ {Act_forward_page, 1, "10"}};
+
+/* ARGSUSED */
+void
+navigate_pulldown_callback(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ do_pulldown_action(navigate_pulldown_actions + (ptrdiff_t) client_data);
+}
+
+
+static struct pd_act scale_pulldown_actions[] = {
+ {Act_set_shrink_factor, 1, "1"},
+ {Act_set_shrink_factor, 1, "2"},
+ {Act_set_shrink_factor, 1, "3"},
+ {Act_set_shrink_factor, 1, "4"}};
+
+/* ARGSUSED */
+void
+scale_pulldown_callback(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ do_pulldown_action(scale_pulldown_actions + (ptrdiff_t) client_data);
+}
+
+void
+set_shrink_factor(shrink)
+ int shrink;
+{
+ static Widget active_shrink_button = NULL;
+ Widget new_shrink_button;
+
+ mane.shrinkfactor = shrink;
+ new_shrink_button = (shrink > 0 && shrink <= XtNumber(shrink_button)
+ ? shrink_button[shrink - 1] : NULL);
+ if (new_shrink_button != active_shrink_button) {
+ if (active_shrink_button != NULL)
+ XmToggleButtonSetState(active_shrink_button, False, False);
+ if (new_shrink_button != NULL)
+ XmToggleButtonSetState(new_shrink_button, True, False);
+ active_shrink_button = new_shrink_button;
+ }
+}
+
+static unsigned int ungrab_serial = 0;
+
+/* ARGSUSED */
+void
+popdown_callback(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ /* Lesstif gives call_data == NULL */
+ if (call_data != NULL && *((XtGrabKind *) call_data) != XtGrabNone)
+ ungrab_serial = LastKnownRequestProcessed(DISP);
+}
+
+#endif /* MOTIF */
+
+#if !TOOLKIT
+
+void
+showmessage(message)
+ _Xconst char *message;
+{
+ get_xy();
+ XDrawImageString(DISP, mane.win, copyGC,
+ 5 - window_x, 5 + X11HEIGHT - window_y, message, strlen(message));
+}
+
+#endif /* not TOOLKIT */
+
+
+/* |||
+ * Currently the event handler does not coordinate XCopyArea requests
+ * with GraphicsExpose events. This can lead to problems if the window
+ * is partially obscured and one, for example, drags a scrollbar.
+ */
+
+/*
+ * Actions for the translation mechanism.
+ */
+
+static Boolean have_arg = False;
+static int number = 0;
+static int sign = 1;
+
+#if TOOLKIT
+
+#define GET_ARG4(arg, param, param2, default) \
+ if (*num_params > 0) \
+ {param;} \
+ else { \
+ if (have_arg) { \
+ arg = (param2); \
+ have_arg = False; \
+ number = 0; \
+ sign = 1; \
+ } \
+ else \
+ {default} \
+ }
+
+#define GET_ARG(arg, default) \
+ GET_ARG4(arg, arg = atoi(*params), sign * number, \
+ arg = (default);)
+
+#define GET_ARG6(arg, param, c, param_c, param2, default)\
+ if (*num_params > 0) { \
+ if (**params == (c)) \
+ {param_c;} \
+ else \
+ {param;} \
+ } \
+ else { \
+ if (have_arg) { \
+ arg = (param2); \
+ have_arg = False; \
+ number = 0; \
+ sign = 1; \
+ } \
+ else \
+ {default;} \
+ }
+
+#define TOGGLE(arg) \
+ if (*num_params > 0) { \
+ if (**params != 't' && (atoi(*params) != 0) == arg) \
+ return; \
+ } \
+ else { \
+ if (have_arg) { \
+ int tmparg = number; \
+ \
+ have_arg = False; \
+ number = 0; \
+ sign = 1; \
+ \
+ if ((tmparg != 0) == arg) \
+ return; \
+ } \
+ }
+
+#else /* not TOOLKIT */
+
+static unsigned char keychar;
+
+#define GET_ARG4(arg, param, param2, default) \
+ if (have_arg) { \
+ arg = (param2); \
+ have_arg = False; \
+ number = 0; \
+ sign = 1; \
+ } \
+ else \
+ {default}
+
+#define GET_ARG(arg, default) \
+ GET_ARG4(arg, NA, sign * number, arg = (default);)
+
+#define GET_ARG6(arg, param, c, param_c, param2, default)\
+ if (have_arg) { \
+ arg = (param2); \
+ have_arg = False; \
+ number = 0; \
+ sign = 1; \
+ } \
+ else \
+ {default;}
+
+#define TOGGLE(arg) \
+ if (have_arg) { \
+ int tmparg = number; \
+ \
+ have_arg = False; \
+ number = 0; \
+ sign = 1; \
+ \
+ if ((tmparg != 0) == arg) \
+ return; \
+ }
+
+#endif /* not TOOLKIT */
+
+
+static
+ACTION(Act_digit)
+{
+ unsigned int digit;
+
+#if TOOLKIT
+ if (*num_params != 1 || (digit = **params - '0') > 9) {
+ XBell(DISP, 0);
+ return;
+ }
+#else
+ digit = keychar - '0';
+#endif
+ have_arg = True;
+ number = number * 10 + digit;
+}
+
+static
+ACTION(Act_minus)
+{
+ have_arg = True;
+ sign = -sign;
+}
+
+static
+ACTION(Act_quit)
+{
+#if !FLAKY_SIGPOLL
+ if (debug & DBG_EVENT)
+ puts(event_freq < 0
+ ? "SIGPOLL is working"
+ : "no SIGPOLL signals received");
+#endif
+ xdvi_normal_exit();
+}
+
+static
+ACTION(Act_goto_page)
+{
+ int arg;
+
+ GET_ARG6(arg, arg = atoi(*params) - pageno_correct,
+ 'e', arg = total_pages - 1,
+ sign * number - pageno_correct, arg = total_pages - 1);
+
+ if (arg < 0 || arg >= total_pages) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ if (current_page != arg)
+ goto_page(arg, home);
+
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ return; /* Don't use longjmp here: it might be called from
+ * within the toolkit, and we don't want to longjmp out
+ * of Xt routines. */
+}
+
+static
+ACTION(Act_forward_page)
+{
+ int arg;
+
+ GET_ARG(arg, 1);
+ arg += current_page;
+
+ if (arg >= 0 && arg < total_pages) {
+ if (current_page != arg)
+ goto_page(arg, home);
+ /* Control-L (and changing the page) clears this box */
+ source_fwd_box_page = -1;
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ return; /* Don't use longjmp here: it might be called from
+ * within the toolkit, and we don't want to longjmp out
+ * of Xt routines. */
+ }
+ XBell(DISP, 0);
+}
+
+static
+ACTION(Act_back_page)
+{
+ int arg;
+
+ GET_ARG(arg, 1);
+ arg = current_page - arg;
+
+ if (arg >= 0 && arg < total_pages) {
+ if (current_page != arg)
+ goto_page(arg, home);
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ return; /* Don't use longjmp here: it might be called from
+ * within the toolkit, and we don't want to longjmp out
+ * of Xt routines. */
+ }
+ XBell(DISP, 0);
+}
+
+static
+ACTION(Act_declare_page_number)
+{
+ int arg;
+
+ GET_ARG(arg, 0);
+ pageno_correct = arg - current_page;
+}
+
+static
+ACTION(Act_home)
+{
+ home(True);
+}
+
+static
+ACTION(Act_center)
+{
+ int x, y;
+
+#if BUTTONS
+ if (event == NULL)
+ return; /* button actions do not provide events */
+#endif
+
+#if TOOLKIT
+#if !MOTIF
+
+ x = event->xkey.x - clip_w / 2;
+ y = event->xkey.y - clip_h / 2;
+ /* The clip widget gives a more exact value. */
+ if (x_bar != NULL)
+ XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (ptrdiff_t) x);
+ if (y_bar != NULL)
+ XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (ptrdiff_t) y);
+ XWarpPointer(DISP, None, None, 0, 0, 0, 0, -x, -y);
+
+#else /* MOTIF */
+
+ get_xy();
+ /* The clip widget gives a more exact value. */
+ x = event->xkey.x - clip_w / 2;
+ y = event->xkey.y - clip_h / 2;
+
+ x = set_bar_value(x_bar, x, (int) (page_w - clip_w));
+ y = set_bar_value(y_bar, y, (int) (page_h - clip_h));
+ XWarpPointer(DISP, None, None, 0, 0, 0, 0,
+ -x - window_x, -y - window_y);
+
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+
+ x = clip_w / 2 - event->xkey.x;
+ if (x > mane.base_x) x = mane.base_x;
+ y = clip_h / 2 - event->xkey.y;
+ if (y > mane.base_y) y = mane.base_y;
+ scrollwindow(&mane, mane.base_x - x, mane.base_y - y);
+ if (x_bar) paint_x_bar();
+ if (y_bar) paint_y_bar();
+ XWarpPointer(DISP, None, None, 0, 0, 0, 0, x, y);
+
+#endif /* not TOOLKIT */
+
+}
+
+static
+ACTION(Act_set_keep_flag)
+{
+
+#if TOOLKIT
+ if (*num_params == 0) {
+#endif
+ if (have_arg) {
+ resource.keep_flag = (number != 0);
+ have_arg = False;
+ number = 0;
+ sign = 1;
+ }
+ else
+ resource.keep_flag = !resource.keep_flag;
+#if TOOLKIT
+ }
+ else
+ resource.keep_flag = (**params == 't'
+ ? !resource.keep_flag
+ : atoi(*params));
+#endif
+}
+
+static
+ACTION(Act_left)
+{
+#if TOOLKIT
+#if !MOTIF
+ if (x_bar != NULL)
+ XtCallCallbacks(x_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (-2 * (ptrdiff_t) clip_w / 3)
+ : (ptrdiff_t) (-atof(*params) * clip_w)));
+ else
+ XBell(DISP, 0);
+#else /* MOTIF */
+ get_xy();
+ (void) set_bar_value(x_bar, (*num_params == 0 ? (-2 * (int) clip_w / 3)
+ : (int) (-atof(*params) * clip_w)) - window_x,
+ (int) (page_w - clip_w));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ if (mane.base_x > 0)
+ scrollmane(mane.base_x - 2 * (int) clip_w / 3, mane.base_y);
+ else
+ XBell(DISP, 0);
+#endif /* not TOOLKIT */
+}
+
+static
+ACTION(Act_right)
+{
+#if TOOLKIT
+#if !MOTIF
+ if (x_bar != NULL)
+ XtCallCallbacks(x_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (2 * (ptrdiff_t) clip_w / 3)
+ : (ptrdiff_t) (atof(*params) * clip_w)));
+ else
+ XBell(DISP, 0);
+#else /* MOTIF */
+ get_xy();
+ (void) set_bar_value(x_bar, (*num_params == 0 ? (2 * (int) clip_w / 3)
+ : (int) (atof(*params) * clip_w)) - window_x,
+ (int) (page_w - clip_w));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ if (mane.base_x < (int) page_w - (int) clip_w)
+ scrollmane(mane.base_x + 2 * (int) clip_w / 3, mane.base_y);
+ else
+ XBell(DISP, 0);
+#endif /* not TOOLKIT */
+}
+
+static
+ACTION(Act_up)
+{
+#if TOOLKIT
+#if !MOTIF
+ if (y_bar != NULL)
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (-2 * (ptrdiff_t) clip_h / 3)
+ : (ptrdiff_t) (-atof(*params) * clip_h)));
+ else
+ XBell(DISP, 0);
+#else /* MOTIF */
+ get_xy();
+ (void) set_bar_value(y_bar, (*num_params == 0 ? (-2 * (int) clip_h / 3)
+ : (int) (-atof(*params) * clip_h)) - window_y,
+ (int) (page_h - clip_h));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ if (mane.base_y > 0)
+ scrollmane(mane.base_x, mane.base_y - 2 * (int) clip_h / 3);
+ else
+ XBell(DISP, 0);
+#endif /* not TOOLKIT */
+}
+
+static
+ACTION(Act_down)
+{
+#if TOOLKIT
+#if !MOTIF
+ if (y_bar != NULL)
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (2 * (ptrdiff_t) clip_h / 3)
+ : (ptrdiff_t) (atof(*params) * clip_h)));
+ else
+ XBell(DISP, 0);
+#else /* MOTIF */
+ get_xy();
+ (void) set_bar_value(y_bar, (*num_params == 0 ? (2 * (int) clip_h / 3)
+ : (int) (atof(*params) * clip_h)) - window_y,
+ (int) (page_h - clip_h));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ if (mane.base_y < (int) page_h - (int) clip_h)
+ scrollmane(mane.base_x, mane.base_y + 2 * (int) clip_h / 3);
+ else
+ XBell(DISP, 0);
+#endif /* not TOOLKIT */
+}
+
+static
+ACTION(Act_down_or_next)
+{
+ if (!resource.keep_flag) {
+#if TOOLKIT
+#if !MOTIF
+ if (y_bar != NULL) {
+ get_xy();
+ if (window_y > (int) clip_h - (int) page_h) {
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0
+ ? (2 * (ptrdiff_t) clip_h / 3)
+ : (ptrdiff_t) (atof(*params) * clip_h)));
+ return;
+ }
+ }
+#else /* MOTIF */
+ get_xy();
+ if (window_y > (int) clip_h - (int) page_h) {
+ (void) set_bar_value(y_bar,
+ (*num_params == 0 ? (2 * (int) clip_h / 3)
+ : (int) (atof(*params) * clip_h)) - window_y,
+ (int) (page_h - clip_h));
+ return;
+ }
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ if (mane.base_y < (int) page_h - (int) clip_h) {
+ scrollmane(mane.base_x, mane.base_y + 2 * (int) clip_h / 3);
+ return;
+ }
+#endif /* not TOOLKIT */
+ } /* !keep_flag */
+
+ if (current_page < total_pages - 1) {
+ goto_page(current_page + 1, home);
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ return; /* Don't use longjmp here: it might be called from
+ * within the toolkit, and we don't want to longjmp out
+ * of Xt routines. */
+ }
+ else
+ XBell(DISP, 0);
+}
+
+static
+ACTION(Act_up_or_previous)
+{
+ if (!resource.keep_flag) {
+#if TOOLKIT
+#if !MOTIF
+ if (y_bar != NULL) {
+ get_xy();
+ if (window_y < 0) {
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0
+ ? (-2 * (ptrdiff_t) clip_h / 3)
+ : (ptrdiff_t) (-atof(*params) * clip_h)));
+ return;
+ }
+ }
+#else /* MOTIF */
+ get_xy();
+ if (window_y < 0) {
+ (void) set_bar_value(y_bar,
+ (*num_params == 0 ? (-2 * (int) clip_h / 3)
+ : (int) (-atof(*params) * clip_h)) - window_y,
+ (int) (page_h - clip_h));
+ return;
+ }
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ if (mane.base_y > 0) {
+ scrollmane(mane.base_x, mane.base_y - 2 * (int) clip_h / 3);
+ return;
+ }
+#endif /* not TOOLKIT */
+ } /* !keep_flag */
+
+ if (current_page > 0) {
+ goto_page(current_page - 1, home_bottom);
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ return; /* Don't use longjmp here: it might be called from
+ * within the toolkit, and we don't want to longjmp out
+ * of Xt routines. */
+ }
+ else
+ XBell(DISP, 0);
+}
+
+static
+ACTION(Act_set_margins)
+{
+ Window ww;
+
+#if BUTTONS
+ if (event == NULL)
+ return; /* button actions do not provide events */
+#endif
+
+ (void) XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &home_x, &home_y,
+ &ww); /* throw away last argument */
+ home_x *= mane.shrinkfactor;
+ home_y *= mane.shrinkfactor;
+}
+
+static
+ACTION(Act_show_display_attributes)
+{
+ Printf("Unit = %d, bitord = %d, byteord = %d\n",
+ BitmapUnit(DISP), BitmapBitOrder(DISP), ImageByteOrder(DISP));
+}
+
+static int
+shrink_to_fit()
+{
+ int value1;
+ int value2;
+
+ value1 = ROUNDUP(unshrunk_page_w, window_w - 2);
+
+#if !MOTIF
+ value2 = ROUNDUP(unshrunk_page_h, window_h - 2);
+#else /* MOTIF */
+ { /* account for menubar */
+ static Dimension new_h;
+
+ /* get rid of scrollbar */
+ XdviResizeWidget(draw_widget, 1, 1);
+ XtVaGetValues(clip_widget, XtNheight, &new_h, NULL);
+ value2 = ROUNDUP(unshrunk_page_h, new_h - 2);
+ }
+#endif /* MOTIF */
+
+ return value1 > value2 ? value1 : value2;
+}
+
+static
+ACTION(Act_set_shrink_factor)
+{
+ int arg;
+
+ GET_ARG6(arg, arg = atoi(*params), 'a', arg = shrink_to_fit(),
+ number, arg = shrink_to_fit());
+
+ if (arg <= 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ if (arg == mane.shrinkfactor)
+ return;
+#if !MOTIF
+ mane.shrinkfactor = arg;
+#else
+ set_shrink_factor(arg);
+#endif
+ if (arg != 1 && arg != bak_shrink) {
+ bak_shrink = arg;
+#if GREY
+#if COLOR
+ if (use_grey) fg_active = NULL;
+#else
+ if (use_grey) init_pix();
+#endif
+#endif /* GREY */
+ reset_fonts();
+ }
+
+ if (dvi_file == NULL) {
+ unshrunk_page_w = unshrunk_page_h = 0;
+ return;
+ }
+
+ init_page();
+ reconfig();
+ home(False);
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+static
+ACTION(Act_shrink_to_dpi)
+{
+ int arg;
+
+ GET_ARG(arg, 0);
+
+ if (arg > 0)
+ arg = (double) pixels_per_inch / arg + 0.5;
+
+ if (arg <= 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ if (arg == mane.shrinkfactor)
+ return;
+#if !MOTIF
+ mane.shrinkfactor = arg;
+#else
+ set_shrink_factor(arg);
+#endif
+ if (arg != 1 && arg != bak_shrink) {
+ bak_shrink = arg;
+#if GREY
+#if COLOR
+ if (use_grey) fg_active = NULL;
+#else
+ if (use_grey) init_pix();
+#endif
+#endif /* GREY */
+ reset_fonts();
+ }
+
+ if (dvi_file == NULL) {
+ unshrunk_page_w = unshrunk_page_h = 0;
+ return;
+ }
+
+ init_page();
+ reconfig();
+ home(False);
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+static
+ACTION(Act_set_density)
+{
+ int arg;
+
+ GET_ARG4(arg, arg = atoi(*params), sign * number,
+ {XBell(DISP, 0); return;});
+
+#if GREY
+ if (use_grey) {
+ float newgamma = arg != 0 ? arg / 100.0 : 1.0;
+
+ if (newgamma == gamma)
+ return;
+ gamma = newgamma;
+#if COLOR
+ fg_active = NULL;
+ reset_colors();
+#else
+ init_pix();
+ if (our_visual->class != TrueColor)
+ return;
+ reset_fonts();
+#endif /* COLOR */
+ }
+ else
+#endif /* GREY */
+ {
+ if (arg < 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ if (arg == density)
+ return;
+ density = arg;
+ reset_fonts();
+ if (mane.shrinkfactor == 1)
+ return;
+ }
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+#if GREY
+
+static
+ACTION(Act_set_greyscaling)
+{
+ TOGGLE(use_grey);
+ use_grey = !use_grey;
+
+ if (use_grey) {
+ if (our_visual->class != TrueColor)
+ init_plane_masks();
+#if COLOR
+ fg_active = NULL;
+#else
+ init_pix();
+#endif
+ }
+ reset_fonts();
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+#endif /* GREY */
+
+#if COLOR
+
+static
+ACTION(Act_set_color)
+{
+ TOGGLE(use_color)
+
+ if (use_color) {
+ use_color = False;
+ full_reset_colors();
+ scanned_page_color = total_pages;
+#if PS
+ if (ignore_papersize_specials || scanned_page_ps <= total_pages)
+ scanned_page = scanned_page_ps;
+#endif
+ }
+ else {
+ use_color = True;
+ scanned_page = scanned_page_color = scanned_page_reset;
+ }
+ ev_flags |= EV_NEWPAGE;
+}
+
+#endif /* COLOR */
+
+#if PS
+
+static
+ACTION(Act_set_ps)
+{
+ TOGGLE(resource._postscript)
+
+ if (resource._postscript) {
+ resource._postscript = False;
+ scanned_page_ps_bak = scanned_page_ps;
+ scanned_page_ps = total_pages;
+#if COLOR
+ if (ignore_papersize_specials || scanned_page_color <= total_pages)
+ scanned_page = scanned_page_color;
+#endif
+ }
+ else {
+ resource._postscript = True;
+ scanned_page_ps = scanned_page_ps_bak;
+ if (scanned_page > scanned_page_ps)
+ scanned_page = scanned_page_ps;
+ }
+
+ psp.toggle();
+ ev_flags |= EV_PS_TOGGLE;
+ XFlush(DISP);
+}
+
+#endif /* PS */
+
+#if PS_GS
+
+static
+ACTION(Act_set_gs_alpha)
+{
+ TOGGLE(resource.gs_alpha)
+ resource.gs_alpha = !resource.gs_alpha;
+
+ ev_flags |= EV_PS_TOGGLE;
+ XFlush(DISP);
+}
+
+#endif /* PS_GS */
+
+#if BUTTONS
+
+static
+ACTION(Act_set_expert_mode)
+{
+ TOGGLE(resource.expert)
+
+ if (resource.expert) { /* create buttons */
+ resource.expert = False;
+ if (destroy_count != 0) return;
+#if !MOTIF
+ create_buttons(); /* this determines xtra_wid */
+ XtSetValues(vport_widget, resizable_on, XtNumber(resizable_on));
+ XdviResizeWidget(vport_widget, window_w -= xtra_wid, window_h);
+ set_button_panel_height((XtArgVal) window_h);
+#else /* MOTIF */
+ create_buttons();
+ window_w -= xtra_wid;
+#endif /* MOTIF */
+ }
+ else { /* destroy buttons */
+ resource.expert = True;
+ if (destroy_count != 0) return;
+ destroy_count = 2;
+ XtAddCallback(panel_widget, XtNdestroyCallback,
+ handle_destroy_buttons, (XtPointer) 0);
+ XtAddCallback(line_widget, XtNdestroyCallback,
+ handle_destroy_buttons, (XtPointer) 0);
+ XtDestroyWidget(panel_widget);
+ XtDestroyWidget(line_widget);
+ window_w += xtra_wid;
+ while (b_head != NULL) {
+ struct button_info *bp = b_head;
+ struct xdvi_action *action;
+
+ b_head = bp->next;
+ free(bp->label);
+ /* free bp->action */
+ for (action = bp->action; action != NULL; ) {
+ struct xdvi_action *act2 = action;
+
+ action = act2->next;
+ if (act2->num_params > 0) free(act2->param);
+ free(act2);
+ }
+ free(bp);
+ }
+ }
+}
+
+#endif /* BUTTONS */
+
+#if !TOOLKIT
+
+static
+ACTION(Act_redraw)
+{
+ ev_flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+#endif /* not TOOLKIT */
+
+static
+ACTION(Act_reread_dvi_file)
+{
+#if PS
+ ps_clear_cache();
+#endif
+ if (dvi_file != NULL) {
+ Fclose(dvi_file);
+ dvi_file = NULL;
+ dvi_file_ready = False;
+ }
+ ev_flags |= EV_NEWDOC;
+}
+
+static
+ACTION(Act_discard_number)
+{
+ have_arg = False;
+ number = 0;
+ sign = 1;
+}
+
+
+/* Actions to support the magnifying glass. */
+
+static void mag_motion ARGS((XEvent *));
+static void mag_release ARGS((XEvent *));
+
+static void
+compute_mag_pos(xp, yp)
+ int *xp, *yp;
+{
+ int t;
+
+ t = mag_x + main_x - alt.width/2;
+ if (t > WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD)
+ t = WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD;
+ if (t < 0) t = 0;
+ *xp = t;
+ t = mag_y + main_y - alt.height/2;
+ if (t > HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD)
+ t = HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD;
+ if (t < 0) t = 0;
+ *yp = t;
+}
+
+static
+ACTION(Act_magnifier)
+{
+ _Xconst char *p;
+ int x, y;
+ XSetWindowAttributes attr;
+#if XAW
+ Window throwaway;
+#elif !TOOLKIT
+ struct mg_size_rec *size_ptr = mg_size + event->xbutton.button - 1;
+#endif
+
+
+ /*
+ * Don't pop up a magnifying glass if we're still generating fonts or
+ * prescanning (e.g., bg_current might be NULL).
+ */
+
+ if (!check_dvi_file() || !dvi_file_ready)
+ return;
+
+#if MOTIF
+ /*
+ * There's an apparent bug in Motif related to the interaction between
+ * the menubar menus and the magnifier.
+ *
+ * If you click on a menu on the menubar and then click on the drawing
+ * widget to pop up a magnifier, the keyboard and pointer are still
+ * grabbed, leading to a weird situation in which the magnifier stays
+ * around even after you release the pointer. The following statement
+ * works around this bug by ignoring such pointer events.
+ *
+ * This bug occurs in Motif 1.2 and OpenMotif 2.2.2 (at least). It
+ * does not occur in Lesstif.
+ */
+
+ if (event->xany.serial < ungrab_serial)
+ return;
+#endif
+
+#if TOOLKIT
+
+ if (event->type != ButtonPress || mouse_release != null_mouse
+ || alt.win != (Window) 0 || mane.shrinkfactor == 1
+ || *num_params != 1) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ p = *params;
+ if (*p == '*') {
+ int n = atoi(p + 1) - 1;
+
+ if (n < 0 || n >= 5 || mg_size[n].w <= 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ alt.width = mg_size[n].w;
+ alt.height = mg_size[n].h;
+ }
+ else {
+ alt.width = alt.height = atoi(p);
+ p = index(p, 'x');
+ if (p != NULL) {
+ alt.height = atoi(p + 1);
+ if (alt.height == 0) alt.width = 0;
+ }
+ if (alt.width == 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ }
+#if !MOTIF
+ (void) XTranslateCoordinates(DISP, event->xbutton.window, mane.win,
+ 0, 0, &mag_conv_x, &mag_conv_y, &throwaway);
+#endif
+
+#else /* not TOOLKIT */
+
+ if (mouse_release != null_mouse || alt.win != (Window) 0
+ || mane.shrinkfactor == 1 || size_ptr->w <= 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ alt.width = size_ptr->w;
+ alt.height = size_ptr->h;
+
+#endif /* not TOOLKIT */
+
+ mag_x = event->xbutton.x + mag_conv_x;
+ mag_y = event->xbutton.y + mag_conv_y;
+ main_x = event->xbutton.x_root - mag_x;
+ main_y = event->xbutton.y_root - mag_y;
+ compute_mag_pos(&x, &y);
+ alt.base_x = (mag_x + mane_base_x) * mane.shrinkfactor - alt.width/2;
+ alt.base_y = (mag_y + mane_base_y) * mane.shrinkfactor - alt.height/2;
+ attr.save_under = True;
+ attr.border_pixel = brdr_Pixel;
+#if COLOR
+ attr.background_pixel = bg_current->pixel;
+#else
+ attr.background_pixel = back_Pixel;
+#endif
+ attr.override_redirect = True;
+#ifdef GREY
+ attr.colormap = our_colormap;
+#endif
+ alt.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
+ x, y, alt.width, alt.height, MAGBORD,
+ our_depth, InputOutput, our_visual,
+ CWSaveUnder | CWBorderPixel | CWBackPixel |
+#ifdef GREY
+ CWColormap |
+#endif
+ CWOverrideRedirect, &attr);
+ XSelectInput(DISP, alt.win, ExposureMask);
+ XMapWindow(DISP, alt.win);
+ alt_stat = 1; /* waiting for exposure */
+ mouse_motion = mag_motion;
+ mouse_release = mag_release;
+}
+
+static void
+mag_motion P1C(XEvent *, event)
+{
+ new_mag_x = event->xmotion.x + mag_conv_x;
+ main_x = event->xmotion.x_root - new_mag_x;
+ new_mag_y = event->xmotion.y + mag_conv_y;
+ main_y = event->xmotion.y_root - new_mag_y;
+
+ if (new_mag_x != mag_x || new_mag_y != mag_y)
+ ev_flags |= EV_MAG_MOVE;
+ else
+ ev_flags &= ~EV_MAG_MOVE;
+}
+
+/* ARGSUSED */
+static void
+mag_release P1C(XEvent *, event)
+{
+ if (alt.win != (Window) 0) {
+ if (alt_stat)
+ alt_stat = -1; /* destroy upon expose */
+ else {
+ XDestroyWindow(DISP, alt.win);
+ if (drawing_mag) ev_flags |= EV_MAG_GONE;
+ alt.win = (Window) 0;
+ mouse_motion = mouse_release = null_mouse;
+ ev_flags &= ~EV_MAG_MOVE;
+ can_exposures(&alt);
+ }
+ }
+}
+
+static void
+movemag(x, y)
+ int x, y;
+{
+ int xx, yy;
+
+ mag_x = x;
+ mag_y = y;
+ if (mag_x == new_mag_x && mag_y == new_mag_y) ev_flags &= ~EV_MAG_MOVE;
+ compute_mag_pos(&xx, &yy);
+ XMoveWindow(DISP, alt.win, xx, yy);
+ scrollwindow(&alt,
+ (x + mane_base_x) * mane.shrinkfactor - (int) alt.width/2,
+ (y + mane_base_y) * mane.shrinkfactor - (int) alt.height/2);
+}
+
+
+/* Actions to support dragging the image. */
+
+static int drag_last_x, drag_last_y; /* last position of cursor */
+static int drag_flags; /* 1 = vert, 2 = horiz */
+
+static void drag_motion ARGS((XEvent *));
+static void drag_release ARGS((XEvent *));
+
+static
+ACTION(Act_drag)
+{
+ if (mouse_release != null_mouse && mouse_release != drag_release)
+ return;
+
+#if TOOLKIT
+
+ if (*num_params != 1) return;
+ switch (**params) {
+ case '|': drag_flags = 1; break;
+ case '-': drag_flags = 2; break;
+ case '+': drag_flags = 3; break;
+ default: return;
+ }
+
+#else /* not TOOLKIT */
+
+ drag_flags = event->xbutton.button;
+ if (drag_flags <= 0 || drag_flags > 3)
+ return;
+ drag_flags = drag_flags ^ (drag_flags >> 1);
+
+#endif /* not TOOLKIT */
+
+ if (mouse_release == null_mouse) {
+ mouse_motion = drag_motion;
+ mouse_release = drag_release;
+ drag_last_x = event->xbutton.x_root;
+ drag_last_y = event->xbutton.y_root;
+ }
+ else
+ drag_motion(event);
+
+#if COLOR
+ {
+ static Boolean curs_pix_set[3] = {False, False, False};
+ static Pixel cursor_pix[3];
+
+ if (bg_current != NULL && (!curs_pix_set[drag_flags - 1]
+ || cursor_pix[drag_flags - 1] != bg_current->pixel)) {
+ XRecolorCursor(DISP, drag_cursor[drag_flags - 1], &cr_Color,
+ &bg_Color);
+ cursor_pix[drag_flags - 1] = bg_current->pixel;
+ curs_pix_set[drag_flags - 1] = True;
+ }
+ }
+#endif
+
+ XDefineCursor(DISP, CURSORWIN, drag_cursor[drag_flags - 1]);
+ XFlush(DISP);
+ dragcurs = True;
+}
+
+
+static void
+drag_motion P1C(XEvent *, event)
+{
+#if MOTIF
+ get_xy();
+#endif
+
+ if (drag_flags & 2) { /* if horizontal motion */
+#if TOOLKIT
+#if !MOTIF
+ if (x_bar != NULL)
+ XtCallCallbacks(x_bar, XtNscrollProc,
+ (XtPointer) (ptrdiff_t)
+ (drag_last_x - event->xbutton.x_root));
+#else /* MOTIF */
+ (void) set_bar_value(x_bar,
+ drag_last_x - event->xbutton.x_root - window_x,
+ (int) (page_w - clip_w));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ scrollmane(mane.base_x + drag_last_x - event->xbutton.x_root,
+ mane.base_y);
+#endif /* not TOOLKIT */
+ drag_last_x = event->xbutton.x_root;
+ }
+
+ if (drag_flags & 1) { /* if vertical motion */
+#if TOOLKIT
+#if !MOTIF
+ if (y_bar != NULL)
+ XtCallCallbacks(y_bar, XtNscrollProc,
+ (XtPointer) (ptrdiff_t)
+ (drag_last_y - event->xbutton.y_root));
+#else /* MOTIF */
+ (void) set_bar_value(y_bar,
+ drag_last_y - event->xbutton.y_root - window_y,
+ (int) (page_h - clip_h));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ scrollmane(mane.base_x,
+ mane.base_y + drag_last_y - event->xbutton.y_root);
+#endif /* not TOOLKIT */
+ drag_last_y = event->xbutton.y_root;
+ }
+}
+
+
+static void
+drag_release P1C(XEvent *, event)
+{
+ drag_motion(event);
+ mouse_motion = mouse_release = null_mouse;
+
+ XDefineCursor(DISP, CURSORWIN,
+ ev_flags & EV_CURSOR ? redraw_cursor : ready_cursor);
+ XFlush(DISP);
+ dragcurs = False;
+}
+
+
+
+/* Wheel support. */
+
+static int wheel_button = -1;
+
+static
+ACTION(Act_wheel)
+{
+#if TOOLKIT
+ int dist;
+
+ if (*num_params == 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ dist = (index(*params, '.') == NULL) ? atoi(*params)
+ : (int) (atof(*params) * resource.wheel_unit);
+#if !MOTIF
+ if (y_bar != NULL)
+ XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (ptrdiff_t) dist);
+#else /* MOTIF */
+ get_xy();
+ (void) set_bar_value(y_bar, dist - window_y, (int) (page_h - clip_h));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ scrollmane(mane.base_x,
+ mane.base_y + (event->xbutton.button == 5
+ ? resource.wheel_unit : -resource.wheel_unit));
+#endif /* not TOOLKIT */
+
+#if TOOLKIT
+ if (event != NULL)
+#endif
+ wheel_button = event->xbutton.button;
+}
+
+static int wheel_h_button = -1;
+
+static
+ACTION(Act_hwheel)
+{
+#if TOOLKIT
+ int dist;
+
+ if (*num_params == 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ dist = (index(*params, '.') == NULL) ? atoi(*params)
+ : (int) (atof(*params) * resource.wheel_unit);
+#if !MOTIF
+ if (x_bar != NULL)
+ XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (ptrdiff_t) dist);
+#else /* MOTIF */
+ get_xy();
+ (void) set_bar_value(x_bar, dist - window_x, (int) (page_w - clip_w));
+#endif /* MOTIF */
+#else /* not TOOLKIT */
+ scrollmane(mane.base_x + (event->xbutton.button == 7
+ ? resource.wheel_unit : -resource.wheel_unit),
+ mane.base_y);
+#endif /* not TOOLKIT */
+
+#if TOOLKIT
+ if (event != NULL)
+#endif
+ wheel_h_button = event->xbutton.button;
+}
+
+#if TOOLKIT
+static
+ACTION(Act_wheel_actions)
+{
+ struct wheel_acts *wactp;
+ struct xdvi_action *actp;
+
+ for (wactp = wheel_actions; wactp != NULL; wactp = wactp->next)
+ if (event->xbutton.button == wactp->button || wactp->button == 0) {
+ Modifiers mask = 0;
+ Modifiers value = 0;
+
+ if (wactp->late_bindings == NULL
+ || _XtComputeLateBindings(DISP, wactp->late_bindings,
+ &value, &mask)) {
+ mask |= wactp->mask;
+ value |= wactp->value;
+ if (((value ^ event->xbutton.state) & mask) == 0) {
+ for (actp = wactp->action; actp != NULL;
+ actp = actp->next)
+ (actp->proc)(w, event,
+ &actp->param, &actp->num_params);
+ return;
+ }
+ }
+ }
+}
+#endif /* TOOLKIT */
+
+
+/* Internal mouse actions. */
+
+#if TOOLKIT
+
+static
+ACTION(Act_motion)
+{
+ if (event->xbutton.button != wheel_button
+ && event->xbutton.button != wheel_h_button)
+ mouse_motion(event);
+}
+
+
+static
+ACTION(Act_release)
+{
+ if (event->xbutton.button == wheel_button) {
+ wheel_button = -1;
+ return;
+ }
+
+ if (event->xbutton.button == wheel_h_button) {
+ wheel_h_button = -1;
+ return;
+ }
+
+ mouse_release(event);
+}
+
+#endif /* TOOLKIT */
+
+
+/* Actions for source specials. */
+
+ACTION(Act_source_special)
+{
+ Window ww;
+
+ if ((event->type == ButtonPress && mouse_release != null_mouse)
+ || alt.win != (Window) 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ source_reverse_x = event->xbutton.x;
+ source_reverse_y = event->xbutton.y;
+ if (event->xbutton.window != mane.win)
+ (void) XTranslateCoordinates(DISP,
+ RootWindowOfScreen(SCRN), mane.win,
+ event->xbutton.x_root, event->xbutton.y_root,
+ &source_reverse_x, &source_reverse_y,
+ &ww); /* throw away last argument */
+
+ source_reverse_x = (source_reverse_x + mane_base_x) * mane.shrinkfactor;
+ source_reverse_y = (source_reverse_y + mane_base_y) * mane.shrinkfactor;
+
+ ev_flags |= EV_SRC;
+}
+
+ACTION(Act_show_source_specials)
+{
+ if ((event->type == ButtonPress && mouse_release != null_mouse)
+ || alt.win != (Window) 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ if (!(ev_flags & EV_SRC)) {
+ source_reverse_x = -1;
+ source_show_all = False;
+ ev_flags |= EV_SRC;
+ }
+}
+
+ACTION(Act_show_all_boxes)
+{
+ if ((event->type == ButtonPress && mouse_release != null_mouse)
+ || alt.win != (Window) 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ if (!(ev_flags & EV_SRC)) {
+ source_reverse_x = -1;
+ source_show_all = True;
+ ev_flags |= EV_SRC;
+ }
+}
+
+
+#undef ACTION
+#undef GET_ARG4
+#undef GET_ARG
+#undef TOGGLE
+
+
+#if TOOLKIT
+
+ /*ARGSUSED*/
+void
+handle_expose(widget, closure, ev, cont)
+ Widget widget;
+ XtPointer closure;
+ XEvent *ev;
+#define event (&(ev->xexpose))
+ Boolean *cont; /* unused */
+{
+ struct WindowRec *windowrec = (struct WindowRec *) closure;
+
+ if (windowrec == &alt) {
+ if (alt_stat < 0) { /* destroy upon exposure */
+ alt_stat = 0;
+ mag_release(ev);
+ return;
+ }
+ else
+ alt_stat = 0;
+ }
+
+ expose(windowrec, event->x, event->y,
+ (unsigned int) event->width, (unsigned int) event->height);
+}
+
+#undef event
+#endif /* TOOLKIT */
+
+
+void
+#if TOOLKIT
+/* ARGSUSED */
+handle_property_change(widget, junk, ev, cont)
+ Widget widget;
+ XtPointer junk;
+ XEvent *ev;
+ Boolean *cont; /* unused */
+#else /* !TOOLKIT */
+handle_property_change(ev)
+ XEvent *ev;
+#endif
+#define event (&(ev->xproperty))
+{
+ char *src_goto_property;
+ size_t src_goto_len;
+
+ if (event->window != XtWindow(top_level)
+ || event->atom != ATOM_SRC_GOTO) /* if spurious event */
+ return;
+
+ /*
+ * Retrieve the data from our window property.
+ */
+
+ src_goto_len = property_get_data(XtWindow(top_level), ATOM_SRC_GOTO,
+ (unsigned char **) &src_goto_property, XGetWindowProperty);
+
+ if (src_goto_len == 0) {
+ if (debug & DBG_CLIENT)
+ puts("SRC_GOTO gave us nothing");
+ return;
+ }
+
+ source_forward_string = src_goto_property;
+ ev_flags |= EV_SRC;
+}
+
+#undef event
+
+
+#if XAW
+
+void
+handle_messages(widget, closure, event, cont)
+ Widget widget;
+ XtPointer closure;
+ XEvent *event;
+ Boolean *cont; /* unused */
+{
+ if (event->type == ClientMessage
+ && event->xclient.message_type == XA_WM_PROTOCOLS
+ && event->xclient.data.l[0] == XA_WM_DELETE_WINDOW) {
+ if (closure != 0)
+ ((XtCallbackProc) closure) (widget, NULL, NULL);
+ else
+ Act_quit(widget, event, NULL, 0);
+ }
+}
+
+#elif MOTIF
+
+void
+handle_wm_delete(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ Act_quit(w, NULL, NULL, 0);
+}
+
+#endif /* MOTIF */
+
+
+/*
+ * Interrupt system for receiving events. The program sets a flag
+ * whenever an event comes in, so that at the proper time (i.e., when
+ * reading a new dvi item), we can check incoming events to see if we
+ * still want to go on printing this page. This way, one can stop
+ * displaying a page if it is about to be erased anyway. We try to read
+ * as many events as possible before doing anything and base the next
+ * action on all events read.
+ * Note that the Xlib and Xt routines are not reentrant, so the most we
+ * can do is set a flag in the interrupt routine and check it later.
+ * Also, sometimes the interrupts are not generated (some systems only
+ * guarantee that SIGIO is generated for terminal files, and on the system
+ * I use, the interrupts are not generated if I use "(xdvi foo &)" instead
+ * of "xdvi foo"). Therefore, there is also a mechanism to check the
+ * event queue every 70 drawing operations or so. This mechanism is
+ * disabled if it turns out that the interrupts do work.
+ * For a fuller discussion of some of the above, see xlife in
+ * comp.sources.x.
+ */
+
+/*
+ * Signal flags
+ */
+
+/* This could be static volatile, but we want to avoid any optimizer bugs. */
+VOLATILE unsigned int sig_flags = 0;
+
+#define SF_USR 1
+#define SF_ALRM 2
+#define SF_POLL 4
+#define SF_CHLD 8
+#define SF_TERM 16
+
+static void do_sigterm ARGS((void));
+static void do_sigchld ARGS((void));
+static void do_sigpoll ARGS((void));
+static void do_sigalrm ARGS((void));
+static void do_sigusr ARGS((void));
+
+#define SP0 do_sigusr /* these must be in the same order as SF_* */
+#define SP1 do_sigalrm
+#define SP2 do_sigpoll
+#define SP3 do_sigchld
+#define SP4 do_sigterm /* highest priority */
+
+typedef void (*signalproc) ARGS((void));
+
+static _Xconst signalproc flags_to_sigproc[32]
+ = {NULL, SP0, SP1, SP1, SP2, SP2, SP2, SP2,
+ SP3, SP3, SP3, SP3, SP3, SP3, SP3, SP3,
+ SP4, SP4, SP4, SP4, SP4, SP4, SP4, SP4,
+ SP4, SP4, SP4, SP4, SP4, SP4, SP4, SP4};
+
+#undef SP0
+#undef SP1
+#undef SP2
+#undef SP3
+#undef SP4
+
+
+/*
+ * Signal routines. At the signal level, all we do is set flags.
+ */
+
+#if !FLAKY_SIGPOLL
+/* ARGSUSED */
+static RETSIGTYPE
+handle_sigpoll(signo)
+ int signo;
+{
+ event_counter = 1;
+ event_freq = -1; /* forget Plan B */
+ sig_flags |= SF_POLL;
+#if !HAVE_SIGACTION
+ (void) signal(SIGPOLL, handle_sigpoll); /* reset the signal */
+#endif
+}
+#endif /* not FLAKY_SIGPOLL */
+
+/* ARGSUSED */
+static RETSIGTYPE
+handle_sigterm(signo)
+ int signo;
+{
+ sig_flags |= SF_TERM;
+}
+
+/* ARGSUSED */
+static RETSIGTYPE
+handle_sigchld(signo)
+ int signo;
+{
+ sig_flags |= SF_CHLD;
+}
+
+/* ARGSUSED */
+static RETSIGTYPE
+handle_sigalrm(signo)
+ int signo;
+{
+ sig_flags |= SF_ALRM;
+}
+
+/* ARGSUSED */
+static RETSIGTYPE
+handle_sigusr(signo)
+ int signo;
+{
+ event_counter = 1;
+ sig_flags |= SF_USR;
+}
+
+
+/*
+ * enable_intr() - Called from main to set up the signal handlers.
+ */
+
+void
+enable_intr() {
+#ifndef FLAKY_SIGPOLL
+ int sock_fd = ConnectionNumber(DISP);
+#endif
+#if HAVE_SIGACTION
+ struct sigaction a;
+#endif
+
+#ifndef FLAKY_SIGPOLL
+#if HAVE_SIGACTION
+ /* Subprocess handling, e.g., MakeTeXPK, fails on the Alpha without
+ this, because SIGPOLL interrupts the call of system(3), since OSF/1
+ doesn't retry interrupted wait calls by default. From code by
+ maj@cl.cam.ac.uk. */
+ a.sa_handler = handle_sigpoll;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGPOLL);
+ a.sa_flags = SA_RESTART;
+ sigaction(SIGPOLL, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGPOLL, handle_sigpoll);
+#endif /* not HAVE_SIGACTION */
+
+ prep_fd(sock_fd, False);
+#endif /* not FLAKY_SIGPOLL */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigterm;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGINT);
+ (void) sigaddset(&a.sa_mask, SIGQUIT);
+ (void) sigaddset(&a.sa_mask, SIGTERM);
+ (void) sigaddset(&a.sa_mask, SIGHUP);
+ a.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &a, NULL);
+ sigaction(SIGQUIT, &a, NULL);
+ sigaction(SIGTERM, &a, NULL);
+ sigaction(SIGHUP, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGINT, handle_sigterm);
+ (void) signal(SIGQUIT, handle_sigterm);
+ (void) signal(SIGTERM, handle_sigterm);
+ (void) signal(SIGHUP, handle_sigterm);
+#endif /* not HAVE_SIGACTION */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigchld;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGCHLD);
+ a.sa_flags = 0;
+ sigaction(SIGCHLD, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGCHLD, handle_sigchld);
+#endif /* not HAVE_SIGACTION */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigalrm;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGALRM);
+ a.sa_flags = 0;
+ sigaction(SIGALRM, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGALRM, handle_sigalrm);
+#endif /* not HAVE_SIGACTION */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigusr;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGUSR1);
+ a.sa_flags = 0;
+ sigaction(SIGUSR1, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGUSR1, handle_sigusr);
+#endif /* not HAVE_SIGACTION */
+
+ (void) sigemptyset(&all_signals);
+ (void) sigaddset(&all_signals, SIGPOLL);
+ (void) sigaddset(&all_signals, SIGINT);
+ (void) sigaddset(&all_signals, SIGQUIT);
+ (void) sigaddset(&all_signals, SIGTERM);
+ (void) sigaddset(&all_signals, SIGHUP);
+ (void) sigaddset(&all_signals, SIGCHLD);
+ (void) sigaddset(&all_signals, SIGALRM);
+ (void) sigaddset(&all_signals, SIGUSR1);
+
+}
+
+
+/*
+ * Mid-level signal handlers. These are called from within read_events(),
+ * and do the actual work appropriate for the given signal.
+ */
+
+/*
+ * Process-related routines. Call set_chld() to indicate that a given
+ * child process should be watched for when it terminates. Call
+ * clear_chld() to remove the process from the list. When the child
+ * terminates, the record is removed from the list and the indicated
+ * process is called.
+ */
+
+static struct xchild *child_recs = NULL; /* head of child process list */
+
+void
+set_chld(cp)
+ struct xchild *cp;
+{
+ cp->next = child_recs;
+ child_recs = cp;
+}
+
+void
+clear_chld(cp)
+ struct xchild *cp;
+{
+ struct xchild **cpp;
+
+ for (cpp = &child_recs;;) {
+ struct xchild *cp2;
+
+ cp2 = *cpp;
+ if (cp2 == cp) break;
+ cpp = &cp2->next;
+ }
+ *cpp = cp->next;
+}
+
+static void
+do_sigchld()
+{
+ pid_t pid;
+ int status;
+
+ sig_flags &= ~SF_CHLD;
+
+#if ! HAVE_SIGACTION
+ (void) signal(SIGCHLD, handle_sigchld); /* reset the signal */
+#endif
+ for (;;) {
+#if HAVE_WAITPID
+ pid = waitpid(-1, &status, WNOHANG);
+#else
+ pid = wait3(&status, WNOHANG, NULL);
+#endif
+ if (pid == 0) break;
+
+ if (pid != -1) {
+ struct xchild **cpp;
+ struct xchild *cp;
+
+ for (cpp = &child_recs;;) {
+ cp = *cpp;
+ if (cp == NULL)
+ break;
+ if (cp->pid == pid) {
+ *cpp = cp->next; /* unlink it */
+ (cp->proc)(status);
+ break;
+ }
+ cpp = &cp->next;
+ }
+ break;
+ }
+
+ if (errno == EINTR) continue;
+ if (errno == ECHILD) break;
+#if HAVE_WAITPID
+ perror("xdvi: waitpid");
+#else
+ perror("xdvi: wait3");
+#endif
+ break;
+ }
+}
+
+
+/*
+ * File-related routines. Call set_io() to indicate that a given fd
+ * should be watched for ability to input or output data. Call clear_io()
+ * to remove it from the list. When poll()/select() indicates that the fd
+ * is available for the indicated type of i/o, the corresponding routine
+ * is called. Call clear_io() to remove an fd from the list.
+ * Both set_io() and clear_io() can be called from within read_proc or
+ * write_proc (although turning an io descriptor on or off is better
+ * accomplished by setting the events flag in the xio structure, and
+ * in the corresponding pollfd structure if the pfd pointer is not NULL
+ * (it is always non-NULL when read_proc and write_proc are called)).
+ * We allocate space for one additional record in the pollfd array, to
+ * accommodate the fd for the X connection; this is done by initializing
+ * num_fds to 1 instead of zero.
+ */
+
+static struct xio *iorecs = NULL; /* head of xio list */
+
+#if HAVE_POLL
+static struct pollfd *fds = NULL;
+static int num_fds = 1; /* current number of fds */
+static int max_fds = 0; /* max allocated number of fds */
+static Boolean io_dirty= True; /* need to recompute fds[] array */
+#else
+static int numfds = 0;
+static fd_set readfds;
+static fd_set writefds;
+#endif
+
+void
+set_io(ip)
+ struct xio *ip;
+{
+ ip->next = iorecs;
+ iorecs = ip;
+
+#if HAVE_POLL
+ ++num_fds;
+ if (!io_dirty && num_fds <= max_fds) {
+ fds[num_fds - 1].fd = ip->fd;
+ fds[num_fds - 1].events = ip->xio_events;
+ ip->pfd = &fds[num_fds - 1];
+ }
+ else {
+ ip->pfd = NULL;
+ io_dirty = True;
+ }
+#else
+ if (numfds <= ip->fd) numfds = ip->fd + 1;
+#endif
+}
+
+void
+clear_io(ip)
+ struct xio *ip;
+{
+ struct xio **ipp;
+
+ for (ipp = &iorecs;;) {
+ struct xio *ip2;
+
+ ip2 = *ipp;
+ if (ip2 == ip) break;
+ ipp = &ip2->next;
+ }
+ *ipp = ip->next;
+
+#if HAVE_POLL
+ --num_fds;
+ io_dirty = True;
+#else
+# if FLAKY_SIGPOLL
+ numfds = ConnectionNumber(DISP);
+# else
+ numfds = (event_freq < 0 ? -1 : ConnectionNumber(DISP));
+# endif
+ for (ip = iorecs; ip != NULL; ip = ip->next)
+ if (ip->fd > numfds)
+ numfds = ip->fd;
+ ++numfds;
+#endif /* !HAVE_POLL */
+}
+
+static void
+do_sigpoll()
+{
+#if FLAKY_SIGPOLL
+ sig_flags &= ~SF_POLL;
+#else
+ struct xio *ip;
+
+ sig_flags &= ~SF_POLL;
+
+#if HAVE_POLL
+
+ if (io_dirty) {
+ struct pollfd *fp;
+
+ if (num_fds > max_fds) {
+ if (fds != NULL) free(fds);
+ fds = xmalloc(num_fds * sizeof *fds);
+ max_fds = num_fds;
+ fds->fd = ConnectionNumber(DISP);
+ fds->events = POLLIN;
+ }
+ fp = fds + 1;
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ fp->fd = ip->fd;
+ fp->events = ip->xio_events;
+ ip->pfd = fp;
+ ++fp;
+ }
+ io_dirty = False;
+ }
+
+ for (;;) {
+ if (poll(fds + 1, num_fds - 1, 0) >= 0)
+ break;
+
+ if (errno != EAGAIN && errno != EINTR) {
+ perror("xdvi: poll");
+ return;
+ }
+ }
+
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ int revents = ip->pfd->revents;
+
+ if (revents & POLLIN) (ip->read_proc)();
+ if (revents & POLLOUT) (ip->write_proc)();
+ }
+
+#else
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (ip->xio_events & XIO_IN)
+ FD_SET(ip->fd, &readfds);
+ if (ip->xio_events & XIO_OUT)
+ FD_SET(ip->fd, &writefds);
+ }
+
+ for (;;) {
+ struct timeval tv;
+
+ tv.tv_sec = tv.tv_usec = 0;
+ if (select(numfds, &readfds, &writefds, (fd_set *) NULL, &tv) >= 0)
+ break;
+
+ if (errno != EAGAIN && errno != EINTR) {
+ perror("select (xdvi read_events)");
+ return;
+ }
+ }
+
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (FD_ISSET(ip->fd, &readfds))
+ (ip->read_proc)();
+ if (FD_ISSET(ip->fd, &writefds))
+ (ip->write_proc)();
+ }
+
+#endif
+
+#endif /* not FLAKY_SIGPOLL */
+}
+
+
+/*
+ * Timer-related routines. Call set_timer() to set a timer a given number
+ * of milliseconds in the future. At that time, the timer will be cleared
+ * and the given procedure will be called with argument set to the struct
+ * passed to set_timer(). The timer routine may call set_timer() or
+ * cancel_timer().
+ */
+
+
+static struct xtimer *timers = NULL; /* head of timer list */
+
+static struct itimerval itv = {{0, 0}, {0, 0}};
+
+#ifndef timercmp
+#define timercmp(a, b, cmp) ((a)->tv_sec cmp (b)->tv_sec || \
+ ((a)->tv_sec == (b)->tv_sec && (a)->tv_usec cmp (b)->tv_usec))
+#endif /* timercmp */
+
+void
+set_timer(tp, ms)
+ struct xtimer *tp;
+ int ms;
+{
+ struct xtimer **tpp;
+ struct xtimer *tp2;
+
+ gettimeofday(&tp->when, NULL);
+ itv.it_value.tv_sec = ms / 1000;
+ itv.it_value.tv_usec = (ms % 1000) * 1000;
+ tp->when.tv_sec += itv.it_value.tv_sec;
+ tp->when.tv_usec += itv.it_value.tv_usec;
+ if (tp->when.tv_usec >= 1000000) {
+ tp->when.tv_usec -= 1000000;
+ ++tp->when.tv_sec;
+ }
+
+ for (tpp = &timers;;) { /* add timer to list */
+ tp2 = *tpp;
+ if (tp2 == NULL || timercmp(&tp->when, &tp2->when, <))
+ break;
+ tpp = &tp2->next;
+ }
+ tp->next = tp2;
+ *tpp = tp;
+
+ if (tpp == &timers) {
+ setitimer(ITIMER_REAL, &itv, NULL);
+ if (ms == 0)
+ sig_flags |= SF_ALRM;
+ }
+}
+
+void
+cancel_timer(tp)
+ struct xtimer *tp;
+{
+ struct xtimer **tpp;
+
+ for (tpp = &timers;;) { /* remove from list */
+ if (*tpp == tp)
+ break;
+ tpp = &(*tpp)->next;
+ }
+
+ *tpp = (*tpp)->next; /* unlink it */
+
+ if (timers == NULL) { /* cancel SIGALRM */
+ itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &itv, NULL);
+ }
+}
+
+static void
+do_sigalrm()
+{
+ struct timeval now;
+
+ sig_flags &= ~SF_ALRM;
+#if !HAVE_SIGACTION
+ (void) signal(SIGALRM, handle_sigalrm); /* reset the signal */
+#endif
+
+ gettimeofday(&now, NULL);
+
+ while (timers != NULL && timercmp(&timers->when, &now, <=)) {
+ struct xtimer *tp;
+
+ tp = timers;
+ timers = timers->next; /* unlink it _first_ */
+ (tp->proc)(tp);
+ }
+
+ if (timers != NULL) { /* set next timer */
+ int i;
+
+ itv.it_value.tv_sec = timers->when.tv_sec - now.tv_sec;
+ i = timers->when.tv_usec - now.tv_usec;
+ if (i < 0) {
+ --itv.it_value.tv_sec;
+ i += 1000000;
+ }
+ itv.it_value.tv_usec = i;
+
+ setitimer(ITIMER_REAL, &itv, NULL);
+ }
+}
+
+
+/*
+ * Handle SIGUSR1 signal. Pretty straightforward.
+ */
+
+static void
+do_sigusr()
+{
+ sig_flags &= ~SF_USR;
+#if !HAVE_SIGACTION
+ (void) signal(SIGUSR1, handle_sigusr); /* reset the signal */
+#endif
+ if (dvi_file != NULL) {
+ Fclose(dvi_file);
+ dvi_file = NULL;
+ dvi_file_ready = False;
+ }
+ ev_flags |= EV_NEWDOC;
+}
+
+
+/*
+ * Handle termination signals. Kill child processes, if permitted.
+ * Otherwise, leave it up to the caller. This is the only place where
+ * the EV_TERM event flag is set, and it can only happen if there's an
+ * active non-killable process. This should only happen if read_events()
+ * is called from one of a very few select locations.
+ */
+
+static void
+do_sigterm()
+{
+ struct xchild *cp;
+ Boolean all_killed = True;
+
+ sig_flags &= ~SF_TERM;
+
+ /* loop through child processes */
+ for (cp = child_recs; cp != NULL; cp = cp->next)
+ if (cp->killable)
+ kill(cp->pid, SIGKILL);
+ else
+ all_killed = False;
+
+ if (all_killed) /* if all processes killed */
+ xdvi_exit(0);
+
+ ev_flags |= EV_TERM; /* otherwise, let the caller handle it */
+}
+
+/*
+ * Set the flag so that termination occurs, via the above routine.
+ * This should be used in place of xdvi_exit() when there may be a
+ * non-killable process running (e.g., anytime within read_events()).
+ */
+
+static void
+xdvi_normal_exit()
+{
+ sig_flags |= SF_TERM;
+}
+
+
+/*
+ * Since redrawing the screen is (potentially) a slow task, xdvi checks
+ * for incoming events while this is occurring. It does not register
+ * a work proc that draws and returns every so often, as the toolkit
+ * documentation suggests. Instead, it checks for events periodically
+ * (or not, if SIGPOLL can be used instead) and processes them in
+ * a subroutine called by the page drawing routine. This routine (below)
+ * checks to see if anything has happened and processes those events and
+ * signals. (Or, if it is called when there is no redrawing that needs
+ * to be done, it blocks until something happens.)
+ *
+ * Ultimately, the goal is to have this be the only place in xdvi where
+ * blocking occurs.
+ *
+ * The argument to this function should be a mask of event types (EV_*)
+ * indicating which event types should cause read_events to return instead
+ * of waiting for more events. This function will always process all
+ * pending events and signals before returning.
+ * The return value is the value of ev_flags.
+ */
+
+unsigned int
+read_events(ret_mask)
+ unsigned int ret_mask;
+{
+ XEvent event;
+
+#if !HAVE_POLL
+ if (numfds == 0) numfds = ConnectionNumber(DISP) + 1;
+#endif
+
+ for (;;) {
+ event_counter = event_freq;
+ /*
+ * The above line clears the flag indicating that an event is
+ * pending. So if an event comes in right now, the flag will be
+ * set again needlessly, but we just end up making an extra call.
+ * Also, be careful about destroying the magnifying glass while
+ * drawing on it.
+ */
+
+#if !FLAKY_SIGPOLL
+
+ if (event_freq < 0) { /* if SIGPOLL works */
+
+ if (!XtPending()) {
+ sigset_t oldsig;
+
+ (void) sigprocmask(SIG_BLOCK, &all_signals, &oldsig);
+ for (;;) {
+ while (sig_flags)
+ flags_to_sigproc[sig_flags]();
+
+ if (XtPending())
+ break;
+
+ if (ev_flags & ret_mask) {
+ (void) sigprocmask(SIG_SETMASK, &oldsig,
+ (sigset_t *) NULL);
+ return ev_flags;
+ }
+ (void) sigsuspend(&oldsig);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsig, (sigset_t *) NULL);
+ }
+ }
+ else
+
+#endif /* not FLAKY_SIGPOLL */
+
+ {
+ for (;;) {
+ struct xio *ip;
+
+ while (sig_flags) {
+ sigset_t oldsig;
+
+ (void) sigprocmask(SIG_BLOCK, &all_signals, &oldsig);
+
+ while (sig_flags)
+ flags_to_sigproc[sig_flags]();
+
+ (void) sigprocmask(SIG_SETMASK, &oldsig,
+ (sigset_t *) NULL);
+ }
+
+ if (XtPending())
+ break;
+
+ if (ev_flags & ret_mask)
+ return ev_flags;
+
+ /* If a SIGUSR1 signal comes right now, then it will wait
+ until an X event or another SIGUSR1 signal arrives. */
+
+#if HAVE_POLL
+ if (io_dirty) {
+ struct pollfd *fp;
+
+ if (num_fds > max_fds) {
+ if (fds != NULL) free(fds);
+ fds = xmalloc(num_fds * sizeof *fds);
+ max_fds = num_fds;
+ fds->fd = ConnectionNumber(DISP);
+ fds->events = POLLIN;
+ }
+ fp = fds + 1;
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ fp->fd = ip->fd;
+ fp->events = ip->xio_events;
+ ip->pfd = fp;
+ ++fp;
+ }
+ io_dirty = False;
+ }
+
+ for (;;) {
+ if (poll(fds, num_fds, -1) >= 0) {
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ int revents = ip->pfd->revents;
+
+ if (revents & POLLIN) (ip->read_proc)();
+ if (revents & POLLOUT) (ip->write_proc)();
+ }
+ break;
+ }
+
+ if (errno == EINTR)
+ break;
+
+ if (errno != EAGAIN) {
+ perror("xdvi: poll");
+ break;
+ }
+ }
+#else
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_SET(ConnectionNumber(DISP), &readfds);
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (ip->xio_events & XIO_IN)
+ FD_SET(ip->fd, &readfds);
+ if (ip->xio_events & XIO_OUT)
+ FD_SET(ip->fd, &writefds);
+ }
+
+ for (;;) {
+ if (select(numfds, &readfds, &writefds, (fd_set *) NULL,
+ (struct timeval *) NULL) >= 0) {
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (FD_ISSET(ip->fd, &readfds))
+ (ip->read_proc)();
+ if (FD_ISSET(ip->fd, &writefds))
+ (ip->write_proc)();
+ }
+ break;
+ }
+
+ if (errno == EINTR)
+ break;
+
+ if (errno != EAGAIN) {
+ perror("xdvi: select");
+ break;
+ }
+ }
+#endif
+ }
+ }
+
+#if TOOLKIT
+
+ XtNextEvent(&event);
+ if (resized) get_geom();
+ if (event.xany.window == alt.win && event.type == Expose) {
+ handle_expose((Widget) NULL, (XtPointer) &alt, &event,
+ (Boolean *) NULL);
+ continue;
+ }
+ (void) XtDispatchEvent(&event);
+
+#else /* not TOOLKIT */
+
+ XNextEvent(DISP, &event);
+ if (event.xany.window == mane.win || event.xany.window == alt.win) {
+ struct WindowRec *wr = &mane;
+
+ if (event.xany.window == alt.win) {
+ wr = &alt;
+ /* check in case we already destroyed the window */
+ if (alt_stat < 0) { /* destroy upon exposure */
+ alt_stat = 0;
+ mag_release(&event);
+ continue;
+ }
+ else
+ alt_stat = 0;
+ }
+ switch (event.type) {
+ case GraphicsExpose:
+ case Expose:
+ expose(wr, event.xexpose.x, event.xexpose.y,
+ event.xexpose.width, event.xexpose.height);
+ break;
+
+ case ButtonPress:
+ if (resource.wheel_unit != 0 && (event.xbutton.button == 4
+ || event.xbutton.button == 5))
+ Act_wheel(&event);
+ else if (resource.wheel_unit != 0
+ && (event.xbutton.button == 6
+ || event.xbutton.button == 7))
+ Act_hwheel(&event);
+ else if (event.xbutton.state & ControlMask) {
+ switch (event.xbutton.button) {
+ case 1: Act_source_special(&event); break;
+ case 2: Act_show_source_specials(&event); break;
+ case 3: Act_show_all_boxes(&event); break;
+ }
+ }
+ else if (event.xbutton.state & ShiftMask)
+ Act_drag(&event);
+ else
+ Act_magnifier(&event);
+ break;
+
+ case MotionNotify:
+ mouse_motion(&event);
+ break;
+
+ case ButtonRelease:
+ if (event.xbutton.button == wheel_button)
+ wheel_button = -1;
+ else if (event.xbutton.button == wheel_h_button)
+ wheel_h_button = -1;
+ else
+ mouse_release(&event);
+ break;
+ } /* end switch */
+ } /* end if window == {mane,alt}.win */
+
+ else if (event.xany.window == x_bar) {
+ if (event.type == Expose)
+ XFillRectangle(DISP, x_bar, copyGC,
+ x_bgn, 1, x_end - x_bgn, BAR_WID);
+ else if (event.type == MotionNotify)
+ scrollmane(event.xmotion.x * page_w / clip_w,
+ mane.base_y);
+ else switch (event.xbutton.button)
+ {
+ case 1:
+ scrollmane(mane.base_x + event.xbutton.x, mane.base_y);
+ break;
+ case 2:
+ scrollmane(event.xbutton.x * page_w / clip_w,
+ mane.base_y);
+ break;
+ case 3:
+ scrollmane(mane.base_x - event.xbutton.x, mane.base_y);
+ }
+ }
+
+ else if (event.xany.window == y_bar) {
+ if (event.type == Expose)
+ XFillRectangle(DISP, y_bar, copyGC,
+ 1, y_bgn, BAR_WID, y_end - y_bgn);
+ else if (event.type == MotionNotify)
+ scrollmane(mane.base_x,
+ event.xmotion.y * page_h / clip_h);
+ else switch (event.xbutton.button)
+ {
+ case 1:
+ scrollmane(mane.base_x, mane.base_y + event.xbutton.y);
+ break;
+ case 2:
+ scrollmane(mane.base_x,
+ event.xbutton.y * page_h / clip_h);
+ break;
+ case 3:
+ scrollmane(mane.base_x, mane.base_y - event.xbutton.y);
+ }
+ }
+
+ else if (event.xany.window == top_level)
+ switch (event.type) {
+ case ConfigureNotify:
+ if (event.xany.window == top_level &&
+ (event.xconfigure.width != window_w ||
+ event.xconfigure.height != window_h)) {
+ Window old_mane_win = mane.win;
+
+ window_w = event.xconfigure.width;
+ window_h = event.xconfigure.height;
+ reconfig();
+ if (old_mane_win == (Window) 0) {
+ ev_flags |= EV_NEWPAGE;
+ home_action = home;
+ }
+ }
+ break;
+
+ case MapNotify: /* if running w/o WM */
+ if (mane.win == (Window) 0) {
+ reconfig();
+ ev_flags |= EV_NEWPAGE;
+ home_action = home;
+ }
+ break;
+
+ case KeyPress:
+ {
+#define TRSIZE 4
+
+ char trbuf[TRSIZE];
+
+ if (XLookupString(&event.xkey, trbuf, TRSIZE,
+ (KeySym *) NULL, (XComposeStatus *) NULL) == 1
+ && (keychar = *trbuf) < 128)
+ (actions[keychar])(&event);
+ }
+ break;
+
+ case PropertyNotify:
+ handle_property_change(&event);
+ break;
+ }
+
+#endif /* not TOOLKIT */
+
+ }
+}
+
+
+/*
+ * Higher-level routines for managing events.
+ */
+
+static void
+can_exposures(windowrec)
+ struct WindowRec *windowrec;
+{
+ windowrec->min_x = windowrec->min_y = MAXDIM;
+ windowrec->max_x = windowrec->max_y = 0;
+}
+
+static void
+redraw(windowrec)
+ struct WindowRec *windowrec;
+{
+
+ currwin = *windowrec;
+ min_x = currwin.min_x + currwin.base_x;
+ min_y = currwin.min_y + currwin.base_y;
+ max_x = currwin.max_x + currwin.base_x;
+ max_y = currwin.max_y + currwin.base_y;
+ can_exposures(windowrec);
+
+ if (debug & DBG_EVENT)
+ Printf("Redraw %d x %d at (%d, %d) (base=%d,%d)\n", max_x - min_x,
+ max_y - min_y, min_x, min_y, currwin.base_x, currwin.base_y);
+
+ if (!(ev_flags & EV_CURSOR)) {
+ if (!dragcurs) {
+ XDefineCursor(DISP, CURSORWIN, redraw_cursor);
+ XFlush(DISP);
+ }
+ ev_flags |= EV_CURSOR;
+ }
+
+ draw_page();
+ warn_spec_now = False;
+}
+
+static void
+redraw_page()
+{
+#if COLOR
+ _Xconst struct rgb *rgbp;
+#endif
+
+ if (debug & DBG_EVENT) Fputs("Redraw page: ", stdout);
+
+ if (scanned_page < current_page) {
+ if (!check_dvi_file())
+ return;
+ prescan();
+ if (ev_flags & EV_GE_NEWPAGE) /* if we need to re-prescan */
+ return;
+ }
+
+ if (page_info[current_page].ww != unshrunk_page_w
+ || page_info[current_page].wh != unshrunk_page_h) {
+ init_page();
+ reconfig();
+ }
+
+ /* We can't call home() without proper unshrunk_page_*, which requires
+ * prescan(), which can't be done from within read_events() */
+
+ if (home_action != NULL) {
+ if (!resource.keep_flag)
+ home_action(False);
+ home_action = NULL;
+#if PS_GS
+ if (gs_postpone_prescan) {
+ if (!setjmp(canit_env))
+ gs_resume_prescan();
+ else
+ return;
+ }
+#endif
+#if TOOLKIT
+ /* This discards the expose event generated by home() */
+ if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE)
+ return;
+ can_exposures(&mane);
+#endif
+ }
+
+#if COLOR
+ rgbp = &bg_initial;
+ if (page_colors != NULL)
+ rgbp = &page_colors[current_page].bg;
+
+ /* Set background color */
+ if (bg_current == NULL
+ || rgbp->r != bg_current->color.r
+ || rgbp->g != bg_current->color.g
+ || rgbp->b != bg_current->color.b) {
+ struct bgrec **bgpp;
+
+ for (bgpp = &bg_head;;) {
+ bg_current = *bgpp;
+ if (bg_current == NULL) { /* if bg is not in list */
+ bg_current = *bgpp = xmalloc(sizeof *bg_current);
+ bg_current->next = NULL;
+ bg_current->color = *rgbp;
+ bg_current->fg_head = NULL;
+ bg_current->pixel_good = False;
+ break;
+ }
+ if (bg_current->color.r == rgbp->r
+ && bg_current->color.g == rgbp->g
+ && bg_current->color.b == rgbp->b)
+ break;
+ bgpp = &bg_current->next;
+ }
+ fg_current = NULL; /* force change of foreground color */
+ /* highGC is only used in XDrawRectangle, so its background color
+ doesn't need to be changed. */
+ if (debug & DBG_DVI)
+ printf("Changing background color to %5d %5d %5d\n",
+ bg_current->color.r, bg_current->color.g,
+ bg_current->color.b);
+
+ if (!bg_current->pixel_good) {
+ bg_current->pixel = alloc_color(&bg_current->color,
+ back_color_data.pixel);
+ bg_current->pixel_good = True;
+ }
+ XSetWindowBackground(DISP, mane.win, bg_current->pixel);
+
+ bg_Color.pixel = bg_current->pixel;
+ XQueryColor(DISP, our_colormap, &bg_Color);
+ XRecolorCursor(DISP, ready_cursor, &cr_Color, &bg_Color);
+ XRecolorCursor(DISP, redraw_cursor, &cr_Color, &bg_Color);
+ }
+#endif /* COLOR */
+
+ dvi_file_ready = True;
+
+ XClearWindow(DISP, mane.win);
+ if (backing_store != NotUseful) {
+ mane.min_x = mane.min_y = 0;
+ mane.max_x = page_w;
+ mane.max_y = page_h;
+ }
+ else {
+ get_xy();
+ mane.min_x = -window_x;
+ mane.max_x = -window_x + clip_w;
+ mane.min_y = -window_y;
+ mane.max_y = -window_y + clip_h;
+ }
+ redraw(&mane);
+}
+
+void
+do_pages()
+{
+ if (debug & DBG_BATCH) {
+ int i;
+
+ (void) read_events(EV_GT_IDLE);
+
+ for (i = 0; i < total_pages; ++i) {
+ goto_page(i, home);
+#if PS_GS
+ for (;;) {
+ redraw_page();
+ (void) read_events(EV_NOWAIT);
+ if (!(ev_flags & (EV_NEWPAGE | EV_NEWDOC))) break;
+ ev_flags = EV_IDLE;
+ }
+#else
+ redraw_page();
+#endif
+ }
+
+ xdvi_exit(0);
+ }
+ else
+ for (;;) { /* normal operation */
+
+ (void) read_events(EV_GT_IDLE);
+
+ if (ev_flags & (EV_NEWPAGE | EV_NEWDOC | EV_PS_TOGGLE)) {
+ ev_flags &= ~(EV_NEWPAGE | EV_EXPOSE | EV_PS_TOGGLE);
+ if (ev_flags & EV_NEWDOC) {
+ ev_flags &= ~EV_NEWDOC;
+ reload_dvi_file();
+ }
+ can_exposures(&mane);
+ can_exposures(&alt);
+
+ if (dvi_file != NULL)
+ redraw_page();
+ else
+ (void) check_dvi_file();
+ }
+
+ else if (ev_flags & EV_SRC) {
+ /* Source special operations are deferred to here because
+ * they call geom_scan(), which may call define_font(),
+ * which may call makefont(), which may call read_events()
+ * recursively.
+ */
+ if (!check_dvi_file())
+ /* if dvi file is corrupted or has changed */
+ continue;
+
+ ev_flags &= ~EV_SRC;
+ if (source_forward_string != NULL) {
+ _Xconst char *s = source_forward_string;
+
+ source_forward_string = NULL;
+ source_forward_search(s);
+ }
+ else if (source_reverse_x != -1)
+ source_reverse_search(source_reverse_x,
+ source_reverse_y);
+ else source_special_show(source_show_all);
+ }
+
+ else if (ev_flags & EV_MAG_MOVE) {
+ if (alt.win == (Window) 0) ev_flags &= ~EV_MAG_MOVE;
+ else if (abs(new_mag_x - mag_x) >
+ 2 * abs(new_mag_y - mag_y))
+ movemag(new_mag_x, mag_y);
+ else if (abs(new_mag_y - mag_y) >
+ 2 * abs(new_mag_x - mag_x))
+ movemag(mag_x, new_mag_y);
+ else movemag(new_mag_x, new_mag_y);
+ }
+
+ else if (ev_flags & EV_EXPOSE) {
+ if (alt.min_x < MAXDIM) {
+ if (mane.min_x >= MAXDIM) ev_flags &= ~EV_EXPOSE;
+ redraw(&alt);
+ }
+ else {
+ ev_flags &= ~EV_EXPOSE;
+ if (mane.min_x < MAXDIM)
+ redraw(&mane);
+ }
+ }
+
+ else if (ev_flags & EV_CURSOR) {
+ /*
+ * This code eliminates unnecessary calls to XDefineCursor,
+ * since this is a slow operation on some hardware
+ * (e.g., S3 chips).
+ */
+ XSync(DISP, False);
+ if (!XtPending()) {
+ ev_flags &= ~EV_CURSOR;
+ if (!dragcurs)
+ XDefineCursor(DISP, CURSORWIN, ready_cursor);
+ }
+ }
+
+ XFlush(DISP);
+ }
+}
+
+
+#if MOTIF_TIMERS
+
+/*
+ * Newer versions of the Motif toolkit use the timer facility
+ * (XtAppAddTimeOut(), etc.) in the X Toolkit. Proper functioning of
+ * this mechanism, however, requires that the X Toolkit be in charge of
+ * blocking. Since xdvi does its own blocking, this means that we need
+ * to provide working alternatives to these X Toolkit routines.
+ * One symptom of the above-mentioned bug is that the printlog window
+ * eventually stops showing dvips progress until you move the mouse.
+ */
+
+static void xt_alarm ARGS((struct xtimer *));
+
+static struct xtimer *xt_free_timers = NULL;
+
+
+XtIntervalId
+XtAppAddTimeOut(app, interval, proc, closure)
+ XtAppContext app;
+ unsigned long interval;
+ XtTimerCallbackProc proc;
+ XtPointer closure;
+{
+ struct xtimer *tp;
+
+ if (xt_free_timers == NULL)
+ tp = xmalloc(sizeof *tp);
+ else {
+ tp = xt_free_timers;
+ xt_free_timers = xt_free_timers->next;
+ }
+
+ tp->proc = xt_alarm;
+ tp->xt_proc = proc;
+ tp->closure = closure;
+
+ set_timer(tp, interval);
+
+ return (XtIntervalId) tp;
+}
+
+void
+XtRemoveTimeOut(id)
+ XtIntervalId id;
+{
+ struct xtimer *tp;
+
+ tp = (struct xtimer *) id;
+
+ /* Motif (Solaris 9, 2003) sometimes calls XtRemoveTimeOut() after
+ the timer event has occurred, so we need to be sure not to remove
+ the timer record twice. */
+ if (tp->proc == NULL)
+ return;
+
+ cancel_timer(tp);
+
+ tp->next = xt_free_timers;
+ xt_free_timers = tp;
+}
+
+void
+xt_alarm(tp)
+ struct xtimer *tp;
+{
+ XtIntervalId id;
+
+ tp->proc = NULL; /* flag timer as used-up */
+ id = (XtIntervalId) tp;
+ (tp->xt_proc)(tp->closure, &id);
+
+ tp->next = xt_free_timers;
+ xt_free_timers = tp;
+}
+
+#endif /* MOTIF_TIMERS */
diff --git a/filefind.c b/filefind.c
@@ -0,0 +1,2867 @@
+/*========================================================================*\
+
+Copyright (c) 1996-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * filefind.c - Routines to perform file searches.
+ */
+
+/*
+ * We assume that "filf-app.h" includes the following, if appropriate:
+ *
+ * <stdlib.h>
+ * <unistd.h>
+ * <string.h>
+ * <memory.h>
+ * <sys/types.h>
+ * <sys/stat.h>
+ * <setjmp.h>
+ * <pwd.h>
+ */
+
+#include "filf-app.h" /* application-related declarations & defs */
+#include "filefind.h"
+
+#ifndef XtNumber
+#define XtNumber(array) (sizeof(array) / sizeof(*array))
+#endif
+
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+#ifndef ST_NLINK_TRICK
+#if defined(VMS)
+#define ST_NLINK_TRICK 0
+#else
+#define ST_NLINK_TRICK 1
+#endif
+#endif /* !defined(ST_NLINK_TRICK) */
+
+extern char *xstrdup ARGS((_Xconst char *));
+extern char *xmemdup ARGS((_Xconst char *, size_t));
+
+ /* These are defined so that the editor can match braces properly. */
+#define LBRACE '{'
+#define RBRACE '}'
+
+ /* In configuration files, semicolons are also valid separators. */
+#if CFGFILE
+#define IS_SEP(c) ((c) == ':' || (c) == ';')
+#else
+#define IS_SEP(c) ((c) == ':')
+#endif
+
+/* Local copy of findrec record. */
+
+static struct findrec lrec;
+
+/*
+ * Additional data structures.
+ */
+
+struct statrec { /* status vis-a-vis laying down the file name */
+ unsigned pos; /* position in ffline */
+ int flags;
+ char quickchar; /* '\0' or 'q' or 'Q' */
+ unsigned quickpos; /* value of pos (above) if 'q' or 'Q' */
+};
+
+struct texmfrec { /* list of texmf components */
+ struct texmfrec *next;
+ _Xconst char *home;
+ _Xconst char *str;
+ int len;
+ int flags;
+};
+
+#if !CFGFILE
+static _Xconst char default_texmf_path[] = DEFAULT_TEXMF_PATH;
+#endif
+
+/* These are global variables. */
+
+_Xconst char *fF_values[MAX_N_OPTS]; /* not static */
+
+static FILE *file_found;
+static jmp_buf got_it;
+static struct steprec **bracepp;
+static struct steprec **steppp;
+static struct findrec *frecp; /* used to distinguish ls-Rs */
+static int seqno;
+static struct texmfrec *texmfhead = NULL;
+static struct rootrec **rootpp;
+static _Xconst struct atomrec *treeatom;
+#if USE_GF
+static int gflags; /* global flags */
+static Boolean pk_second_pass;
+#endif
+
+ /* dummy records for handling %s after // or wild cards */
+static struct atomrec pct_s_dummy = {NULL, NULL, NULL, F_PCT_S};
+static struct atomrec pct_s_dummy_slash
+ = {NULL, NULL, NULL, F_PCT_S | F_SLASH_SLASH};
+
+ /* flag value for directories not read yet */
+static struct treerec not_read_yet = {NULL, NULL, NULL};
+
+/*
+ * The following expands in 128-byte increments to be as long as is
+ * necessary. We don't often use pointers to refer to elements of this
+ * array, since it may move when it is enlarged.
+ */
+
+#if !EXTERN_FFLINE
+static char *ffline = NULL;
+static int ffline_len = 0; /* current length of the array */
+#endif
+
+
+/*
+ * ls-R database hash table
+ */
+
+struct lsr {
+ struct lsr *next; /* next in hash chain */
+ struct findrec *frecp; /* which search type? */
+ short seqno; /* which ls-R invocation we are using */
+ short keylen; /* length of key */
+ _Xconst char *key;
+ _Xconst char *value;
+};
+
+static struct lsr *lsrtab[1024]; /* hash table */
+
+
+/*
+ * Forward references.
+ */
+
+static void dobrace();
+static struct steprec *scan_pct_s();
+static void atomize_pct_s();
+
+
+#if !EXTERN_FFLINE
+
+/*
+ * Expand ffline[] to at least the given size.
+ */
+
+static void
+expandline(n)
+ int n;
+{
+ int newlen = n + 128;
+
+ ffline = (ffline == NULL) ? xmalloc(newlen) : xrealloc(ffline, newlen);
+ ffline_len = newlen;
+}
+
+#endif /* !EXTERN_FFLINE */
+
+
+/*
+ * prehash() - hash function (before modding).
+ */
+
+static unsigned int
+prehash(str, len)
+ _Xconst char *str;
+ size_t len;
+{
+ _Xconst char *p;
+ unsigned int hash;
+
+ hash = 0;
+ for (p = str + len; p > str; )
+ hash = hash * 5 + *--p;
+ return hash;
+}
+
+
+#if !EXTERN_GETPW
+
+/*
+ * Look up the home directory.
+ */
+
+static _Xconst struct passwd *
+ff_getpw(pp, p_end)
+ _Xconst char **pp;
+ _Xconst char *p_end;
+{
+ _Xconst char *p = *pp;
+ _Xconst char *p1;
+ int len;
+ _Xconst struct passwd *pw;
+
+ ++p; /* skip the tilde */
+ p1 = p;
+ while (p1 < p_end && *p1 != '/') ++p1;
+ len = p1 - p;
+ if (len == 0) /* if no user name */
+ pw = getpwuid(getuid());
+ else {
+ if (len >= ffline_len)
+ expandline(len);
+ bcopy(p, ffline, len);
+ ffline[len] = '\0';
+ pw = getpwnam(ffline);
+ }
+ if (pw != NULL)
+ *pp = p1;
+ return pw;
+}
+
+#endif /* !EXTERN_GETPW */
+
+
+static void
+gethome(pp, p_end, homepp)
+ _Xconst char **pp;
+ _Xconst char *p_end;
+ _Xconst char **homepp;
+{
+ _Xconst struct passwd *pw;
+
+ pw = ff_getpw(pp, p_end);
+ if (pw != NULL)
+ *homepp = xstrdup(pw->pw_dir);
+}
+
+
+#if CFGFILE
+
+/*
+ * index() for next path separator. Return pointer to next path separator
+ * or to end of string if none. Never return NULL.
+ */
+
+static _Xconst char *
+sep_index(p)
+ _Xconst char *p;
+{
+ int len;
+ _Xconst char *p1;
+ _Xconst char *p2;
+
+ len = strlen(p);
+ p1 = memchr(p, ':', len);
+ if (p1 == NULL) p1 = p + len;
+ p2 = memchr(p, ';', p1 - p);
+ return (p2 != NULL ? p2 : p1);
+}
+
+
+/*
+ * Configuration file routines.
+ */
+
+struct envrec *envtab[128]; /* hash table for local environment */
+
+struct cfglist { /* linked list of config files we've done */
+ struct cfglist *next;
+ _Xconst char *value;
+};
+
+struct cfglist *cfghead; /* head of that linked list */
+
+/* global stuff for the fancy loop over config files. */
+
+static _Xconst struct envrec *lastvar = NULL;
+static _Xconst char *deflt = DEFAULT_CONFIG_PATH;
+
+/*
+ * Get the node containing a local environment variable.
+ */
+
+struct envrec *
+ffgetenv(key)
+ _Xconst char *key;
+{
+ int keylen;
+ struct envrec *envp;
+
+ keylen = strlen(key);
+ envp = envtab[prehash(key, keylen) % XtNumber(envtab)];
+ ++keylen;
+ for (;;) {
+ if (envp == NULL ||
+ (envp->key != NULL && memcmp(envp->key, key, keylen) == 0))
+ break;
+ envp = envp->next;
+ }
+
+ if (FFDEBUG)
+ printf("ffgetenv(%s) --> %s\n", key,
+ (envp != NULL && envp->value != NULL) ? envp->value : "none");
+
+ return envp;
+}
+
+
+/*
+ * Store the value of a local environment variable.
+ */
+
+static void
+ffputenv(key, keylen, value, flag)
+ _Xconst char *key;
+ int keylen;
+ _Xconst char *value;
+ Boolean flag;
+{
+ struct envrec **envpp;
+ struct envrec *envp;
+ _Xconst char *key1;
+
+ envpp = envtab + prehash(key, keylen) % XtNumber(envtab);
+ ++keylen;
+ for (;;) { /* loop to find the key in the hash chain */
+ envp = *envpp;
+ if (envp == NULL) { /* if no existing entries */
+ key1 = xmemdup(key, keylen);
+ break;
+ }
+ if (envp->key != NULL && memcmp(key, envp->key, keylen) == 0) {
+ /* skip to the end of the chain of identical keys */
+ while (envp->next != NULL && envp->next->key == NULL)
+ envp = envp->next;
+ /* If we already defined this variable this time around. */
+ if (envp->flag)
+ return;
+ /* If this is a getenv() placeholder. */
+ if (envp->value == NULL) {
+ envp->value = value;
+ envp->flag = flag;
+ return;
+ }
+ envpp = &envp->next;
+ key1 = NULL;
+ break;
+ }
+ envpp = &envp->next;
+ }
+
+ envp = xmalloc(sizeof(*envp));
+ envp->next = *envpp;
+ envp->key = key1;
+ envp->value = value;
+ envp->flag = flag;
+ *envpp = envp;
+}
+
+
+#ifdef SELFAUTO
+
+ /* contains values of SELFAUTOLOC, SELFAUTODIR, and SELFAUTOPARENT */
+static _Xconst char *selfautostr = NULL;
+static int selfautoloclen;
+static int selfautodirlen;
+static int selfautoparentlen;
+
+/*
+ * Resolve a symlink. Returns the length of the new string.
+ */
+
+static int
+getrealname(pos, len)
+ int pos; /* position in ffline[] of beginning of filename */
+ int len; /* length of string in ffline[] */
+{
+ struct stat statbuf;
+ char *buffer;
+ int bufsize;
+ char *buf1;
+ int pos1;
+ int len1;
+
+ for (;;) { /* loop over symlinks in chain */
+ if (lstat(ffline + pos, &statbuf) != 0) {
+ perror(ffline + pos);
+ return len;
+ }
+ if (!S_ISLNK(statbuf.st_mode))
+ break;
+ buffer = xmalloc(statbuf.st_size + 1);
+ bufsize = readlink(ffline + pos, buffer, statbuf.st_size + 1);
+ if (bufsize < 0 || bufsize > statbuf.st_size) {
+ perror(ffline + pos);
+ return len;
+ }
+ buffer[bufsize] = '\0';
+ buf1 = buffer;
+ if (buffer[0] == '/') /* if absolute path, just replace */
+ pos1 = pos; /* copy it to the beginning */
+ else {
+ pos1 = pos + len;
+ /* find preceding slash */
+ while (pos1 > pos && ffline[--pos1] != '/') ;
+ /* get rid of multiple slashes */
+ while (pos1 > pos && ffline[pos1 - 1] == '/') --pos1;
+ for (;;) {
+ if (buf1[0] == '.' && buf1[1] == '/')
+ buf1 += 2;
+ else if (buf1[0] == '.' && buf1[1] == '.' && buf1[2] == '/')
+ {
+ buf1 += 3;
+ ffline[pos1] = '\0';
+ pos1 = getrealname(pos, pos1 - pos) + pos;
+ /* back up to preceding slash */
+ while (pos1 > pos && ffline[--pos1] != '/') ;
+ /* get rid of multiple slashes */
+ while (pos1 > pos && ffline[pos1 - 1] == '/') --pos1;
+ }
+ else break;
+ while (*buf1 == '/') ++buf1;
+ }
+ ++pos1; /* put the slash back */
+ }
+ len1 = buffer + bufsize + 1 - buf1;
+ if (pos1 + len1 >= ffline_len)
+ expandline(pos1 + len1);
+ bcopy(buf1, ffline + pos1, len1);
+ free(buffer);
+ len = pos1 + len1 - pos - 1;
+ }
+ return len;
+}
+
+
+/*
+ * Initialize SELFAUTOLOC, SELFAUTODIR, and SELFAUTOPARENT.
+ */
+
+static void
+selfautoinit(pos)
+ int pos;
+{
+ _Xconst char *p;
+ int len;
+ _Xconst char *path;
+ int argv0len;
+ int pos1;
+ struct stat statbuf;
+
+ if (index(argv0, '/') != NULL) { /* if program was called directly */
+ len = strlen(argv0) + 1;
+ if (pos + len >= ffline_len)
+ expandline(pos + len);
+ bcopy(argv0, ffline + pos, len);
+ --len;
+ }
+ else { /* try to find it in $PATH */
+ path = getenv("PATH");
+ argv0len = strlen(argv0) + 1;
+ len = 0;
+ if (path != NULL)
+ for (;;) {
+ p = sep_index(path);
+ len = p - path;
+ pos1 = pos + len;
+ if (pos + len + argv0len >= ffline_len)
+ expandline(pos + len + argv0len);
+ bcopy(path, ffline + pos, len);
+ ffline[pos1] = '/';
+ bcopy(argv0, ffline + pos1 + 1, argv0len);
+ len += argv0len;
+ if (stat(ffline + pos, &statbuf) == 0
+ && S_ISREG(statbuf.st_mode)
+ && (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ break;
+ if (*p == '\0') {
+ len = 0;
+ break;
+ }
+ path = p + 1;
+ }
+ }
+
+ /* Now we have: file name starting in ffline[pos], and len = length. */
+
+ len = getrealname(pos, len);
+ p = ffline + pos + len;
+ while (p > ffline + pos && *--p != '/') ;
+ selfautoloclen = p - (ffline + pos);
+ selfautostr = xmemdup(ffline + pos, selfautoloclen);
+ p = selfautostr + selfautoloclen;
+ while (p > selfautostr && *--p != '/') ;
+ selfautodirlen = p - selfautostr;
+ while (p > selfautostr && *--p != '/') ;
+ selfautoparentlen = p - selfautostr;
+
+ if (FFDEBUG) {
+ fputs("SELFAUTOLOC = ", stdout);
+ fwrite(selfautostr, 1, selfautoloclen, stdout);
+ fputs("\nSELFAUTODIR = ", stdout);
+ fwrite(selfautostr, 1, selfautodirlen, stdout);
+ fputs("\nSELFAUTOPARENT = ", stdout);
+ fwrite(selfautostr, 1, selfautoparentlen, stdout);
+ putchar('\n');
+ }
+}
+
+#endif /* SELFAUTO */
+
+
+/*
+ * Do a dollar substitution of this variable. Return position in ffline.
+ */
+
+static int envexpand();
+
+static int
+dollarsub(key, keylen, pos, percent)
+ _Xconst char *key;
+ int keylen;
+ int pos;
+ char percent;
+{
+ _Xconst char *env_value;
+ struct envrec *env_rec;
+
+#ifdef SELFAUTO
+ if (keylen >= 11 && memcmp(key, "SELFAUTO", 8) == 0
+ && ((keylen == 11
+ && (memcmp(key + 8, "LOC", 3) == 0 || memcmp(key + 8, "DIR", 3) == 0))
+ || (keylen == 14 && memcmp(key + 8, "PARENT", 6) == 0))) {
+ int len;
+
+ if (selfautostr == NULL)
+ selfautoinit(pos);
+ len = (keylen != 11 ? selfautoparentlen
+ : key[8] == 'L' ? selfautoloclen : selfautodirlen);
+ if (pos + len >= ffline_len)
+ expandline(pos + len);
+ bcopy(selfautostr, ffline + pos, len);
+ return pos + len;
+ }
+#endif
+
+ if (pos + keylen >= ffline_len)
+ expandline(pos + keylen);
+ bcopy(key, ffline + pos, keylen);
+ ffline[pos + keylen] = '\0';
+ env_value = getenv(ffline + pos);
+ env_rec = ffgetenv(ffline + pos);
+ if (env_rec == NULL)
+ if (env_value == NULL)
+ return pos; /* no value found */
+ else { /* create a placeholder record */
+ ffputenv(ffline + pos, keylen, NULL, False);
+ env_rec = ffgetenv(ffline + pos);
+ }
+
+ if (env_rec->flag) /* if recursive call */
+ return pos;
+ if (env_value == NULL) env_value = env_rec->value;
+ env_rec->flag = True;
+ pos = envexpand(env_value, env_value + strlen(env_value), pos, percent);
+ env_rec->flag = False;
+ return pos;
+}
+
+
+/*
+ * Expand all environment references in a string and add the result to
+ * ffline. Return the length of ffline.
+ */
+
+static int
+envexpand(p, p_end, pos, percent)
+ _Xconst char *p;
+ _Xconst char *p_end;
+ int pos;
+ char percent;
+{
+ _Xconst char *p1;
+ _Xconst char *p2;
+
+ for (;;) { /* transfer this to ffline */
+ for (p2 = p;;) { /* find the next $ */
+ _Xconst char *p3;
+
+ p1 = memchr(p2, '$', p_end - p);
+ if (p1 == NULL) {
+ p1 = p_end;
+ break;
+ }
+ p3 = p1;
+ while (p3-- > p2 && *p3 == percent) ;
+ /* if preceded by an even number of percents */
+ if ((p3 - p1) % 2 != 0)
+ break;
+ p2 = p1 + 1;
+ }
+ if (p1 > p) {
+ if (pos + (p1 - p) >= ffline_len)
+ expandline(pos + (p1 - p));
+ bcopy(p, ffline + pos, p1 - p);
+ pos += p1 - p;
+ }
+ if (p1 >= p_end)
+ break;
+ ++p1;
+ if (*p1 == LBRACE) {
+ ++p1;
+ for (p = p1;; ++p) {
+ if (p >= p_end) /* if syntax error */
+ break;
+ if (*p == RBRACE) {
+ pos = dollarsub(p1, p - p1, pos, percent);
+ ++p;
+ break;
+ }
+ }
+ }
+ else {
+ p = p1;
+ while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')
+ || (*p >= '0' && *p <= '9') || *p == '_')
+ ++p;
+ pos = dollarsub(p1, p - p1, pos, percent);
+ }
+ }
+ return pos;
+}
+
+
+/*
+ * Do all expansions up to the next colon or '\0'.
+ */
+
+static int
+form_path_part(pathpp, percent)
+ _Xconst char **pathpp;
+ char percent;
+{
+ _Xconst char *path;
+ _Xconst char *p;
+ _Xconst char *p_end;
+ int pos;
+
+ path = *pathpp;
+ p_end = p;
+ for (p = path;;) { /* find end of path part */
+ _Xconst char *p1;
+
+ p_end = sep_index(p);
+ if (*p_end == '\0')
+ break;
+ p1 = p_end;
+ while (p1 > p && *--p1 == percent) ;
+ /* if preceded by an even number of percents */
+ if ((p_end - p1) % 2 != 0)
+ break;
+ p = p_end + 1;
+ }
+ *pathpp = p_end;
+
+ return envexpand(path, p_end, 0, percent);
+}
+
+/*
+ * Read a config file.
+ */
+
+static void
+read_config_file(f)
+ FILE *f;
+{
+ int pos;
+ char *p;
+ char *keybegin, *keyend, *valend;
+ struct envrec *envp;
+ struct envrec **envpp;
+
+ for (;;) { /* loop over input lines */
+
+ /*
+ * Read a line into ffline[]. It can be arbitrarily long.
+ * We may assume here that ffline_len > 0 since ffline[] was used
+ * to hold the full name of the config file.
+ */
+
+ pos = 0;
+ for (;;) {
+ int len;
+
+ if (fgets(ffline + pos, ffline_len - pos, f) == NULL) break;
+ len = strlen(ffline + pos);
+ if (len == 0) break;
+ pos += len;
+ if (ffline[pos - 1] == '\n')
+ break;
+ if (pos + 2 >= ffline_len)
+ expandline(pos);
+ }
+
+ if (pos == 0) break; /* if end of file */
+
+ if (ffline[pos - 1] == '\n') /* trim off trailing \n */
+ ffline[--pos] = '\0';
+
+ p = ffline;
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p == '\0') continue; /* blank line */
+ if (*p == '%' || *p == '#') continue; /* comment */
+
+ keybegin = p;
+ while (*p != '\0' && *p != ' ' && *p != '\t' && *p != '='
+ && *p != '.')
+ ++p;
+ keyend = p;
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p == '.') { /* if qualified by a program name */
+ _Xconst char *progbegin;
+
+ ++p;
+ while (*p == ' ' || *p == '\t') ++p;
+ progbegin = p;
+ while (*p != '\0' && *p != ' ' && *p != '\t' && *p != '=')
+ ++p;
+ if (!(memcmp(progbegin, prog, p - progbegin) == 0
+ && prog[p - progbegin] == '\0')
+ && !(p - progbegin == FFCLASS_LENGTH
+ && memcmp(progbegin, FFCLASS, FFCLASS_LENGTH) == 0))
+ /* if program name does not match */
+ continue;
+ while (*p == ' ' || *p == '\t') ++p;
+ }
+ if (*p != '=') { /* syntax error */
+ if (FFDEBUG)
+ printf("Config line rejected (bad syntax): %s\n", ffline);
+ continue;
+ }
+ do
+ ++p;
+ while (*p == ' ' || *p == '\t');
+ valend = ffline + pos;
+ while (valend > p && (valend[-1] == ' ' || valend[-1] == '\t'))
+ --valend;
+ *keyend = *valend = '\0';
+ ffputenv(keybegin, keyend - keybegin, xmemdup(p, valend - p + 1),
+ True);
+ }
+
+ /*
+ * Clear all the flag fields. This indicates that the variables are
+ * no longer new.
+ */
+
+ for (envpp = envtab; envpp < envtab + XtNumber(envtab); ++envpp)
+ for (envp = *envpp; envp != NULL; envp = envp->next)
+ envp->flag = False;
+}
+
+
+/*
+ * Read a config file path list.
+ */
+
+static void
+rd_cfg(paths)
+ _Xconst char *paths;
+{
+ int pos;
+ FILE *f;
+ struct cfglist **cfgpp;
+
+ for (;;) {
+ if (*paths == '\0' || IS_SEP(*paths)) { /* do the default */
+ if (deflt != NULL) {
+ _Xconst char *d1 = deflt;
+
+ deflt = NULL;
+ rd_cfg(d1); /* do the compiled-in default */
+ }
+ }
+ else {
+ pos = form_path_part(&paths, '\0');
+ if (ffline[0] == '~') {
+ _Xconst char *home = NULL;
+ char *ffp = ffline;
+
+ gethome(&ffp, ffline + pos, &home);
+ if (home != NULL) {
+ int homelen = strlen(home);
+ int pos1 = ffp - ffline;
+
+ pos -= pos1;
+ if (pos + homelen >= ffline_len)
+ expandline(pos + homelen);
+ bcopy(ffline + pos1, ffline + homelen, pos);
+ bcopy(home, ffline, homelen);
+ pos += homelen;
+ free((char *) home);
+ }
+ }
+ if (pos > 0 && ffline[pos - 1] == '/')
+ --pos; /* trim trailing slash */
+ if (pos + 11 >= ffline_len)
+ expandline(pos);
+ ffline[pos] = '\0';
+ cfgpp = &cfghead;
+ for (;;) { /* check for duplicates */
+ struct cfglist *cfgp;
+
+ if (*cfgpp == NULL) { /* if not a duplicate */
+ /* Add it to the list */
+ cfgp = xmalloc(sizeof(*cfgp));
+ cfgp->next = NULL;
+ cfgp->value = xmemdup(ffline, pos + 1);
+ *cfgpp = cfgp;
+
+ bcopy("/texmf.cnf", ffline + pos, 11);
+ if (FFDEBUG)
+ printf("Reading config file %s\n", ffline);
+ f = fopen(ffline, "r");
+ if (f == NULL) {
+ if (FFDEBUG)
+ printf("%s: %s\n", ffline, strerror(errno));
+ }
+ else {
+ read_config_file(f);
+ fclose(f);
+ /* Did it define a new TEXMFCNF value? */
+ /* If so, utilize its value. */
+ if (lastvar == NULL) {
+ lastvar = ffgetenv("TEXMFCNF");
+ if (lastvar != NULL)
+ rd_cfg(lastvar->value);
+ }
+ else if (lastvar->next != NULL
+ && lastvar->next->key == NULL) {
+ lastvar = lastvar->next;
+ rd_cfg(lastvar->value);
+ }
+ }
+ break;
+ }
+ cfgp = *cfgpp;
+ if (strcmp(cfgp->value, ffline) == 0) {
+ if (FFDEBUG)
+ printf(
+ "Skipped duplicate config file %s/texmf.cnf\n",
+ ffline);
+ break;
+ }
+ cfgpp = &cfgp->next;
+ }
+ }
+ if (*paths == '\0') break;
+ ++paths;
+ }
+}
+
+
+/*
+ * Read the config file (public routine).
+ */
+
+void
+readconfig()
+{
+ _Xconst char *paths;
+
+ paths = getenv("TEXMFCNF");
+ if (paths == NULL) { /* if no env variable set */
+ paths = deflt; /* use compiled-in default */
+ deflt = NULL; /* mark it as used */
+ }
+ rd_cfg(paths);
+}
+
+#endif /* CFGFILE */
+
+
+/*
+ * Scan the path part from // or wild cards, to the end.
+ * This assumes that {} have already been taken care of.
+ */
+
+static void
+atomize(p0, sp)
+ _Xconst char *p0;
+ struct steprec *sp;
+{
+ struct atomrec *head;
+ struct atomrec **linkpp;
+ int flags; /* F_SLASH_SLASH and F_WILD */
+ Boolean percent_s;
+ _Xconst char *p = p0;
+ _Xconst char *p1;
+ _Xconst char *p2;
+
+ /*
+ * First check the string for braces.
+ */
+
+ for (p1 = p; ;++p1) {
+ if (*p1 == '\0' || IS_SEP(*p1))
+ break;
+ if (*p1 == LBRACE) {
+ /* Take care of braces first. This code should only be reached
+ * if atomize() is called from ff_prescan(). */
+ unsigned n;
+
+ bracepp = &sp->nextstep;
+ n = p1 - p0;
+ if (n >= ffline_len)
+ expandline(n);
+ bcopy(p0, ffline, n);
+ dobrace(p1, n, 1, False);
+ return;
+ }
+ if (*p1 == '%' && p1[1] != '\0')
+ ++p1;
+ }
+
+ /*
+ * No braces. Split it up into atoms (delimited by / or //).
+ */
+
+ linkpp = &head;
+ flags = 0;
+ percent_s = False;
+ for (;;) {
+ if (*p == '/') {
+ ++p;
+ flags |= F_SLASH_SLASH;
+ /* a %[qQ] may occur following the first //. */
+ if (*p == '%')
+ if (p[1] == 'q' || p[1] == 'Q') {
+ if (p[1] == 'Q') flags |= F_QUICKONLY;
+ flags |= F_QUICKFIND;
+ p += 2;
+ }
+ }
+ p1 = p;
+ for (;; ++p) {
+ if (*p == '\0' || IS_SEP(*p)) {
+ p2 = NULL;
+ if (!(sp->flags & F_FILE_USED))
+ p2 = lrec.no_f_str + 1;
+ break;
+ }
+ if (*p == '/') {
+ p2 = p + 1;
+ break;
+ }
+ if (*p == '%' && p[1] != '\0' && p[1] != '/') {
+ ++p;
+ if (*p == 'f') sp->flags |= F_FILE_USED;
+#if USE_GF
+ /* set it in sp because we may never reach try_to_open*/
+ else if (*p == lrec.pk_opt_char) sp->flags |= F_PK_USED;
+#endif
+ else if (*p == 's' && (p[1] == '\0' || IS_SEP(p[1]))) {
+ --p;
+ percent_s = True;
+ if (lrec.v.pct_s_atom == NULL)
+ atomize_pct_s();
+ break;
+ }
+ }
+ else if (*p == '*' || *p == '?' || *p == '[')
+ flags |= F_WILD;
+ }
+ if (p != p1) { /* add on an atomrec */
+ struct atomrec *atomp;
+
+ atomp = xmalloc(sizeof(struct atomrec));
+ *linkpp = atomp;
+ linkpp = &atomp->next;
+ atomp->flags = flags;
+ flags = 0;
+ atomp->p = p1;
+ atomp->p_end = p;
+ }
+ if (percent_s) {
+ *linkpp = (flags & F_SLASH_SLASH) ? &pct_s_dummy_slash
+ : &pct_s_dummy;
+ sp->flags |= F_PCT_S;
+ break;
+ }
+ p = p2;
+ if (p == NULL) {
+ *linkpp = NULL;
+ break;
+ }
+ }
+ sp->atom = head;
+}
+
+/*
+ * prescan2() sets up the steprec information for a brace alternative.
+ * It also does much of the work in ff_prescan().
+ */
+
+static _Xconst char *
+prescan2(sp, p, skip)
+ struct steprec *sp;
+ _Xconst char *p;
+ Boolean skip; /* true if initial / does not mean // */
+{
+ int flags;
+
+ /*
+ * Scan the string, looking for // or wild cards or braces.
+ * It takes the input / by / so that we can back up to the previous
+ * slash if there is a wild card (which may be hidden in braces).
+ */
+
+ flags = sp->flags;
+ for (;;) { /* loop over slash-separated substrings */
+ sp->strend = p;
+ sp->flags = flags;
+ while (*p == '/') { /* check for // */
+ if (skip) {
+ ++p;
+ skip = False;
+ }
+ else {
+ atomize(p, sp);
+ return p;
+ }
+ }
+ for (;;) { /* loop over characters in this subpart */
+ if (*p == '\0' || IS_SEP(*p)) {
+ sp->strend = p;
+ sp->flags = flags;
+ return p;
+ }
+ if (*p == '/')
+ break;
+ if (*p == LBRACE) {
+ unsigned n;
+
+ bracepp = &sp->nextstep;
+ n = p - sp->strend;
+ if (n >= ffline_len)
+ expandline(n);
+ bcopy(sp->strend, ffline, n);
+ dobrace(p, n, 1, skip);
+ return p;
+ }
+ skip = False;
+ if (*p == '%' && p[1] != '\0') {
+ ++p;
+ if (*p == 's' && (p[1] == '\0' || IS_SEP(p[1]))) {
+ sp->strend = p - 1;
+ sp->flags = flags;
+ sp->nextstep = scan_pct_s();
+ return p;
+ }
+ else if (*p == 'f')
+ flags |= F_FILE_USED | F_VARIABLE;
+ else if (*p == 'F' || *p == lrec.x_var_char)
+ flags |= F_VARIABLE;
+#if USE_GF
+ else if (*p == lrec.pk_opt_char)
+ flags |= F_PK_USED;
+#endif
+ /* %c and %C are sorted out later. */
+ }
+ else if (*p == '*' || *p == '?' || *p == '[') {
+ atomize(sp->strend, sp);
+ return p;
+ }
+ ++p;
+ }
+ ++p;
+ }
+}
+
+/*
+ * dobrace() is the recursive routine for handling {} alternatives.
+ * bracepp (global) = address of where to put next brace item on the
+ * linked list. It has to be global because dobrace() is called
+ * recursively and leaves its droppings at varying levels.
+ * p = input string pointer; it should point to the opening brace.
+ * pos = position within ffline[] for output string.
+ * level = nesting depth.
+ */
+
+static void
+dobrace(p, pos0, level, skip)
+ _Xconst char *p;
+ unsigned pos0;
+ int level;
+ Boolean skip; /* true if initial / does not mean // */
+{
+ int lev;
+ int level1;
+ _Xconst char *p1;
+ unsigned pos;
+
+ for (;;) { /* loop over the alternatives */
+ lev = 0;
+ ++p; /* skip left brace or comma */
+ pos = pos0;
+ for (;;) { /* loop over characters */
+ if (*p == '\0' || IS_SEP(*p)) {
+ /* keep the braces matched: { */
+ fprintf(stderr, "%s: Missing } in %s path.\n",
+ prog, lrec.type);
+ return;
+ }
+ else if (*p == '%') {
+ if (p[1] != '\0') {
+ if (pos >= ffline_len)
+ expandline(pos);
+ ffline[pos++] = *p++;
+ }
+ }
+ else if (*p == LBRACE) {
+ dobrace(p, pos, level + 1, skip && pos == pos0);
+ /* skip to the next matching comma or right brace */
+ for (;;) {
+ if (*p == '\0' || IS_SEP(*p))
+ return; /* this has already been reported */
+ else if (*p == '%') {
+ if (p[1] != '\0') ++p;
+ }
+ else if (*p == LBRACE)
+ ++lev;
+ else if (*p == ',') {
+ if (lev == 0)
+ break;
+ }
+ else if (*p == RBRACE) {
+ if (lev == 0)
+ break;
+ --lev;
+ }
+ ++p;
+ }
+ goto out2;
+ }
+ else if (*p == ',' || *p == RBRACE)
+ break;
+ if (pos >= ffline_len)
+ expandline(pos);
+ ffline[pos++] = *p++;
+ }
+ p1 = p;
+ level1 = level;
+ for (;;) {
+ /* skip until matching right brace */
+ for (;;) {
+ if (*p1 == '\0' || IS_SEP(*p1))
+ goto out2; /* this has already been reported */
+ if (*p1 == '%') {
+ if (p1[1] != '\0') ++p1;
+ }
+ else if (*p1 == LBRACE)
+ ++lev;
+ else if (*p1 == RBRACE) {
+ if (lev == 0) {
+ ++p1;
+ break;
+ }
+ --lev;
+ }
+ ++p1;
+ }
+ --level1;
+ /* now copy until a qualifying comma */
+ for (;;) {
+ if (*p1 == '\0' || IS_SEP(*p1)) {
+ if (level1 == 0) {
+ struct steprec *bp;
+
+ if (pos >= ffline_len)
+ expandline(pos);
+ ffline[pos++] = '\0';
+ *bracepp = bp = xmalloc(sizeof(struct steprec));
+ bp->next = NULL;
+ bp->atom = NULL;
+ bp->nextstep = NULL;
+ bracepp = &bp->next;
+ bp->str = xmemdup(ffline, pos);
+ bp->flags = 0;
+ (void) prescan2(bp, bp->str, skip);
+ }
+ /* else: this has already been reported */
+ goto out2;
+ }
+ if (*p1 == '%') {
+ if (p1[1] != '\0') {
+ if (pos >= ffline_len)
+ expandline(pos);
+ ffline[pos++] = '%';
+ ++p1;
+ }
+ }
+ else if (*p1 == LBRACE) {
+ dobrace(p1, pos, level1 + 1, False);
+ goto out2;
+ }
+ else if (*p1 == ',' && level1 > 0)
+ break;
+ else if (*p1 == RBRACE && level1 > 0) {
+ --level1;
+ ++p1;
+ continue;
+ }
+ if (pos >= ffline_len)
+ expandline(pos);
+ ffline[pos++] = *p1++;
+ }
+ }
+ out2:
+ if (*p != ',') break;
+ }
+}
+
+
+/*
+ * Prescan the '%s' string. This is done only once.
+ */
+
+static struct steprec *
+scan_pct_s()
+{
+ struct steprec **headpp;
+ _Xconst char *p;
+ struct steprec *sp;
+
+ if (lrec.v.pct_s_head != NULL) /* if we've already done this */
+ return lrec.v.pct_s_head;
+
+ headpp = &lrec.v.pct_s_head;
+ p = lrec.pct_s_str;
+ for (p = lrec.pct_s_str; ; ++p) {
+ ++lrec.v.pct_s_count;
+ *headpp = sp = xmalloc(sizeof(struct steprec));
+ sp->atom = NULL;
+ sp->nextstep = NULL;
+ sp->flags = 0;
+ sp->str = p;
+ headpp = &sp->next;
+ (void) prescan2(sp, p, False);
+ for (; *p != '\0' && !IS_SEP(*p); ++p)
+ if (*p == '%' && p[1] != '\0') ++p;
+ if (*p == '\0') break;
+ }
+ *headpp = NULL;
+ return lrec.v.pct_s_head;
+}
+
+/*
+ * Pre-atomize the '%s' strings. Again, done only once.
+ */
+
+static void
+atomize_pct_s()
+{
+ _Xconst struct atomrec **app;
+ struct steprec *sp;
+
+ (void) scan_pct_s(); /* make sure the count is valid */
+
+ app = lrec.v.pct_s_atom =
+ xmalloc((unsigned) lrec.v.pct_s_count * sizeof(*app));
+
+ for (sp = lrec.v.pct_s_head; sp != NULL; sp = sp->next, ++app) {
+ static struct steprec dummy;
+
+ dummy.flags = 0;
+ atomize(sp->str, &dummy);
+ *app = dummy.atom;
+#if USE_GF
+ dummy.atom->flags |= dummy.flags;
+#endif
+ }
+}
+
+
+/*
+ * Init_texmf - Initialize the linked list of options for %t.
+ */
+
+static void /* here's a small subroutine */
+add_to_texmf_list(pp)
+ _Xconst char **pp;
+{
+ static struct texmfrec **tpp = &texmfhead;
+ struct texmfrec *tp;
+ _Xconst char *p;
+ _Xconst char *p_end;
+ _Xconst char *home = NULL;
+ int flags = 0;
+#if CFGFILE
+ _Xconst char *p0;
+ int pos;
+#endif
+
+#if CFGFILE
+ p0 = *pp;
+ pos = form_path_part(pp, '\0');
+ p = ffline;
+ p_end = ffline + pos;
+ ffline[pos] = '\0';
+#else
+ p = *pp;
+ p_end = index(p, ':');
+ if (p_end == NULL) p_end = p + strlen(p);
+ *pp = p_end;
+#endif
+
+ if (*p == '!' && p[1] == '!') {
+ p += 2;
+ flags = F_QUICKONLY;
+ }
+
+ if (*p == '~')
+ gethome(&p, p_end, &home);
+
+#if CFGFILE
+ pos -= p - ffline;
+ if (*pp - p0 >= pos && memcmp(p, *pp - pos, pos) == 0)
+ p = *pp - pos;
+ else
+ p = xmemdup(p, pos + 1);
+#endif
+
+ tp = *tpp = xmalloc(sizeof(struct texmfrec));
+ tp->home = home;
+ tp->str = p;
+#if CFGFILE
+ tp->len = pos;
+#else
+ tp->len = p_end - p;
+#endif
+ tp->flags = flags;
+ tp->next = NULL;
+ tpp = &tp->next;
+}
+
+
+#if CFGFILE
+
+static void
+intexmf(env_value, env_ptr, dflt)
+ _Xconst char *env_value;
+ _Xconst struct envrec *env_ptr;
+ _Xconst char *dflt;
+{
+ _Xconst char *path;
+ Boolean did_next_default;
+
+ if (env_value != NULL) {
+ path = env_value;
+ env_value = NULL;
+ }
+ else if (env_ptr != NULL && env_ptr->value != NULL) {
+ path = env_ptr->value;
+ env_ptr = env_ptr->next;
+ if (env_ptr != NULL && env_ptr->key != NULL)
+ env_ptr = NULL;
+ }
+ else if (dflt != NULL) {
+ path = dflt;
+ dflt = NULL;
+ }
+ else return;
+
+ did_next_default = False;
+
+ for (;;) {
+ if (*path == '\0' || IS_SEP(*path)) {
+ if (!did_next_default) {
+ intexmf(env_value, env_ptr, dflt);
+ did_next_default = True;
+ }
+ }
+ else
+ add_to_texmf_list(&path);
+ if (*path == '\0')
+ break;
+ ++path;
+ }
+}
+
+#endif /* CFGFILE */
+
+
+static void
+init_texmf()
+{
+#if !CFGFILE
+ _Xconst char *texmf;
+ _Xconst char *texmf2;
+#endif
+ _Xconst struct texmfrec *tp;
+ unsigned n;
+
+ if (texmfhead != NULL)
+ return;
+
+#if CFGFILE
+
+ intexmf(getenv("TEXMF"), ffgetenv("TEXMF"), DEFAULT_TEXMF_PATH);
+
+#else /* not CFGFILE */
+
+ texmf = getenv("TEXMF");
+ texmf2 = default_texmf_path;
+ if (texmf == NULL) {
+ texmf = default_texmf_path;
+ texmf2 = NULL;
+ }
+
+ for (;;) {
+ if (*texmf == '\0' || *texmf == ':') {
+ if (texmf2 != NULL)
+ for (;;) {
+ while (*texmf2 == ':') ++texmf2;
+ if (*texmf2 == '\0') break;
+ add_to_texmf_list(&texmf2);
+ }
+ }
+ else
+ add_to_texmf_list(&texmf);
+ if (*texmf == '\0')
+ break;
+ ++texmf;
+ }
+
+#endif /* not CFGFILE */
+
+ /* Make sure ffline[] is long enough for these. */
+
+ n = 0;
+ for (tp = texmfhead; tp != NULL; tp = tp->next)
+ if (tp->len > n)
+ n = tp->len;
+
+ if (n > ffline_len)
+ expandline(n);
+}
+
+
+/*
+ * Scan this path part. This is done at most once.
+ * We look for // or wild cards or {}.
+ */
+
+static _Xconst char *
+ff_prescan(p)
+ _Xconst char *p;
+{
+ struct steprec *sp;
+
+ *steppp = sp = xmalloc(sizeof(struct steprec));
+ sp->next = NULL;
+ sp->flags = 0;
+ sp->atom = NULL;
+ sp->nextstep = NULL;
+
+ /*
+ * Scan the string, looking for // or wild cards or braces.
+ */
+
+ sp->str = p;
+ return prescan2(sp, p, True);
+}
+
+/*
+ * This routine handles the translation of the '%' modifiers.
+ * It returns the new number string length (pos).
+ * It makes sure that at least one free byte remains in ffline[].
+ */
+
+static unsigned
+xlat(stat_in, stat_ret, pos0, p, lastp)
+ _Xconst struct statrec *stat_in;
+ struct statrec *stat_ret;
+ unsigned pos0;
+ _Xconst char *p;
+ _Xconst char *lastp;
+{
+ struct statrec status;
+ _Xconst char *q;
+ int l;
+
+ status.pos = pos0;
+ if (stat_ret != NULL)
+ status = *stat_in;
+
+ while (p < lastp) {
+ q = memchr(p, '%', lastp - p);
+ l = (q != NULL ? q : lastp) - p;
+ if (status.pos + l >= ffline_len)
+ expandline(status.pos + l);
+ bcopy(p, ffline + status.pos, l);
+ status.pos += l;
+ p = q;
+ if (p == NULL) break;
+ do {
+ ++p;
+ if (p >= lastp) break;
+ q = index(lrec.fF_etc, *p);
+ if (q != NULL) {
+ _Xconst char *str = fF_values[q - lrec.fF_etc];
+
+ if (str != NULL) {
+ l = strlen(str);
+ if (status.pos + l >= ffline_len)
+ expandline(status.pos + l);
+ bcopy(str, ffline + status.pos, l);
+ status.pos += l;
+ }
+ else { /* eliminate a possible double slash */
+ if (p[1] == '/' && (status.pos == 0
+ || ffline[status.pos - 1] == '/'))
+ --status.pos;
+ }
+ }
+ else if (*p == 'q' || *p == 'Q') {
+ status.quickchar = *p;
+ status.quickpos = status.pos;
+ }
+ else {
+ if (status.pos + 1 >= ffline_len)
+ expandline(ffline_len);
+ ffline[status.pos++] = *p;
+ }
+ ++p;
+ }
+ while (p < lastp && *p == '%');
+ }
+
+ if (stat_ret != NULL)
+ *stat_ret = status;
+ return status.pos;
+}
+
+
+/*
+ * TRY_TO_OPEN - Try to open the file. Exit via longjmp() if success.
+ */
+
+#if USE_GF
+#define TRY_TO_OPEN(pos, flags) try_to_open(pos, flags)
+#else
+#define TRY_TO_OPEN(pos, flags) try_to_open(pos)
+#endif
+
+static void
+TRY_TO_OPEN(pos, flags)
+ unsigned pos;
+#if USE_GF
+ int flags;
+#endif
+{
+#if USE_GF
+ gflags |= flags;
+ if (pk_second_pass && !(flags & F_PK_USED))
+ return;
+#endif
+ ffline[pos] = '\0';
+
+ if (FFDEBUG)
+ printf("Trying %s file %s\n", lrec.type, ffline);
+
+ file_found = xfopen(ffline, OPEN_MODE);
+ if (file_found != NULL)
+ longjmp(got_it, 1);
+}
+
+
+/*
+ * lsrgetline - Read a line from the (ls-R) file and return:
+ * minus its length if it ends in a colon (including the colon);
+ * its length otherwise;
+ * zero for end of file.
+ * Blank lines are skipped.
+ */
+
+static int
+lsrgetline(f, pos0)
+ FILE *f; /* ls-R file */
+ unsigned pos0; /* relative position in line to start reading */
+{
+ unsigned pos = pos0;
+
+ for (;;) {
+ if (pos + 4 >= ffline_len)
+ expandline(pos);
+ if (fgets(ffline + pos, ffline_len - pos, f) == NULL)
+ break;
+ pos += strlen(ffline + pos);
+ if (pos > pos0 && ffline[pos - 1] == '\n') {
+ --pos; /* trim newline */
+ if (pos > pos0) break; /* if ffline still nonempty */
+ }
+ }
+ if (pos > pos0 && ffline[pos - 1] == ':') {
+ ffline[pos - 1] = '/'; /* change trailing colon to slash */
+ return pos0 - pos;
+ }
+ else
+ return pos - pos0;
+}
+
+
+/*
+ * lsrput - Put a key/value pair into the ls-R database.
+ */
+
+static void
+lsrput(key, keylen, value)
+ _Xconst char *key;
+ unsigned keylen;
+ _Xconst char *value;
+{
+ struct lsr **lpp;
+ struct lsr *lp;
+
+#if 0
+ fputs("lsrput: key = `", stdout);
+ fwrite(key, 1, keylen, stdout);
+ printf("'; value = `%s'.\n", value);
+#endif
+
+ /* make the new record */
+ lp = xmalloc(sizeof(*lp));
+ lp->next = NULL;
+ lp->frecp = frecp;
+ lp->seqno = seqno;
+ lp->keylen = keylen;
+ lp->key = xmemdup(key, keylen);
+ lp->value = value;
+
+ /* insert it */
+ lpp = lsrtab + prehash(key, keylen) % XtNumber(lsrtab);
+ while (*lpp != NULL) /* skip to end of chain (performance reasons) */
+ lpp = &(*lpp)->next;
+ *lpp = lp;
+}
+
+
+/*
+ * init_quick_find - Read ls-R database for this particular search.
+ */
+
+static void
+init_quick_find(root, pos, atom, pos1)
+ struct rootrec *root; /* pointer to the governing rootrec */
+ unsigned pos; /* position of %[qQ] in ffline[] */
+ _Xconst struct atomrec *atom; /* the beginning of the atomlist */
+ unsigned pos1; /* next free byte in ffline[] */
+{
+#define LS_R_LEN 5 /* length of the string "ls-R\0" */
+ char tmpsav[LS_R_LEN];
+ int keypos; /* position of start of key pattern */
+ int keyend; /* last + 1 character of the key */
+ int keypos_a; /* position + 1 of last slash */
+ unsigned pos2; /* end + 1 of the decoded thing */
+ int nslashes; /* how many slashes in bbbcccddd */
+ FILE *f; /* ls-R file */
+ _Xconst char *fullpat; /* fields in *root */
+ _Xconst char *keypat; /* " */
+ _Xconst char *keypat_end; /* " */
+ _Xconst char *fullpat_end; /* " */
+ _Xconst char *keypat_a; /* position of end+1 of restricted
+ * initial fixed part */
+ int retval; /* return value of lsrgetline */
+
+ /*
+ * Reencode the string of atoms into a character string
+ * When we're done, ffline[] contains:
+ * /aa/aa/a...a/ bbb/bb...bb/bbb %f/cc/c...c/%d ddd/ddd/.../ddd
+ *
+ * where the aaa part is what's already in ffline[], and
+ * the rest is the decoded atom chain. The ccc part of this
+ * string contains all the variable specifiers (not replaced by
+ * anything), and the bbb and ddd parts are character strings that
+ * should occur verbatim in the file name.
+ */
+
+ root->flags &= ~F_QUICKFIND; /* clear it for now; set it later */
+
+ if (atom->flags & F_PCT_S)
+ atom = treeatom;
+
+ if (atom->flags & F_WILD) return; /* not allowed */
+
+ pos2 = pos1;
+ keypos = -1;
+ nslashes = 0;
+
+ for (;;) {
+ _Xconst char *p;
+
+ keypos_a = pos2;
+ /* translate the atom, leaving %f and maybe %d alone */
+ for (p = atom->p; p < atom->p_end; ++p) {
+ if (p >= atom->p_end) break;
+ if (*p == '%') {
+ _Xconst char *q;
+
+ ++p;
+ if (p >= atom->p_end) break;
+ q = index(lrec.fF_etc, *p);
+ if (q != NULL) {
+ if (q - lrec.fF_etc < lrec.n_var_opts) {
+ /* it's a variable specifier (%f or ...) */
+ --p; /* copy it over */
+ if (keypos < 0) keypos = pos2;
+ keyend = pos2 + 2;
+ }
+ else {
+ _Xconst char *str = fF_values[q - lrec.fF_etc];
+
+ if (str != NULL) {
+ int l = strlen(str);
+
+ if (pos2 + l >= ffline_len)
+ expandline(pos2 + l);
+ bcopy(str, ffline + pos2, l);
+ pos2 += l;
+ }
+ continue;
+ }
+ }
+ }
+ if (pos2 + 1 >= ffline_len)
+ expandline(pos2);
+ ffline[pos2++] = *p;
+ }
+
+ atom = atom->next;
+ if (atom == NULL) break;
+
+ if (atom->flags & F_PCT_S) atom = treeatom;
+ if (atom->flags & (F_SLASH_SLASH | F_WILD))
+ return; /* not supported */
+
+ if (pos2 == keypos_a) continue; /* if /%m/ with no mode */
+ ffline[pos2++] = '/';
+ ++nslashes;
+ }
+
+ if (keypos_a > keypos) keypos_a = keypos;
+
+ root->flags |= F_QUICKFIND; /* it's eligible */
+
+ if (FFDEBUG) {
+#define DDD(a,b,c) \
+ fputs(a, stdout); \
+ fwrite(ffline + (b), 1, (c) - (b), stdout); \
+ puts("'");
+
+ DDD("\nReading ls-R.\nOriginal string = `", 0, pos1);
+ DDD("Restricted initial fixed part = `", pos1, keypos_a);
+ DDD("Initial fixed part = `", pos1, keypos);
+ DDD("Key pattern = `", keypos, keyend);
+ DDD("Final fixed part = `", keyend, pos2);
+#undef DDD
+ }
+
+ /*
+ * Open ls-R and start reading it.
+ */
+
+ bcopy(ffline + pos, tmpsav, sizeof(tmpsav));
+ bcopy("ls-R", ffline + pos, sizeof(tmpsav));
+ if (FFDEBUG) printf("Opening ls-R file %s\n", ffline);
+ f = xfopen(ffline, OPEN_MODE);
+ bcopy(tmpsav, ffline + pos, sizeof(tmpsav));
+ if (f == NULL) {
+ if (FFDEBUG) printf("xfopen: %s\n", strerror(errno));
+ return;
+ }
+
+ fullpat = xmemdup(ffline + pos1, pos2 - pos1);
+ keypat = fullpat + (keypos - pos1);
+ keypat_a = fullpat + (keypos_a - pos1);
+ keypat_end = fullpat + (keyend - pos1);
+ fullpat_end = fullpat + (pos2 - pos1);
+
+ do { /* skip initial comment lines */
+ retval = lsrgetline(f, pos1);
+ if (retval == 0) {
+ fclose(f);
+ ++n_files_left;
+ return; /* premature end of file */
+ }
+ } while (ffline[pos1] == '%');
+
+ /* First take care of file names without a directory: these are
+ * those in the same directory as the ls-R file */
+
+ while (retval > 0) {
+ if (nslashes == 0 /* if there are no slashes in the pattern */
+ /* and if ls-R is in the same directory
+ * as the //: */
+ && pos1 == pos
+ /* and if the initial fixed part matches: */
+ && memcmp(ffline + pos1, fullpat, keypat - fullpat) == 0
+ /* and if the final fixed part matches: */
+ && memcmp(ffline + pos1 + retval
+ - (fullpat_end - keypat_end),
+ keypat_end, fullpat_end - keypat_end) == 0)
+ /* then create a directory entry */
+ lsrput(ffline + pos1 + (keypat - fullpat),
+ retval - (keypat - fullpat) - (fullpat_end - keypat_end), "");
+ retval = lsrgetline(f, pos1); /* read next line */
+ }
+
+ /*
+ * Now do whole directories.
+ */
+
+ for (;;) {
+ int i;
+ _Xconst char *p;
+ _Xconst char *p_begin;
+ _Xconst char *p_end;
+ unsigned pos3;
+ unsigned pos4;
+ unsigned pos5;
+ unsigned retpos;
+ char *value;
+
+ while (retval > 0) /* skip to next directory */
+ retval = lsrgetline(f, pos1);
+ if (retval == 0) break; /* if end of file */
+ retval = -retval; /* length of the string */
+ /* also, retval is now > 0, so a continue statement won't lead to
+ * an infinite loop. */
+ retpos = pos1 + retval;
+ if (ffline[pos1] == '/') { /* if absolute path */
+ /* these should be referring to the same directory */
+ if (retval < pos1 || memcmp(ffline + pos1, ffline, pos1) != 0)
+ continue;
+ pos2 = pos1 + pos1;
+ }
+ else { /* relative path */
+ pos2 = pos1;
+ if (retval >= 2 && ffline[pos1] == '.'
+ && ffline[pos1 + 1] == '/')
+ pos2 += 2; /* eliminate "./" */
+ /* these should be referring to the same directory */
+ if (retpos - pos2 < pos1 - pos
+ || memcmp(ffline + pos2, ffline + pos, pos1 - pos) != 0)
+ continue;
+ pos2 += pos1 - pos;
+ }
+ /* now pos2 points to what should follow the // */
+ /* count backwards from the end of the string to just after the
+ (nslashes + 1)-st slash */
+ p_begin = ffline + pos2;
+ p_end = ffline + retpos;
+ i = nslashes;
+ for (p = p_end; p > p_begin; )
+ if (*--p == '/') {
+ if (i == 0) {
+ ++p;
+ break;
+ }
+ else --i;
+ }
+ if (i > 0) continue; /* if too few slashes */
+ pos3 = p - ffline;
+ /* the next part of the directory name should match the initial
+ fixed part of the pattern */
+ if (p_end - p < keypat_a - fullpat
+ || memcmp(p, fullpat, keypat_a - fullpat) != 0)
+ continue;
+ pos4 = pos3 + (keypat - fullpat); /* start of key */
+ value = NULL;
+ for (;;) { /* read the files in this directory */
+ retval = lsrgetline(f, retpos);
+ if (retval <= 0) { /* if done with list*/
+ bcopy(ffline + retpos, ffline + pos1, -retval);
+ break;
+ }
+ /* check the remaining part of the initial fixed part */
+ /* (the first test is only for performance) */
+ if (keypat_a != keypat
+ && memcmp(ffline + retpos, keypat_a, keypat - keypat_a) != 0)
+ continue;
+ /* end of key */
+ pos5 = retpos + retval - (fullpat_end - keypat_end);
+ /* check the final fixed part */
+ if (pos5 < pos4 || (fullpat_end != keypat_end
+ && memcmp(ffline + pos5, keypat_end,
+ fullpat_end - keypat_end) != 0))
+ continue;
+ if (value == NULL) {
+ value = xmemdup(ffline + pos2, pos3 - pos2 + 1);
+ value[pos3 - pos2] = '\0';
+ }
+ lsrput(ffline + pos4, pos5 - pos4, value);
+ }
+ }
+
+ fclose(f); /* close the file */
+ ++n_files_left;
+
+ /* Fill in the requisite entries in *root: we have ls-R. */
+ root->fullpat = fullpat;
+ root->fullpat_end = fullpat_end;
+ root->keypat = keypat;
+ root->keypat_end = keypat_end;
+}
+
+/*
+ * wildmatch - Tell whether the string matches the pattern.
+ *
+ * pat pointer to first character of pattern
+ * pat_end pointer to last + 1 character of pattern
+ * candidate the string
+ * allowvar how many characters of fF_etc should be treated
+ * as *
+ */
+
+static Boolean
+wildmatch(pat, pat_end, candidate, allowvar)
+ _Xconst char *pat;
+ _Xconst char *pat_end;
+ _Xconst char *candidate;
+ int allowvar; /* How many of %f, %F, %d, ... to */
+ /* treat as '*' */
+{
+ _Xconst char *p;
+ _Xconst char *q = candidate;
+
+ for (p = pat; p < pat_end; ++p)
+ switch (*p) {
+
+ case '%': {
+ _Xconst char *q1;
+
+ if (p + 1 >= pat_end) continue;
+ ++p;
+ q1 = index(lrec.fF_etc, *p);
+ if (q1 == NULL) { /* %[ or something */
+ if (*q != *p)
+ return False;
+ ++q;
+ break;
+ }
+
+ if (q1 - lrec.fF_etc < allowvar) { /* treat it as '*' */
+ for (q1 = q + strlen(q); q1 >= q; --q1)
+ if (wildmatch(p + 1, pat_end, q1, allowvar))
+ return True;
+ return False;
+ }
+ else {
+ _Xconst char *str = fF_values[q1 - lrec.fF_etc];
+ int l;
+
+ if (str == NULL) str = "";
+ l = strlen(str);
+ if (bcmp(q, str, l) != 0)
+ return False;
+ q += l;
+ }
+ break;
+ }
+
+ case '*': {
+ _Xconst char *q1;
+
+ for (q1 = q + strlen(q); q1 >= q; --q1)
+ if (wildmatch(p + 1, pat_end, q1, allowvar))
+ return True;
+ return False;
+ }
+
+ case '?':
+ if (*q == '\0')
+ return False;
+ ++q;
+ break;
+
+ case '[': {
+ char c;
+ Boolean reverse = False;
+
+ c = *q++;
+ if (c == '\0')
+ return False;
+
+ ++p;
+ if (*p == '^') {
+ reverse = True;
+ ++p;
+ }
+
+ for (;;) {
+ char c1;
+ char c2;
+
+ if (p >= pat_end)
+ return False; /* syntax error */
+ c1 = *p;
+ if (c1 == ']') {
+ if (reverse)
+ break; /* success */
+ else
+ return False;
+ }
+ c2 = c1;
+ ++p;
+ if (*p == '-' && p[1] != ']') {
+ ++p;
+ c2 = *p++;
+ if (c2 == '%') c2 = *p++;
+ }
+ if (p >= pat_end)
+ return False; /* syntax error */
+ if (c >= c1 && c <= c2) {
+ if (reverse)
+ return False;
+ else { /* success */
+ while (*p != ']') {
+ if (*p == '%') ++p;
+ ++p;
+ if (p >= pat_end)
+ return False; /* syntax error */
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ if (*q != *p)
+ return False;
+ ++q;
+ }
+
+ if (*q != '\0')
+ return False;
+ return True;
+}
+
+
+/*
+ * Read in the given directory.
+ */
+
+static void
+filltree(pos, treepp, atom, slashslash)
+ unsigned pos;
+ struct treerec **treepp;
+ struct atomrec *atom;
+ Boolean slashslash;
+{
+ DIR *f;
+ struct dirent *dp;
+
+ if (pos == 0) {
+ if (ffline_len == 0)
+ expandline(2);
+ ffline[0] = '.';
+ ffline[1] = '\0';
+ }
+ else
+ ffline[pos - 1] = '\0';
+
+ if (FFDEBUG)
+ printf("Opening directory %s\n", ffline);
+
+ f = xopendir(ffline);
+ if (f == NULL) {
+ if (FFDEBUG) printf("%s: %s\n", ffline, strerror(errno));
+ *treepp = NULL;
+ return;
+ }
+
+ if (pos != 0) ffline[pos - 1] = '/';
+ for (;;) {
+ char *line1;
+ struct stat statbuf;
+ struct treerec *leaf;
+ Boolean isdir;
+ unsigned len;
+#if ST_NLINK_TRICK
+ struct treerec *child;
+#endif
+
+ dp = readdir(f);
+ if (dp == NULL) break; /* done */
+
+ len = NAMLEN(dp);
+ if (pos + len >= ffline_len)
+ expandline(pos + (int) len);
+ line1 = ffline + pos;
+ bcopy(dp->d_name, line1, len);
+ line1[len] = '\0';
+ if (*line1 == '.' && (line1[1] == '\0'
+ || (line1[1] == '.' && line1[2] == '\0')))
+ continue; /* skip . and .. */
+
+ if (lstat(ffline, &statbuf) != 0) {
+ fprintf(stderr, "%s/filltree/stat: ", prog);
+ perror(ffline);
+ continue;
+ }
+ isdir = False;
+#if ST_NLINK_TRICK
+ child = ¬_read_yet;
+#endif
+ if (S_ISDIR(statbuf.st_mode)) {
+ isdir = True;
+ if (!slashslash
+ && (atom->next == NULL
+ || !wildmatch(atom->p, atom->p_end, line1,
+ lrec.n_var_opts)))
+ continue;
+#if ST_NLINK_TRICK
+ if (statbuf.st_nlink <= 2)
+ child = NULL;
+#endif
+ }
+ else if (S_ISREG(statbuf.st_mode)) {
+ if (atom->next != NULL
+ || (slashslash && !(atom->flags & F_WILD))
+ || !wildmatch(atom->p, atom->p_end, line1,
+ lrec.n_var_opts))
+ continue;
+ }
+ else continue; /* something else */
+
+ leaf = xmalloc(sizeof(struct treerec));
+ {
+ char *str;
+
+ str = xmemdup(dp->d_name, (unsigned) len + 1);
+ str[len] = '\0';
+ leaf->dirname = str;
+ }
+#if ST_NLINK_TRICK
+ leaf->child = child;
+#else
+ leaf->child = ¬_read_yet;
+#endif
+ leaf->isdir = isdir;
+ *treepp = leaf;
+ treepp = &leaf->next;
+ }
+ closedir(f);
+ ++n_files_left;
+
+ *treepp = NULL;
+}
+
+
+/*
+ * do_tree_search() - recursive routine for // and wild card searches.
+ */
+
+static void
+do_tree_search(treepp, atom, goback, pos, flags)
+ struct treerec **treepp;
+ _Xconst struct atomrec *atom;
+ _Xconst struct atomrec *goback;
+ unsigned pos;
+ int flags;
+{
+ int aflags;
+ struct treerec *tp;
+
+ /*
+ * If we're at the end of the chain of atoms, try to open the file.
+ */
+
+ if (atom == NULL) {
+ TRY_TO_OPEN(pos - 1, flags);
+ return;
+ }
+
+ /*
+ * Otherwise, we're still forming the path.
+ */
+
+ aflags = atom->flags;
+ if (aflags & F_PCT_S) { /* if it's a dummy record */
+ atom = treeatom;
+ aflags |= atom->flags;
+ }
+
+ if (aflags & F_SLASH_SLASH)
+ goback = atom;
+
+ if (goback == NULL) { /* wild card search, no // yet */
+ /*
+ * If the next atom is neither wild nor variable, then we don't
+ * need to do a readdir() on the directory. Just add the
+ * appropriate characters to the path and recurse.
+ */
+ if (!(atom->flags & (F_WILD | F_VARIABLE))) {
+ pos = xlat(NULL, NULL, pos, atom->p, atom->p_end);
+ ffline[pos++] = '/';
+ do_tree_search(treepp, atom->next, goback, pos,
+ flags | atom->flags);
+ return;
+ }
+ /*
+ * Otherwise, go down one level in the tree.
+ */
+ if (*treepp == ¬_read_yet) /* if readdir() not done yet */
+ filltree(pos, treepp, atom, False); /* do it */
+
+ for (tp = *treepp; tp != NULL; tp = tp->next)
+ if (wildmatch(atom->p, atom->p_end, tp->dirname, 0)) {
+ int len = strlen(tp->dirname);
+ bcopy(tp->dirname, ffline + pos, len);
+ ffline[pos + len++] = '/';
+ do_tree_search(&tp->child, atom->next, goback, pos + len,
+ flags | atom->flags);
+ }
+
+ return;
+ }
+
+ /*
+ * If we got here, then we're past a //
+ */
+
+ if (atom->next == NULL && !(atom->flags & F_WILD))
+ /* if we can try a file */
+ TRY_TO_OPEN(xlat(NULL, NULL, pos, atom->p, atom->p_end),
+ flags | atom->flags);
+
+ if (*treepp == ¬_read_yet) /* if readdir() not done yet */
+ filltree(pos, treepp, atom, True); /* do it */
+
+ for (tp = *treepp; tp != NULL; tp = tp->next) {
+ tp->tried_already = False;
+ if ((atom->next != NULL || (atom->flags & F_WILD))
+ && wildmatch(atom->p, atom->p_end, tp->dirname, 0)) {
+ int len = strlen(tp->dirname);
+ bcopy(tp->dirname, ffline + pos, len);
+ ffline[pos + len++] = '/';
+ do_tree_search(&tp->child, atom->next, goback, pos + len,
+ flags | atom->flags);
+ tp->tried_already = True;
+ }
+ }
+
+ for (tp = *treepp; tp != NULL; tp = tp->next)
+ if (!tp->tried_already && tp->isdir) {
+ int len = strlen(tp->dirname);
+ bcopy(tp->dirname, ffline + pos, len);
+ ffline[pos + len++] = '/';
+ do_tree_search(&tp->child, goback, goback, pos + len, flags);
+ }
+}
+
+
+/*
+ * begin_tree_search() - start a wild card or // search.
+ */
+
+static void
+begin_tree_search(status, oneatom, twoatom)
+ _Xconst struct statrec *status;
+ _Xconst struct atomrec *oneatom; /* initial atom */
+ _Xconst struct atomrec *twoatom; /* if F_PCT_S set */
+{
+ struct treerec **tpp;
+
+#if USE_GF
+ {
+ int flags = status->flags;
+
+ if (twoatom != NULL)
+ flags |= twoatom->flags;
+ if (pk_second_pass && !(flags & F_PK_USED))
+ return;
+ }
+#endif
+
+#if 0
+ {
+ _Xconst struct atomrec *atom;
+
+ puts("begin_tree_search():");
+ fwrite(ffline, 1, status->pos, stdout);
+ putchar('\n');
+ atom = oneatom;
+ for (;;) {
+ fputs("+ ", stdout);
+ if (atom->flags & F_SLASH_SLASH) fputs("(//) ", stdout);
+ if (atom->flags & F_PCT_S) atom = twoatom;
+ fwrite(atom->p, 1, atom->p_end - atom->p, stdout);
+ if (atom->flags & F_WILD) fputs(" (wild)", stdout);
+ putchar('\n');
+ atom = atom->next;
+ if (atom == NULL) break;
+ }
+ putchar('\n');
+ }
+#endif
+
+ ++seqno;
+ treeatom = twoatom; /* save this globally */
+
+ /*
+ * Find the record controlling this mess. Create one, if necessary.
+ */
+
+ if (status->flags & F_VARIABLE) {
+ struct vrootrec {
+ struct rootrec *next; /* link to next in hash chain */
+ struct treerec *tree; /* the tree */
+ _Xconst char *path;
+ int seqno;
+ };
+ struct rtab {
+ struct rtab *next;
+ int seqno;
+ int len;
+ _Xconst char *tag;
+ struct vrootrec *r;
+ };
+ static struct rtab *varroot[32];
+ struct rtab **tpp2;
+ struct rtab *t;
+ struct vrootrec *r;
+
+ tpp2 = varroot + prehash(ffline, status->pos) % XtNumber(varroot);
+ for (;;) {
+ t = *tpp2;
+ if (t == NULL) {
+ t = xmalloc(sizeof(*t));
+ t->seqno = seqno;
+ t->len = status->pos;
+ t->tag = xmemdup(ffline, status->pos);
+ r = xmalloc(sizeof(*r));
+ r->next = NULL;
+ r->tree = ¬_read_yet; /* readdir() not done yet */
+ t->r = r;
+ t->next = NULL;
+ *tpp2 = t;
+ break;
+ }
+ if (t->seqno == seqno && t->len == status->pos
+ && memcmp(t->tag, ffline, t->len) == 0) {
+ r = t->r;
+ break;
+ }
+ tpp2 = &t->next;
+ }
+ tpp = &r->tree;
+ }
+ else {
+ struct rootrec *r;
+
+ r = *rootpp;
+ if (r == NULL) {
+ r = xmalloc(sizeof(*r));
+ r->next = NULL;
+ r->tree = ¬_read_yet; /* readdir() not done yet */
+ r->fullpat = NULL; /* no ls-R yet */
+ *rootpp = r;
+ r->flags = status->flags |
+ ((oneatom->flags & F_PCT_S) ? twoatom : oneatom) ->flags;
+ if (r->flags & F_QUICKFIND)
+ init_quick_find(r, status->pos, oneatom, status->pos);
+ else if (status->quickchar != '\0') {
+ r->flags |= (status->quickchar == 'Q' ? F_QUICKONLY : 0);
+ /* (init_quick_find() will set F_QUICKFIND in r->flags) */
+ init_quick_find(r, status->quickpos, oneatom, status->pos);
+ }
+ }
+ rootpp = &r->next;
+ tpp = &r->tree;
+ /* do ls-R search, if appropriate */
+ if ((r->flags & F_QUICKFIND) && r->fullpat != NULL) {
+ unsigned pos;
+ struct lsr *lp;
+
+ pos = xlat(NULL, NULL, status->pos, r->keypat, r->keypat_end);
+ lp = lsrtab[prehash(ffline + status->pos, pos - status->pos)
+ % XtNumber(lsrtab)];
+ for (;;) {
+ if (lp == NULL) break; /* no match */
+ if (lp->frecp == frecp && lp->seqno == seqno
+ && lp->keylen == pos - status->pos
+ && memcmp(lp->key, ffline + status->pos, lp->keylen) == 0)
+ { /* if match */
+ struct statrec stat1;
+ int len = strlen(lp->value);
+
+ stat1 = *status;
+ if (stat1.pos + len > ffline_len)
+ expandline(stat1.pos + len);
+ bcopy(lp->value, ffline + stat1.pos, len);
+ stat1.pos += len;
+ (void) xlat(&stat1, &stat1, 0,
+ r->fullpat, r->fullpat_end);
+ TRY_TO_OPEN(stat1.pos, stat1.flags);
+ return;
+ }
+ lp = lp->next;
+ }
+ /* if there's an ls-R database, and our file is not there,
+ * then we don't look recursively this time. */
+ return;
+ }
+ if ((r->flags & (F_QUICKFIND | F_QUICKONLY))
+ == (F_QUICKFIND | F_QUICKONLY)) {
+#if USE_GF
+ gflags |= status->flags;
+#endif
+ return;
+ }
+ }
+
+ do_tree_search(tpp, oneatom, NULL, status->pos, status->flags);
+}
+
+
+/*
+ * dostep() - Process a steprec record.
+ */
+
+static void
+dostep(sp, stat0)
+ _Xconst struct steprec *sp;
+ _Xconst struct statrec *stat0;
+{
+ struct statrec status;
+
+ (void) xlat(stat0, &status, 0, sp->str, sp->strend);
+
+ status.flags |= sp->flags;
+
+ if (sp->atom != NULL) { /* if wild cards or // */
+ if (sp->flags & F_PCT_S) {
+ int i;
+
+ for (i = 0; i < lrec.v.pct_s_count; ++i)
+ begin_tree_search(&status, sp->atom, lrec.v.pct_s_atom[i]);
+ }
+ else
+ begin_tree_search(&status, sp->atom, NULL);
+ }
+ else if (sp->nextstep != NULL) { /* if {} list */
+ struct steprec *sp1;
+
+ for (sp1 = sp->nextstep; sp1 != NULL; sp1 = sp1->next)
+ dostep(sp1, &status);
+ }
+ else { /* end of string */
+ if (!(status.flags & F_FILE_USED)) {
+ (void) xlat(&status, &status, 0,
+ lrec.no_f_str, lrec.no_f_str_end);
+#if USE_GF
+ status.flags |= lrec.no_f_str_flags;
+#endif
+ }
+ TRY_TO_OPEN(status.pos, status.flags);
+ }
+}
+
+
+/*
+ * fixbegin() - Handle !!, %t, %S, and ~ at the beginning of a specifier.
+ */
+
+static void
+fixbegin(sp)
+ struct steprec *sp;
+{
+ _Xconst char *p = sp->str;
+
+ /*
+ * Initial !!.
+ */
+
+ if (*p == '!' && p[1] == '!' && sp->strend >= p + 2) {
+ sp->flags |= F_QUICKONLY;
+ p += 2;
+ }
+
+ /*
+ * Take care of %S, %t, and ~.
+ */
+
+ sp->home = NULL;
+
+ if (*p == '%') {
+ if (p[1] == 'S' && sp->strend == p + 2 && sp->atom == NULL
+ && sp->nextstep == NULL) { /* %S */
+ init_texmf();
+ sp->flags |= F_PCT_T;
+ p = "/";
+ sp->strend = p + 1;
+ sp->nextstep = scan_pct_s();
+ }
+ if (p[1] == 't' && sp->strend >= p + 2) { /* %t */
+ init_texmf();
+ sp->flags |= F_PCT_T;
+ p += 2;
+ }
+ }
+ else if (*p == '~')
+ gethome(&p, sp->strend, &sp->home);
+
+ sp->str = p;
+}
+
+
+/*
+ * pathpart() - Handle one (colon-separated) part of the search path.
+ */
+
+static _Xconst char *
+pathpart(p)
+ _Xconst char *p;
+{
+ struct steprec *sp;
+ static _Xconst struct statrec stat_ini = {0, 0, '\0', 0};
+ struct statrec status;
+
+ sp = *steppp;
+ if (sp == NULL) { /* do prescanning (lazy evaluation) */
+ _Xconst char *p_end;
+#if CFGFILE
+ _Xconst char *p1;
+ int pos;
+#endif
+
+#if CFGFILE
+ p_end = p;
+ pos = form_path_part(&p_end, '%');
+ ffline[pos] = '\0';
+ if (pos <= p_end - p && memcmp(ffline, p_end - pos, pos) == 0)
+ p1 = p_end - pos;
+ else
+ p1 = xmemdup(ffline, pos + 1);
+ (void) ff_prescan(p1);
+#else
+ p_end = ff_prescan(p);
+ /* skip to next colon or end of string */
+ for (; *p_end != '\0' && *p_end != ':'; ++p_end)
+ if (*p_end == '%' && p_end[1] != '\0')
+ ++p_end;
+#endif
+
+ sp = *steppp;
+ if (sp->str == sp->strend && sp->nextstep != NULL) {
+ /* If it's braces right off the bat, then pretend these are */
+ /* all different specifiers (so %t, %S, !!, and ~ can work). */
+ /* There's a memory leak here, but it's bounded. */
+ struct steprec *sp1 = sp->nextstep;
+
+ for (;;) {
+ fixbegin(sp1);
+ if (sp1->next == NULL) {
+ sp1->nextpart = p_end;
+ break;
+ }
+ sp1->nextpart = p;
+ sp1 = sp1->next;
+ }
+ *steppp = sp = sp->nextstep; /* relink the chain */
+ }
+ else {
+ fixbegin(sp);
+ sp->nextpart = p_end;
+ }
+ }
+ steppp = &sp->next;
+
+ if (sp->flags & F_PCT_T) {
+ struct texmfrec *tp;
+
+ for (tp = texmfhead; tp != NULL; tp = tp->next) {
+ status = stat_ini;
+ status.flags = tp->flags;
+ if (tp->home != NULL) {
+ status.pos = strlen(tp->home);
+ if (status.pos + tp->len >= ffline_len)
+ expandline(status.pos + tp->len);
+ bcopy(tp->home, ffline, status.pos);
+ }
+ bcopy(tp->str, ffline + status.pos, tp->len);
+ status.pos += tp->len;
+#if ! USE_GF
+ dostep(sp, &status);
+#else
+ if (lrec.pk_gf_addr != NULL) *lrec.pk_gf_addr = "pk";
+ pk_second_pass = False;
+ gflags = 0;
+ dostep(sp, &status);
+ if (gflags & F_PK_USED) {
+ *lrec.pk_gf_addr = "gf";
+ pk_second_pass = True;
+ dostep(sp, &status);
+ }
+#endif
+ }
+ }
+ else {
+ status = stat_ini;
+ if (sp->home != NULL) {
+ unsigned len = strlen(sp->home);
+
+ if (len >= ffline_len)
+ expandline(len);
+ bcopy(sp->home, ffline, len);
+ status.pos = len;
+ }
+#if ! USE_GF
+ dostep(sp, &status);
+#else
+ if (lrec.pk_gf_addr != NULL) *lrec.pk_gf_addr = "pk";
+ pk_second_pass = False;
+ gflags = 0;
+ dostep(sp, &status);
+ if (gflags & F_PK_USED) {
+ *lrec.pk_gf_addr = "gf";
+ pk_second_pass = True;
+ dostep(sp, &status);
+ }
+#endif
+ }
+
+ return sp->nextpart;
+}
+
+
+#if CFGFILE
+
+/*
+ * Recursive routine for searching in config file path variables.
+ */
+
+static void
+ffrecurse(env_ptr, dflt)
+ _Xconst struct envrec *env_ptr;
+ _Xconst char *dflt;
+{
+ _Xconst char *p;
+ Boolean did_next_default;
+
+ if (env_ptr != NULL) {
+ p = env_ptr->value;
+ env_ptr = env_ptr->next;
+ if (env_ptr != NULL && env_ptr->key != NULL)
+ env_ptr = NULL;
+ }
+ else if (dflt != NULL) {
+ p = dflt;
+ dflt = NULL;
+ }
+ else return;
+
+ did_next_default = False;
+ for (;;) {
+ if (*p == '\0' || IS_SEP(*p)) {
+ if (!did_next_default) {
+ ffrecurse(env_ptr, dflt);
+ did_next_default = True;
+ }
+ }
+ else
+ p = pathpart(p);
+ if (*p == '\0')
+ break;
+ ++p;
+ }
+}
+
+#endif /* CFGFILE */
+
+
+#if FFDUMP
+
+/*
+ * Debugging routine. Dump those crazy step records.
+ */
+
+static void
+dumpsteps(sp, indent)
+ _Xconst struct steprec *sp;
+ int indent;
+{
+ _Xconst struct steprec *sp1;
+ int i;
+
+ while (sp != NULL) {
+ for (i = 0; i < indent; ++i) putchar(' ');
+ printf("%04o `", sp->flags);
+ fwrite(sp->str, 1, sp->strend - sp->str, stdout);
+ puts("'");
+
+ if (sp->home != NULL) {
+ for (i = 0; i < indent; ++i) putchar(' ');
+ printf(" Home = %s\n", sp->home);
+ }
+
+ /* there's an atomrec dumper in begin_tree_search() */
+
+ dumpsteps(sp->nextstep, indent + 2);
+
+ sp = sp->next;
+ }
+}
+
+#endif
+
+
+/*
+ * This is the main search routine. It calls pathpath() for each
+ * component of the path. Substitution for the default path is done here.
+ */
+
+FILE *
+filefind(name, srchtype, path_ret)
+ _Xconst char *name; /* name of the font or file */
+ struct findrec *srchtype; /* what type of search to perform */
+ _Xconst char **path_ret; /* put the name of the file here */
+{
+ lrec = *srchtype;
+ fF_values[0] = fF_values[1] = name;
+
+ if (setjmp(got_it) == 0) {
+ if (*name == '/' || *name == '~') { /* if absolute path */
+ unsigned pos;
+ unsigned pos0 = 0;
+ _Xconst struct passwd *pw = NULL;
+
+ if (*name == '~')
+ pw = ff_getpw(&name, name + strlen(name));
+ if (pw != NULL) {
+ pos0 = strlen(pw->pw_dir);
+ if (pos0 >= ffline_len)
+ expandline(pos0);
+ bcopy(pw->pw_dir, ffline, pos0);
+ fF_values[0] = fF_values[1] = name;
+ }
+#if ! USE_GF
+ pos = xlat(NULL, NULL, pos0, lrec.abs_str,
+ lrec.abs_str + strlen(lrec.abs_str));
+ TRY_TO_OPEN(pos, 0);
+#else
+ if (lrec.pk_gf_addr != NULL) *lrec.pk_gf_addr = "pk";
+ pk_second_pass = False;
+ pos = xlat(NULL, NULL, pos0, lrec.abs_str,
+ lrec.abs_str + strlen(lrec.abs_str));
+ TRY_TO_OPEN(pos, lrec.abs_str_flags);
+ if (lrec.abs_str_flags & F_PK_USED) {
+ *lrec.pk_gf_addr = "gf";
+ pk_second_pass = True;
+ pos = xlat(NULL, NULL, pos0, lrec.abs_str,
+ lrec.abs_str + strlen(lrec.abs_str));
+ TRY_TO_OPEN(pos, lrec.abs_str_flags);
+ }
+#endif
+ }
+ else {
+ _Xconst char *p;
+
+ steppp = &lrec.v.stephead;
+ frecp = srchtype;
+ seqno = 0;
+ rootpp = &lrec.v.rootp;
+
+#if CFGFILE
+
+ if (lrec.path1 == NULL)
+ ffrecurse(lrec.envptr, lrec.path2);
+ else {
+ Boolean did_the_default = False;
+
+ for (p = lrec.path1;;) {
+ if (*p == '\0' || IS_SEP(*p)) {
+ /* bring in the default path */
+ if (!did_the_default) {
+ ffrecurse(lrec.envptr, lrec.path2);
+ did_the_default = True;
+ }
+ }
+ else
+ p = pathpart(p);
+ if (*p == '\0') break;
+ ++p; /* skip the colon */
+ }
+ }
+
+#else /* not CFGFILE */
+
+ for (p = lrec.path1;;) {
+ if (*p == '\0' || *p == ':') {
+ /* bring in the default path */
+ if (lrec.path2 != NULL) {
+ _Xconst char *p1 = lrec.path2;
+
+ for (;;) {
+ if (*p1 == '\0') break;
+ if (*p1 == ':') continue;
+ p1 = pathpart(p1);
+ if (*p1 == '\0') break;
+ ++p1; /* skip the colon */
+ }
+ }
+ }
+ else
+ p = pathpart(p);
+ if (*p == '\0') break;
+ ++p; /* skip the colon */
+ }
+
+#endif /* not CFGFILE */
+
+ file_found = NULL;
+ }
+ }
+ else {
+ /* it longjmp()s here when it finds the file */
+ if (FFDEBUG) puts("--Success--\n");
+ if (path_ret != NULL)
+ *path_ret = xstrdup(ffline);
+ }
+
+ srchtype->v = lrec.v; /* restore volatile parameters of *srchtype */
+
+#if FFDUMP
+ dumpsteps(srchtype->v.stephead, 0);
+ putchar('\n');
+#endif
+
+ return file_found;
+}
diff --git a/filefind.h b/filefind.h
@@ -0,0 +1,273 @@
+/*========================================================================*\
+
+Copyright (c) 1996-1999 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * filefind.h - Define the data structures that specify how to search
+ * for various types of files.
+ */
+
+
+/*
+ * First, some macro definitions.
+ * Optionally, filf-app.h may define these.
+ */
+
+#ifndef True
+typedef char Boolean;
+#define True 1
+#define False 0
+#endif
+
+#ifndef ARGS
+#if NeedFunctionPrototypes
+#define ARGS(x) x
+#else
+#define ARGS(x) ()
+#endif
+#endif
+
+/*
+ * Record describing how to search for this type of file. Fields are
+ * described further below.
+ */
+
+struct findrec {
+ _Xconst char *path1;
+#if CFGFILE
+ _Xconst struct envrec *envptr;
+#endif
+ _Xconst char *path2;
+ _Xconst char *type;
+ _Xconst char *fF_etc;
+ char x_var_char;
+ int n_var_opts;
+ _Xconst char *no_f_str;
+ _Xconst char *no_f_str_end;
+ _Xconst char *abs_str;
+#if USE_GF
+ int no_f_str_flags;
+ int abs_str_flags;
+ char pk_opt_char;
+ _Xconst char **pk_gf_addr;
+#endif
+ _Xconst char *pct_s_str;
+
+ struct {
+ struct steprec *stephead;
+ struct steprec *pct_s_head;
+ int pct_s_count;
+ _Xconst struct atomrec **pct_s_atom;
+ struct rootrec *rootp;
+ } v;
+};
+
+/*
+ * And now, the star of our show.
+ */
+
+extern FILE *filefind ARGS((_Xconst char *, struct findrec *,
+ _Xconst char **));
+
+/*
+ * Here are the meanings of the various fields in struct findrec:
+ *
+ * const char *path1
+ * Colon-separated list of path components to use in the search.
+ * This can be obtained, for example, from the environment
+ * variable 'XDVIFONTS.'
+ *
+ * const struct envrec *envptr
+ * Pointer to linked list of local environment variable records
+ * for the appropriate variable. These variables are only the
+ * ones defined in some config file.
+ *
+ * const char *path2
+ * Secondary list of path components to use in the search.
+ * Normally, this is the compiled-in default, and is used at the
+ * point (if any) where an extra colon appears in path1.
+ *
+ * const char *type
+ * The type of the search (font, vf, etc.).
+ *
+ * const char *fF_etc
+ * Certain of the characters following '%' that are to be
+ * substituted with strings. This should begin with 'f' and 'F'.
+ * It should not include 'q', 'Q', 't', 's', or 'S'.
+ *
+ * char x_var_char
+ * If there is another character besides 'f' and 'F' whose
+ * corresponding string may change for different files of this
+ * type, then it should be third in fF_etc, and x_var_char
+ * should contain its value. Otherwise, x_var_char should be 'f'.
+ *
+ * int n_var_opts
+ * x_var_char == 'f' ? 2 : 3
+ *
+ * const char *no_f_str
+ * The address of the string to be implicitly added to the path
+ * component if %f was not used.
+ *
+ * const char *no_f_str_end
+ * The address of '\0' terminating the above string.
+ *
+ * int no_f_str_flags
+ * Flags to be set if no_f_str is used.
+ *
+ * const char *abs_str
+ * String to use for the path in case the font/file name begins
+ * with a '/' (indicating an absolute path).
+ *
+ * int abs_str_flags
+ * Flags to be set if abs_str is used.
+ *
+ * char pk_opt_char
+ * 'p' for pk/gf file searching (signifying that %p is to be
+ * replaced alternately with "pk" and "gf"; 'f' otherwise
+ * (signifying that there is no such character).
+ *
+ * const char **pk_gf_addr
+ * The address of a pointer that is to be alternately changed
+ * to point to "pk" or "gf", as above.
+ *
+ * const char *pct_s_str
+ * The string to be substituted for %s occurring at the end of
+ * a path component. This may not contain braces ({}), but it
+ * may consist of several strings, separated by colons.
+ *
+ * The remaining fields store information about past searches. They
+ * should be initialized to NULL or 0, as appropriate.
+ *
+ * struct steprec *stephead;
+ * Head of the first linked list of steprecs.
+ *
+ * struct steprec *pct_s_head;
+ * Head of the linked list of steprecs for %s.
+ *
+ * int pct_s_count;
+ * Length of the above linked list.
+ *
+ * const struct atomrec **pct_s_atom;
+ * An array containing linked list of atomrecs for %s.
+ *
+ * struct rootrec *rootp;
+ * Head of the linked list of rootrecs.
+ */
+
+/*
+ * Values for flags.
+ */
+
+#define F_FILE_USED 1 /* if %f was used */
+#define F_VARIABLE 2 /* if the string may change next time */
+#define F_PK_USED 4 /* if %p was used */
+#define F_PCT_T 8 /* component began with %t */
+#define F_PCT_S 16 /* put %s after this string of atoms */
+#define F_SLASH_SLASH 32 /* (atomrec) if this began with // */
+#define F_WILD 64 /* (atomrec) if wild cards present */
+#define F_QUICKFIND 128 /* (atomrec, rootrec) if %q or %Q */
+#define F_QUICKONLY 256 /* if %Q */
+
+/*
+ * Values to put in for %x specifiers.
+ */
+
+#ifndef MAX_N_OPTS
+#define MAX_N_OPTS 6
+#endif
+
+extern _Xconst char *fF_values[MAX_N_OPTS];
+
+/*
+ * Additional data structures. These are included because they are
+ * referenced in the above structure, but really they are internal
+ * to filefind.c.
+ */
+
+/*
+ * This is the main workhorse data structure. It is used (1) in a linked
+ * list, one for each component of the path; (2) in linked lists of
+ * {} alternatives; and (3) in linked lists of alternatives for %s.
+ * It contains precomputed (via lazy evaluation) information about how
+ * to lay down the candidate file name.
+ */
+
+struct steprec {
+ struct steprec *next; /* link to next record in chain */
+ _Xconst char *str; /* the string we're now looking at */
+ _Xconst char *strend;
+ int flags; /* not cumulative */
+ struct atomrec *atom;
+ struct steprec *nextstep;
+ _Xconst char *nextpart; /* only for the main linked list */
+ _Xconst char *home; /* ~ expansion result (main list only)*/
+};
+
+/*
+ * Components of a path following a // or wild card.
+ */
+
+struct atomrec {
+ struct atomrec *next;
+ _Xconst char *p; /* first char. of dir. name */
+ _Xconst char *p_end; /* last + 1 char. */
+ int flags; /* F_PCT_S or F_SLASH_SLASH (so far) */
+};
+
+/*
+ * Roots of tree structures containing information on subdirectories.
+ */
+
+struct rootrec {
+ struct rootrec *next; /* link to next in list */
+ struct treerec *tree; /* the tree */
+ int flags; /* F_QUICKFIND and F_QUICKONLY */
+ _Xconst char *fullpat; /* xlat pattern for use with ls-R */
+ _Xconst char *fullpat_end;
+ _Xconst char *keypat; /* key for ls-R database search */
+ _Xconst char *keypat_end;
+};
+
+/*
+ * Nodes in the above-mentioned tree structure.
+ */
+
+struct treerec {
+ _Xconst char *dirname;
+ struct treerec *next; /* link to next sibling */
+ struct treerec *child; /* link to subdirectories */
+ Boolean tried_already;
+ Boolean isdir;
+};
+
+/*
+ * Config file environment variable.
+ */
+
+struct envrec {
+ struct envrec *next;
+ _Xconst char *key;
+ _Xconst char *value;
+ Boolean flag;
+};
+
+extern struct envrec *ffgetenv ARGS((_Xconst char *));
diff --git a/filf-app.h b/filf-app.h
@@ -0,0 +1,45 @@
+/*========================================================================*\
+
+Copyright (c) 1996-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * filf-app.h - Application-related declarations and definitions for
+ * filefind.c
+ */
+
+
+#include "xdvi.h"
+#include <sys/stat.h>
+#include <pwd.h>
+
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#define FFDEBUG (debug & DBG_OPEN)
+#define EXTERN_FFLINE 1 /* xdvi provides this */
+#define EXTERN_GETPW 1 /* this, too */
+
+#define FFCLASS "XDvi" /* name and length of cfg file class */
+#define FFCLASS_LENGTH 4
diff --git a/font-open.c b/font-open.c
@@ -0,0 +1,2470 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "filf-app.h" /* application-related defs, etc. */
+#include "filefind.h"
+
+#include <errno.h>
+#include <signal.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+extern char *getenv ARGS((_Xconst char *));
+#endif
+
+/*
+ * If you think you have to change DEFAULT_TAIL, then you haven't read the
+ * documentation closely enough.
+ */
+
+#ifndef VMS
+#define PATH_SEP ':'
+#define DEFAULT_TAIL "/%f.%d%p"
+#define DEFAULT_VF_TAIL "/%f.vf"
+#else /* VMS */
+#define PATH_SEP '/'
+#define DEFAULT_TAIL ":%f.%d%p"
+#define DEFAULT_VF_TAIL ":%f.vf"
+#endif /* VMS */
+
+#ifndef DEFAULT_FONT_SIZES
+ /* default sizes for current dpi */
+#define DEFAULT_FONT_SIZES "m0:m0.5:m1:m2:m3:m4:m5"
+#endif
+
+#ifdef MKTEXPK
+static _Xconst char *makepkcmd = NULL;
+#endif
+
+/*
+ * Information on how to search for pk and gf files.
+ */
+
+static _Xconst char no_f_str_pkgf[] = DEFAULT_TAIL;
+
+static struct findrec search_pkgf = {
+ /* path1 */ NULL,
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ DEFAULT_FONT_PATH,
+ /* type */ "font",
+ /* fF_etc */ "fFdbpm",
+ /* x_var_char */ 'd',
+ /* n_var_opts */ 3,
+ /* no_f_str */ no_f_str_pkgf,
+ /* no_f_str_end */ no_f_str_pkgf + sizeof(no_f_str_pkgf) - 1,
+ /* abs_str */ "%f.%d%p",
+#ifdef USE_GF
+ /* no_f_str_flags */ F_FILE_USED | F_PK_USED,
+ /* abs_str_flags */ F_FILE_USED | F_PK_USED,
+ /* pk_opt_char */ 'p',
+ /* pk_gf_addr */ &fF_values[4],
+#endif
+ /* pct_s_str */ "%qfonts/%p/%m//:%qfonts/%p/modeless//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+#ifdef DOSNAMES
+
+static _Xconst char no_f_str_dos[] = "/dpi%d/%f.%p";
+
+static struct findrec search_pkgf_dos = {
+ /* path1 */ NULL,
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ DEFAULT_FONT_PATH,
+ /* type */ "font",
+ /* fF_etc */ "fFdbpm",
+ /* x_var_char */ 'd',
+ /* n_var_opts */ 3,
+ /* no_f_str */ no_f_str_dos,
+ /* no_f_str_end */ no_f_str_dos + sizeof(no_f_str_dos) - 1,
+ /* abs_str */ "%f.%d%p",
+#ifdef USE_GF
+ /* no_f_str_flags */ F_FILE_USED | F_PK_USED,
+ /* abs_str_flags */ F_FILE_USED | F_PK_USED,
+ /* pk_opt_char */ 'p',
+ /* pk_gf_addr */ &fF_values[4],
+#endif
+ /* pct_s_str */ "%qfonts/%p/%m//:%qfonts/%p/modeless//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+#endif /* DOSNAMES */
+
+/*
+ * Information on how to search for vf files.
+ */
+
+static _Xconst char no_f_str_vf[] = DEFAULT_VF_TAIL;
+
+static struct findrec search_vf = {
+ /* path1 */ NULL,
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ DEFAULT_VF_PATH,
+ /* type */ "vf",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f', /* i.e., none */
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_vf,
+ /* no_f_str_end */ no_f_str_vf + sizeof(no_f_str_vf) - 1,
+ /* abs_str */ "%f.vf",
+#ifdef USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f', /* none */
+ /* pk_gf_addr */ NULL,
+#endif
+ /* pct_s_str */ "%qfonts/vf//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+static int *sizes, *sizend;
+static char default_size_list[] = DEFAULT_FONT_SIZES;
+
+static char bdpi_string[10];
+static char dpi_string[10];
+
+static double magsteps[10] = {1.0, 1.2, 1.44, 1.728, 2.0736,
+ 2.48832, 2.985984, 3.5831808,
+ 4.29981696, 5.159780352};
+
+#if FREETYPE || PS
+
+/*
+ * Information on how to search for dvips configuration files.
+ */
+
+static _Xconst char no_f_str_dvips_cf[] = "/%f";
+
+static struct findrec search_dvips_cf = {
+ /* path1 */ NULL,
+# if CFGFILE
+ /* envptr */ NULL,
+# endif
+ /* path2 */ DEFAULT_DVIPS_CF_PATH,
+ /* type */ "dvips config",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f', /* i.e., none */
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_dvips_cf,
+ /* no_f_str_end */ no_f_str_dvips_cf + sizeof no_f_str_dvips_cf -1,
+ /* abs_str */ "%f",
+# if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f', /* none */
+ /* pk_gf_addr */ NULL,
+# endif
+ /* pct_s_str */ "%qdvips//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+/*
+ * Information on how to search for (dvips-style) map files.
+ */
+
+static _Xconst char no_f_str_fontmap[] = "/%f";
+
+static struct findrec search_fontmap = {
+ /* path1 */ NULL,
+# if CFGFILE
+ /* envptr */ NULL,
+# endif
+ /* path2 */ DEFAULT_FONTMAP_PATH,
+ /* type */ "font map",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f', /* i.e., none */
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_fontmap,
+ /* no_f_str_end */ no_f_str_fontmap + sizeof no_f_str_fontmap -1,
+ /* abs_str */ "%f",
+# if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f', /* none */
+ /* pk_gf_addr */ NULL,
+# endif
+ /* pct_s_str */ "%qfonts/map/{xdvi,dvips,pdftex}//:%qfonts/map//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+/*
+ * Information on how to search for font encoding files.
+ */
+
+static _Xconst char no_f_str_enc[] = "/%f";
+
+static struct findrec search_enc = {
+ /* path1 */ no_f_str_enc, /* flag value: uninitialized */
+# if CFGFILE
+ /* envptr */ NULL,
+# endif
+ /* path2 */ DEFAULT_ENC_PATH,
+ /* type */ "font encoding",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f', /* i.e., none */
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_enc,
+ /* no_f_str_end */ no_f_str_enc + sizeof no_f_str_enc -1,
+ /* abs_str */ "%f",
+# if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f', /* none */
+ /* pk_gf_addr */ NULL,
+# endif
+ /* pct_s_str */ "%qfonts/enc//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+/*
+ * Information on how to search for Type 1 fonts.
+ */
+
+static _Xconst char no_f_str_type1[] = "/%f";
+
+static struct findrec search_type1 = {
+ /* path1 */ no_f_str_type1, /* flag value: uninitialized */
+# if CFGFILE
+ /* envptr */ NULL,
+# endif
+ /* path2 */ DEFAULT_TYPE1_PATH,
+ /* type */ "Type 1 font",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f',
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_type1,
+ /* no_f_str_end */ no_f_str_type1 + sizeof(no_f_str_type1) - 1,
+ /* abs_str */ "%f",
+# if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f',
+ /* pk_gf_addr */ NULL,
+# endif
+ /* pct_s_str */ "%qfonts/type1//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+#endif /* FREETYPE || PS */
+
+
+static int
+atosize(p)
+ _Xconst char *p;
+{
+ _Xconst char *q;
+ Boolean minus;
+ double factor;
+
+ if (*p != 'm')
+ return atoi(p);
+
+ for (q = "agstep";; ++q) {
+ ++p;
+ if (*q == '\0' || *p != *q) break;
+ }
+
+ minus = False;
+ if (*p == '-') {
+ minus = True;
+ ++p;
+ }
+
+ if (*p < '0' || *p > '9')
+ return 0;
+ factor = magsteps[*p - '0'];
+ ++p;
+
+ if (*p == '.' && p[1] == '5')
+ factor *= 1.0954451150103321; /* sqrt(1.2) */
+
+ return (int)
+ ((minus ? pixels_per_inch / factor : pixels_per_inch * factor) + 0.5);
+}
+
+static void
+get_sizes(size_list, spp)
+ char *size_list;
+ int **spp;
+{
+ if (*size_list == PATH_SEP) ++size_list;
+ for (;;) {
+ *(*spp)++ = atosize(size_list);
+ size_list = index(size_list, PATH_SEP);
+ if (size_list == NULL) return;
+ ++size_list;
+ }
+}
+
+
+#if FREETYPE || PS
+
+/*
+ * The following code handles lookup of Type 1 fonts for use as FreeType
+ * fonts, and for use within MetaPost output.
+ * The system psfonts.map file is read into an AVL tree as needed (lazy
+ * evaluation), and searched for Type 1 fonts.
+ */
+
+struct p_list { /* list of map file names */
+ struct p_list *next;
+ _Xconst char *value;
+};
+
+ /* Initialize this list to "psfonts.map". */
+
+static struct p_list psfonts_map = {NULL, "psfonts.map"};
+
+static struct p_list *p_head = &psfonts_map;
+static struct p_list **p_tail = &psfonts_map.next;
+
+static FILE *mapfile = NULL;
+
+static Boolean
+fgets_long(f)
+ FILE *f;
+{
+ int len;
+
+ if (fgets(ffline, ffline_len, f) == NULL)
+ return False;
+
+ len = 0;
+ for (;;) {
+ len += strlen(ffline + len);
+ if (len > 0 && ffline[len - 1] == '\n') {
+ ffline[--len] = '\0';
+ break;
+ }
+ if (len < ffline_len - 1)
+ break;
+ expandline(len);
+ fgets(ffline + len, ffline_len - len, f);
+ }
+
+ return True;
+}
+
+/*
+ * Get list of map files from dvips config file(s).
+ */
+
+static void
+getdefaults(f)
+ FILE *f;
+{
+ char *p, *q;
+ int len;
+ struct p_list *p_node;
+
+ while (fgets_long(f)) {
+ p = ffline;
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p == 'p') {
+ do ++p;
+ while (*p == ' ' || *p == '\t');
+
+ if (*p == '+')
+ do ++p;
+ while (*p == ' ' || *p == '\t');
+ else { /* discard old list */
+ struct p_list *pl, *pl2;
+
+ *p_tail = NULL;
+ pl = p_head;
+ if (pl == &psfonts_map) pl = pl->next;
+ while (pl != NULL) {
+ free((char *) pl->value);
+ pl2 = pl->next;
+ free(pl);
+ pl = pl2;
+ }
+ p_tail = &p_head;
+ }
+
+ /* get white-delimited argument */
+ len = strlen(p);
+ q = memchr(p, ' ', len);
+ if (q != NULL) len = q - p;
+ q = memchr(p, '\t', len);
+ if (q != NULL) len = q - p;
+ p[len] = '\0';
+
+ p_node = xmalloc(sizeof *p_node);
+ p_node->value = xmemdup(p, len + 1);
+ *p_tail = p_node;
+ p_tail = &p_node->next;
+ }
+ }
+
+ Fclose(f);
+ ++n_files_left;
+}
+
+
+/*
+ * Information about Type 1 fonts is stored in an AVL tree.
+ */
+
+static struct avl_t1 *t1_head = NULL;
+
+
+/*
+ * Parse line from psfonts.map file.
+ */
+
+static struct avl_t1 *
+dvips_parse(line)
+ _Xconst char *line;
+{
+ _Xconst char *w1p, *encp, *pfp, *qp;
+ size_t w1l, encl, pfl, ql;
+ _Xconst char *w2p;
+ size_t w2l;
+ _Xconst char *p, *p0;
+ _Xconst char *err;
+ struct avl_t1 *t1p;
+ char *q;
+
+ w2l = w1l = encl = pfl = ql = 0;
+ err = NULL;
+ p = line;
+ for (;;) { /* loop over words */
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p == '\0')
+ break;
+
+ if (*p == '"') { /* quoted string */
+ _Xconst char *p_end;
+
+ p0 = p + 1;
+ p_end = p0 + strlen(p0);
+ p = memchr(p0, '"', p_end - p0);
+ if (p == NULL) p = p_end;
+ qp = (ql == 0 ? p0 : NULL);
+ ql += p - p0 + 1;
+ if (*p == '"') ++p;
+ continue;
+ }
+
+ if (*p == '<') { /* encoding or pfa/b file */
+ int wtype = 0;
+
+ ++p;
+ if (*p == '<') {
+ wtype = 1; /* font file */
+ ++p;
+ }
+ else if (*p == '[') {
+ wtype = -1; /* encoding file */
+ ++p;
+ }
+
+ /* find word */
+ while (*p == ' ' || *p == '\t') ++p;
+ p0 = p;
+ while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
+
+ if (wtype == 0 && p > p0 + 4 && p[-4] == '.') {
+ if (memcmp(p - 3, "enc", 3) == 0
+ || memcmp(p - 3, "ENC", 3) == 0)
+ wtype = -1;
+ else if (memcmp(p - 3, "pfa", 3) == 0
+ || memcmp(p - 3, "pfb", 3) == 0
+ || memcmp(p - 3, "PFA", 3) == 0
+ || memcmp(p - 3, "PFB", 3) == 0)
+ wtype = 1;
+ }
+
+ if (wtype > 0) {
+ if (pfl != 0)
+ err = "more than one font file given";
+ else {
+ pfp = p0;
+ pfl = p - p0 + 1;
+ }
+ }
+ else if (wtype < 0) {
+ if (encl != 0)
+ err = "more than one encoding file given";
+ else {
+ encp = p0;
+ encl = p - p0 + 1;
+ }
+ }
+ else
+ err = "cannot identify file type";
+ }
+ else { /* if ordinary word */
+ p0 = p;
+ while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
+ if (w1l == 0) {
+ w1p = p0;
+ w1l = p - p0;
+ }
+ else if (w2l == 0) {
+ w2p = p0;
+ w2l = p - p0;
+ }
+ else
+ err = "more than two non-download words given";
+ }
+ } /* end loop over words */
+
+ if (w1l == 0) {
+ if (debug & DBG_OPEN)
+ Fprintf(stderr,
+ "%s: map file %s: line \"%s\" does not give a font name.\n",
+ prog, p_head->value, line);
+ return NULL;
+ }
+
+ if (err != NULL) {
+ if (debug & DBG_OPEN)
+ Fprintf(stderr, "%s: map file %s, font %.*s: %s\n", prog,
+ p_head->value, (int) w1l, w1p, err);
+ return NULL;
+ }
+
+ t1p = (struct avl_t1 *) avladd(w1p, w1l, (struct avl **) &t1_head,
+ sizeof(struct avl_t1));
+
+ if (t1p->key != w1p) { /* if existing record */
+ if (debug & DBG_OPEN)
+ Fprintf(stderr,
+ "%s: map file %s, font %.*s: duplicate record; using first one\n",
+ prog, p_head->value, (int) w1l, w1p);
+ return NULL;
+ }
+
+ t1p->key = q = xmalloc(w1l + w2l + 1 + pfl + encl + ql);
+
+ memcpy(q, w1p, w1l);
+ q += w1l;
+ t1p->psname = t1p->key;
+ if (w2l != 0) {
+ t1p->psname = q;
+ memcpy(q, w2p, w2l);
+ q += w2l;
+ }
+ *q++ = '\0';
+
+ t1p->fontfile = NULL;
+ if (pfl != 0) {
+ t1p->fontfile = q;
+ memcpy(q, pfp, pfl - 1);
+ q += pfl;
+ q[-1] = '\0';
+ }
+
+ t1p->encname = t1p->addinfo = NULL;
+# if FREETYPE
+ t1p->bad = False;
+ t1p->ft = NULL;
+# endif
+
+ if (encl != 0) {
+ t1p->encname = q;
+ memcpy(q, encp, encl - 1);
+ q += encl;
+ q[-1] = '\0';
+ }
+
+ if (ql != 0) {
+ t1p->addinfo = q;
+ if (qp != 0) {
+ memcpy(q, qp, ql - 1);
+ q += ql;
+ }
+ else { /* multiple quoted strings; rescan to get them */
+ _Xconst char *p_end;
+
+ p = line;
+ p_end = p + strlen(p);
+ for (;;) {
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p == '\0')
+ break;
+
+ /* found a word */
+ if (*p == '"') {
+ ++p;
+ p0 = p;
+ p = memchr(p0, '"', p_end - p0);
+ if (p == NULL) p = p_end;
+ memcpy(q, p0, p - p0);
+ q += p - p0;
+ *q++ = ' ';
+ if (*p == '\0') break;
+ ++p;
+ }
+ else /* skip unquoted word */
+ while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
+ }
+ }
+ q[-1] = '\0';
+ }
+
+ return t1p;
+}
+
+/*
+ * Information on the Ghostscript font aliasing mechanism is kept in
+ * another AVL tree. Each identifier points to a list of strings,
+ * up to one from each Fontmap file. Within a Fontmap file, later entries
+ * for a given string override earlier ones.
+ */
+
+struct avl_gs { /* structure for gs font information */
+ AVL_COMMON;
+ short fontmap_number; /* sequence of most recent entry */
+ Boolean in_use;
+ struct gs_list *list;
+};
+
+struct gs_list { /* list of Fontmap entries for this font name */
+ struct gs_list *next;
+ _Xconst char value[0];
+};
+
+static struct avl_gs *gs_head = NULL;
+
+typedef void (*gs_path_proc) ARGS((FILE *));
+
+static _Xconst char *env_gs_lib;
+
+static FILE *
+gs_try_fopen(str, len, name)
+ _Xconst char *str;
+ unsigned int len;
+ _Xconst char *name;
+{
+ unsigned int namelen = strlen(name) + 1;
+ FILE *f;
+
+ if (len + namelen + 1 > ffline_len) expandline(len + namelen + 1);
+ memcpy(ffline, str, len);
+ ffline[len] = '/';
+ memcpy(ffline + len + 1, name, namelen);
+
+ f = xfopen(ffline, OPEN_MODE);
+
+ if (debug & DBG_OPEN)
+ Printf("gs_try_fopen: %s: %s\n", ffline,
+ f != NULL ? "file opened" : strerror(errno));
+
+ return f;
+}
+
+static FILE *
+gs_path_fopen(name, proc)
+ _Xconst char *name;
+ gs_path_proc proc;
+{
+ _Xconst char *str1 = env_gs_lib;
+ _Xconst char *str2 = DEFAULT_GS_LIB_PATH;
+ _Xconst char *str1_end, *str2_end;
+ _Xconst char *p1, *p2;
+ FILE *f;
+
+ if (str1 == NULL) {
+ str1 = str2;
+ str2 = NULL;
+ }
+
+ str1_end = str1 + strlen(str1);
+
+ for (;;) {
+ p1 = memchr(str1, ':', str1_end - str1);
+ if (p1 == NULL) p1 = str1_end;
+ if (p1 == str1) {
+ if (str2 != NULL) {
+ str2_end = str2 + strlen(str2);
+ for (;;) {
+ p2 = memchr(str2, ':', str2_end - str2);
+ if (p2 == NULL) p2 = str2_end;
+ if (p2 > str2) {
+ f = gs_try_fopen(str2, p2 - str2, name);
+ if (f != NULL) {
+ if (proc != NULL)
+ proc(f);
+ else
+ return f;
+ }
+ }
+ if (*p2 == '\0')
+ break;
+ str2 = p2 + 1;
+ }
+ str2 = NULL;
+ }
+ }
+ else {
+ f = gs_try_fopen(str1, p1 - str1, name);
+ if (f != NULL) {
+ if (proc != NULL)
+ proc(f);
+ else
+ return f;
+ }
+ }
+
+ if (*p1 == '\0')
+ break;
+ str1 = p1 + 1;
+ }
+
+ return NULL;
+}
+
+
+static FILE *
+lookup_gs_font(font, path_ret)
+ _Xconst char *font;
+ _Xconst char **path_ret;
+{
+ struct avl_gs *gsfp;
+ int font_len;
+ int i;
+
+ font_len = strlen(font);
+ gsfp = gs_head;
+ for (;;) {
+ if (gsfp == NULL) /* if not found */
+ return NULL;
+
+ i = font_len - gsfp->key_len;
+ if (i == 0)
+ i = memcmp(font, gsfp->key, font_len);
+ if (i == 0) { /* if found */
+ struct gs_list *gl, *gl2, *gl3;
+ FILE *f;
+
+ if (gsfp->in_use) {
+ if (debug & DBG_OPEN)
+ Printf("Alias loop for %s detected; ignoring.\n", font);
+ return NULL;
+ }
+
+ /* If we haven't done it yet, reverse the linked list */
+ if (gsfp->fontmap_number != 0) {
+ gsfp->fontmap_number = 0;
+ gl = gsfp->list;
+ gl2 = NULL;
+ while (gl != NULL) {
+ gl3 = gl->next;
+ gl->next = gl2;
+ gl2 = gl;
+ gl = gl3;
+ }
+ gsfp->list = gl2;
+ }
+ gsfp->in_use = True;
+ f = NULL;
+ for (gl = gsfp->list; gl != NULL; gl = gl->next) {
+ if (gl->value[0] == '\0') { /* if alias */
+ if (debug & DBG_OPEN)
+ Printf("Found alias %s --> %s\n", font,
+ gl->value + 1);
+ f = lookup_gs_font(gl->value + 1, path_ret);
+ if (debug & DBG_OPEN)
+ if (f == NULL)
+ Printf("Alias %s not found.\n", gl->value + 1);
+ if (f != NULL) break;
+ }
+ else {
+ if (debug & DBG_OPEN)
+ Printf("Checking file %s\n", gl->value);
+ if (gl->value[0] == '/' || (gl->value[0] == '.'
+ && (gl->value[1] == '/' || (gl->value[1] == '.'
+ && gl->value[2] == '/')))) {
+ f = xfopen(gl->value, OPEN_MODE);
+ if (f != NULL) {
+ *path_ret = xstrdup(gl->value);
+ break;
+ }
+ }
+ else {
+ f = gs_path_fopen(gl->value, NULL);
+ if (f != NULL) {
+ *path_ret = xstrdup(ffline);
+ break;
+ }
+ }
+ }
+ }
+ gsfp->in_use = False;
+ return f;
+ }
+ gsfp = (struct avl_gs *) (i < 0 ? gsfp->left : gsfp->right);
+ }
+}
+
+
+#define GS_BUF_SIZE 4096
+
+struct gsfile {
+ FILE *f;
+ unsigned char *buffer;
+ _Xconst unsigned char *bufpos;
+ _Xconst unsigned char *buf_end;
+};
+
+static Boolean
+gs_fillbuf(gsf)
+ struct gsfile *gsf;
+{
+ unsigned char *p;
+ unsigned int len;
+
+ if (gsf->buf_end < gsf->buffer + GS_BUF_SIZE)
+ return False;
+
+ gsf->bufpos = p = gsf->buffer;
+ for (;;) {
+ len = gsf->buf_end - p;
+ if (len <= 0) break;
+ len = fread(p, 1, len, gsf->f);
+ if (len <= 0) break;
+ p += len;
+ }
+ gsf->buf_end = p;
+ return (p > gsf->buffer);
+}
+
+static unsigned char gs_ctype[256];
+
+#define GS_EOF '\0'
+#define GS_ERR '%'
+#define LPAREN '('
+#define RPAREN ')'
+
+static void
+init_gs_ctype()
+{
+ _Xconst char *p;
+
+ for (p = " \t\f\n\r";; ++p) {
+ gs_ctype[(unsigned char) *p] = 1; /* white space */
+ if (*p == '\0') break;
+ }
+ gs_ctype['/'] = 2; /* literal token */
+ gs_ctype['('] = 3; /* string */
+ for (p = ")<>[]{}%"; *p != '\0'; ++p)
+ gs_ctype[(unsigned char) *p] = 4; /* delimiter */
+}
+
+static unsigned char
+get_gs_character(gsfp)
+ struct gsfile *gsfp;
+{
+ unsigned char c;
+
+ for (;;) {
+ if (gsfp->bufpos >= gsfp->buf_end && !gs_fillbuf(gsfp))
+ return '%';
+ c = *gsfp->bufpos++;
+
+ /* Check for comments */
+ if (c == '%') {
+ for (;;) {
+ _Xconst unsigned char *p1, *p2;
+
+ p1 = memchr(gsfp->bufpos, '\n',
+ gsfp->buf_end - gsfp->bufpos);
+ if (p1 == NULL) p1 = gsfp->buf_end;
+ p2 = memchr(gsfp->bufpos, '\r', p1 - gsfp->bufpos);
+ if (p2 != NULL) p1 = p2;
+ p2 = memchr(gsfp->bufpos, '\f', p1 - gsfp->bufpos);
+ if (p2 != NULL) p1 = p2;
+ if (p1 < gsfp->buf_end) {
+ gsfp->bufpos = p1 + 1;
+ break;
+ }
+ if (!gs_fillbuf(gsfp))
+ return '%';
+ }
+ continue;
+ }
+
+ if (gs_ctype[c] != 1)
+ break;
+ }
+
+ return c;
+}
+
+static unsigned char
+get_gs_token(gsfp, pos, pos_ret, file_type)
+ struct gsfile *gsfp;
+ unsigned int pos;
+ unsigned int *pos_ret;
+ _Xconst char *file_type;
+{
+ unsigned char gs_t_type;
+ unsigned char c;
+ _Xconst unsigned char *p0;
+ unsigned int pos0;
+ unsigned int depth;
+
+ gs_t_type = c = get_gs_character(gsfp);
+ if (c == '%')
+ return GS_EOF;
+
+ p0 = gsfp->bufpos;
+ switch (gs_ctype[c]) {
+ case 0: /* most characters */
+ case 2: /* '/' */
+ --p0; /* retain initial character */
+ pos0 = pos;
+ for (;;) {
+ if (gsfp->bufpos >= gsfp->buf_end) {
+ unsigned int len = gsfp->bufpos - p0;
+
+ if (pos + len >= ffline_len) expandline(pos + len);
+ bcopy(p0, ffline + pos, len);
+ pos += len;
+ if (!gs_fillbuf(gsfp))
+ break;
+ p0 = gsfp->buffer;
+ }
+ if (gs_ctype[*gsfp->bufpos] != 0) {
+ unsigned int len = gsfp->bufpos - p0;
+
+ if (pos + len >= ffline_len) expandline(pos + len);
+ bcopy(p0, ffline + pos, len);
+ pos += len;
+ break;
+ }
+ ++gsfp->bufpos;
+ }
+ /* Filter out DOS ^Z */
+ if (pos == pos0 + 1 && ffline[pos0] == '\032')
+ return GS_EOF;
+ break;
+
+ case 3: /* left parenthesis */
+ depth = 1;
+ for (;;) {
+ _Xconst unsigned char *p1, *p2, *p3;
+
+ if (gsfp->bufpos >= gsfp->buf_end) {
+ unsigned int len = gsfp->bufpos - p0;
+
+ if (pos + len >= ffline_len) expandline(pos + len);
+ bcopy(p0, ffline + pos, len);
+ pos += len;
+ if (!gs_fillbuf(gsfp)) {
+ Fprintf(stderr,
+ "%s: unterminated string in %s file; giving up.\n"
+ ,
+ prog, file_type);
+ return GS_ERR;
+ }
+ p0 = gsfp->buffer;
+ }
+ p1 = memchr(gsfp->bufpos, RPAREN,
+ gsfp->buf_end - gsfp->bufpos);
+ if (p1 == NULL) p1 = gsfp->buf_end;
+ for (;;) {
+ p2 = memchr(gsfp->bufpos, LPAREN, p1 - gsfp->bufpos);
+ if (p2 == NULL) p2 = p1;
+ p3 = p2;
+ for (;;) {
+ if (p3 <= gsfp->bufpos) {
+ if (c == '\\') --p3;
+ break;
+ }
+ if (p3[-1] != '\\') break;
+ --p3;
+ }
+ c = '\\' - 1 + ((p2 - p3) & 1);
+ if (p2 >= p1)
+ break;
+ if (c != '\\')
+ ++depth;
+ gsfp->bufpos = p2 + 1;
+ c = '\0';
+ }
+ if (p1 < gsfp->buf_end) { /* if left parenthesis at p1 */
+ if (c != '\\') {
+ if (--depth == 0) {
+ unsigned int len = p1 - p0;
+
+ if (pos + len >= ffline_len)
+ expandline(pos + len);
+ bcopy(p0, ffline + pos, len);
+ pos += len;
+ gsfp->bufpos = p1 + 1;
+ break;
+ }
+ }
+ ++p1;
+ }
+ gsfp->bufpos = p1;
+ }
+ /* We could do backslash escaping here, but it's probably
+ unnecessary. */
+ break;
+
+ default:
+ Fprintf(stderr,
+ "%s: invalid character `%c' encountered in %s file; giving up.\n",
+ prog, c, file_type);
+ return GS_ERR;
+ }
+
+ *pos_ret = pos;
+ return gs_t_type;
+}
+
+
+static short gs_fontmap_number = 0;
+
+static void
+process_gs_fontmap P1C(FILE *, f)
+{
+ struct gsfile gsf;
+ unsigned char buffer[GS_BUF_SIZE];
+ unsigned char ttype;
+ unsigned int pos1, pos2, pos3;
+
+ ++gs_fontmap_number;
+
+ gsf.f = f;
+ gsf.buffer = buffer;
+ gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE;
+
+ /*
+ * Allow entries of the following types:
+ *
+ * (string) .runlibfile
+ * /identifier (string) ;
+ * /identifier /alias ;
+ */
+
+ for (;;) {
+ ttype = get_gs_token(&gsf, 0, &pos1, "Fontmap");
+ if (ttype == GS_EOF || ttype == GS_ERR)
+ break;
+ if (ttype == LPAREN) {
+ FILE *f1;
+
+ ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap");
+ if (ttype == GS_ERR)
+ break;
+ if (ttype == GS_EOF) {
+ Fprintf(stderr,
+ "%s: unexpected end of Fontmap file; giving up.\n", prog);
+ break;
+ }
+ if (ttype != '.' || pos2 - pos1 != 11
+ || memcmp(ffline + pos1, ".runlibfile", 11) != 0) {
+ Fprintf(stderr, "%s: invalid token following \"(%.*s)\" in Fontmap file; giving up.\n",
+ prog, (int) pos1, ffline);
+ break;
+ }
+
+ ffline[pos1] = '\0';
+ if (ffline[0] == '/' || (ffline[0] == '.' && (ffline[1] == '/'
+ || (ffline[1] == '.' && ffline[2] == '/'))))
+ f1 = xfopen(ffline, OPEN_MODE);
+ else {
+ char *q;
+
+ q = xmemdup(ffline, pos1 + 1);
+ f1 = gs_path_fopen(q, NULL);
+ free(q);
+ }
+
+ if (f1 == NULL)
+ Fprintf(stderr, "%s: Fontmap .runlibfile: %s: %s\n",
+ prog, ffline, strerror(errno));
+ else {
+ --gs_fontmap_number;
+ process_gs_fontmap(f1);
+ }
+ }
+ else if (ttype == '/') {
+ struct avl_gs *gsfp;
+ struct gs_list *gslp;
+
+ ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap");
+ if (ttype == GS_ERR)
+ break;
+ if (ttype == GS_EOF) {
+ Fprintf(stderr,
+ "%s: unexpected end of Fontmap file; giving up.\n", prog);
+ break;
+ }
+ if ((ttype != '/' && ttype != LPAREN)
+ || pos2 == pos1 /* empty string would mess things up */
+ || get_gs_token(&gsf, pos2, &pos3, "Fontmap") != ';'
+ || pos3 != pos2 + 1) {
+ Fprintf(stderr,
+ "%s: invalid token following \"%.*s\" in Fontmap file; giving up.\n",
+ prog, (int) pos1, ffline);
+ break;
+ }
+ if (ttype == '/')
+ ffline[pos1] = '\0'; /* mark aliases by initial \0 */
+ ffline[pos2++] = '\0'; /* terminate string */
+
+ /* Add to database */
+ gsfp = (struct avl_gs *) avladd(ffline + 1, pos1 - 1,
+ (struct avl **) &gs_head, sizeof *gsfp);
+
+ if (gsfp->key == ffline + 1) { /* if new record */
+ gsfp->key = xmemdup(ffline + 1, pos1 - 1);
+ gsfp->in_use = False;
+ gsfp->list = NULL;
+ }
+ else {
+ if (strlen(gsfp->list->value + 1) + 2 == pos2 - pos1
+ && memcmp(gsfp->list->value, ffline + pos1, pos2 - pos1)
+ == 0)
+ continue; /* ignore duplicate entry */
+ if (gsfp->fontmap_number == gs_fontmap_number) {
+ /* Later entries in a Fontmap file override earlier
+ ones */
+ gslp = gsfp->list;
+ gsfp->list = gslp->next;
+ free(gslp);
+ }
+ }
+ gslp = xmalloc(sizeof *gslp + pos2 - pos1);
+ gslp->next = gsfp->list;
+ gsfp->list = gslp;
+ memcpy((char *) gslp->value, ffline + pos1, pos2 - pos1);
+
+ gsfp->fontmap_number = gs_fontmap_number;
+ }
+ else {
+ Fprintf(stderr, "%s: invalid token \"%s\" in Fontmap file; giving up.\n",
+ prog, ffline);
+ }
+ }
+
+ Fclose(f);
+ ++n_files_left;
+}
+
+/*
+ * Read Ghostscript Fontmap files. These are used if the line in
+ * psfonts.map does not contain a filename for the font.
+ *
+ * For example:
+ * n019003l NimbusSanL-Regu
+ */
+
+static void
+read_gs_fontmaps()
+{
+ env_gs_lib = getenv("XDVI_GS_LIB");
+ if (env_gs_lib == NULL)
+ env_gs_lib = getenv("GS_LIB");
+
+ if (gs_ctype[0] == 0)
+ init_gs_ctype();
+
+ (void) gs_path_fopen("Fontmap", process_gs_fontmap);
+}
+
+
+/*
+ * pre_lookup_t1_font - Find a Type 1 font (or return NULL).
+ */
+
+static struct avl_t1 *
+pre_lookup_t1_font(fontname)
+ _Xconst char *fontname;
+{
+ struct avl_t1 *t1p;
+ size_t len;
+ int i;
+
+ /* first, search for the font */
+
+ len = strlen(fontname);
+ t1p = t1_head;
+ while (t1p != NULL) {
+ i = len - t1p->key_len;
+ if (i == 0)
+ i = memcmp(fontname, t1p->key, len);
+ if (i == 0)
+ return t1p; /* found it */
+ t1p = (struct avl_t1 *) (i < 0 ? t1p->left : t1p->right);
+ }
+
+ /* next, read in more records in hopes of finding the font */
+
+ if (p_head != NULL)
+ for (;;) {
+ if (!fgets_long(mapfile)) { /* if end of file */
+ Fclose(mapfile);
+ ++n_files_left;
+ for (;;) {
+ p_head = p_head->next;
+ if (p_head == NULL)
+ return NULL;
+ mapfile = filefind(p_head->value, &search_fontmap,
+ NULL);
+ if (mapfile != NULL) {
+ if (debug & DBG_OPEN)
+ printf("Map file: %s\n", p_head->value);
+ break;
+ }
+ Fprintf(stderr, "%s: cannot open map file %s\n", prog,
+ p_head->value);
+ }
+ continue;
+ }
+
+ if (*ffline < ' ' || *ffline == '*' || *ffline == '#'
+ || *ffline == ';' || *ffline == '%')
+ continue;
+
+ t1p = dvips_parse(ffline);
+
+ if (t1p != NULL && t1p->key_len == len
+ && memcmp(t1p->key, fontname, len) == 0)
+ return t1p; /* found it */
+ }
+
+ return NULL;
+}
+
+/*
+ * lookup_t1_font - Find a Type 1 font (or return NULL).
+ */
+
+# if FREETYPE
+
+static struct avl_t1 *
+lookup_t1_font(fontp)
+ struct font *fontp;
+{
+ struct avl_t1 *t1p;
+ struct ftfont *ftp;
+
+ t1p = pre_lookup_t1_font(fontp->fontname);
+
+ if (t1p == NULL)
+ return NULL;
+
+ if (t1p->bad) {
+ if (debug & DBG_OPEN)
+ Printf("Font %s is marked as bad: skipping scalable version\n",
+ fontp->fontname);
+ return NULL;
+ }
+
+ ftp = t1p->ft;
+ if (ftp != NULL) { /* if it's is already in use at another size */
+ struct font *first_size;
+
+ /* The first node in the linked list of sizes contains the file */
+ /* reference, so we link in the new node after the first node */
+ first_size = ftp->first_size;
+ fontp->next_size = first_size->next_size;
+ first_size->next_size = fontp;
+ }
+ else { /* first use at this size */
+ t1p->ft = ftp = xmalloc(sizeof *ftp);
+ ftp->face = NULL;
+ ftp->t1 = t1p;
+ ftp->first_size = fontp;
+ fontp->next_size = NULL;
+ }
+ fontp->ft = ftp;
+ fontp->size = NULL;
+
+ return t1p;
+}
+
+# endif /* FREETYPE */
+
+FILE *
+open_t1_font(t1p, path_ret)
+ struct avl_t1 *t1p;
+ _Xconst char **path_ret;
+{
+ FILE *f;
+
+ /*
+ * Set up the search paths, if necessary.
+ */
+
+ if (search_type1.path1 == no_f_str_type1) { /* if uninitialized */
+# if CFGFILE
+ if ((search_type1.path1 = getenv("XDVIT1FONTS")) == NULL
+ && (search_type1.path1 = getenv("T1FONTS")) == NULL
+ && (search_type1.path1 = getenv("T1INPUTS")) == NULL
+ && (search_type1.path1 = getenv("TEXFONTS")) == NULL
+ && (search_type1.path1 = getenv("XDVIHEADERS")) == NULL
+ && (search_type1.path1 = getenv("TEXPSHEADERS")) == NULL)
+ search_type1.path1 = getenv("PSHEADERS");
+ search_type1.envptr = ffgetenv("T1FONTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_type1.envptr != NULL
+ && search_type1.envptr->value == NULL)
+ search_type1.envptr = NULL;
+# else /* not CFGFILE */
+ if ((search_type1.path1 = getenv("XDVIT1FONTS")) == NULL
+ && (search_type1.path1 = getenv("T1FONTS")) == NULL
+ && (search_type1.path1 = getenv("T1INPUTS")) == NULL
+ && (search_type1.path1 = getenv("TEXFONTS")) == NULL
+ && (search_type1.path1 = getenv("XDVIHEADERS")) == NULL
+ && (search_type1.path1 = getenv("TEXPSHEADERS")) == NULL
+ && (search_type1.path1 = getenv("PSHEADERS")) == NULL) {
+ search_type1.path1 = search_type1.path2;
+ search_type1.path2 = NULL;
+ }
+# endif /* not CFGFILE */
+ }
+
+ if (t1p->fontfile == NULL) { /* look up in GS Fontmap */
+ static Boolean gs_fontmap_initialized = False;
+
+ if (!gs_fontmap_initialized) {
+ read_gs_fontmaps();
+ gs_fontmap_initialized = True;
+ }
+
+ if (debug & DBG_OPEN)
+ Printf(
+ "Looking for font %.*s using gs method (PS name %s) --\n",
+ t1p->key_len, t1p->key, t1p->psname);
+ f = lookup_gs_font(t1p->psname, path_ret);
+
+ if (f == NULL) {
+ Fprintf(stderr, "%s: cannot find Type 1 font %s\n", prog,
+ t1p->psname);
+ return NULL;
+ }
+
+ if (debug & DBG_OPEN)
+ Printf("Found file %s\n", *path_ret);
+ }
+ else {
+ f = filefind(t1p->fontfile, &search_type1, path_ret);
+
+ if (f == NULL) {
+ Fprintf(stderr, "%s: cannot find Type 1 font file %s (will try PK version instead)\n",
+ prog, t1p->fontfile);
+ return NULL;
+ }
+ }
+
+ return f;
+}
+
+
+/*
+ * Read the encoding vector file. This assumes the same format as afm2tfm.
+ */
+
+void
+read_encoding(encp)
+ struct avl_enc *encp;
+{
+ FILE *f;
+ struct gsfile gsf;
+ unsigned char buffer[GS_BUF_SIZE];
+ jmp_buf err_env;
+ unsigned char ttype;
+ unsigned int pos1, pos2;
+ unsigned int identindex[256];
+ _Xconst char *str;
+ unsigned int i;
+
+ if (debug & DBG_OPEN)
+ Printf("Reading encoding file %s\n", encp->key);
+
+ encp->valid = False;
+
+ /*
+ * Set up the search paths, if necessary.
+ */
+
+ if (search_enc.path1 == no_f_str_enc) { /* if uninitialized */
+# if CFGFILE
+ if ((search_enc.path1 = getenv("XDVIENCS")) == NULL
+ && (search_enc.path1 = getenv("ENCFONTS")) == NULL)
+ search_enc.path1 = getenv("TEXFONTS");
+ search_enc.envptr = ffgetenv("ENCFONTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_enc.envptr != NULL && search_enc.envptr->value == NULL)
+ search_enc.envptr = NULL;
+# else /* not CFGFILE */
+ if ((search_enc.path1 = getenv("XDVIENCS")) == NULL
+ && (search_enc.path1 = getenv("ENCFONTS")) == NULL
+ && (search_enc.path1 = getenv("TEXFONTS")) == NULL) {
+ search_enc.path1 = search_enc.path2;
+ search_enc.path2 = NULL;
+ }
+# endif /* not CFGFILE */
+ }
+
+ f = filefind(encp->key, &search_enc, NULL);
+ if (f == NULL) {
+ Fprintf(stderr,
+ "%s: cannot find encoding file %s; ignoring encoding\n",
+ prog, encp->key);
+ return;
+ }
+
+ if (gs_ctype[0] == 0)
+ init_gs_ctype();
+
+ gsf.f = f;
+ gsf.buffer = buffer;
+ gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE;
+
+ if (!setjmp(err_env)) {
+ if (get_gs_token(&gsf, 0, &pos1, "encoding") != '/'
+ || get_gs_character(&gsf) != '[')
+ longjmp(err_env, 1);
+
+ pos1 = 0;
+ for (i = 0; i < 256; ++i) {
+ if (get_gs_token(&gsf, pos1, &pos2, "encoding") != '/')
+ longjmp(err_env, 1);
+ if (pos2 == pos1 + 8
+ && memcmp(ffline + pos1, "/.notdef", 8) == 0)
+ identindex[i] = 0;
+ else {
+ ffline[pos1] = '\0';
+ identindex[i] = pos1 + 1;
+ pos1 = pos2;
+ }
+ }
+
+ if (get_gs_character(&gsf) != ']')
+ longjmp(err_env, 1);
+
+ ttype = get_gs_token(&gsf, pos1, &pos2, "encoding");
+ if (!(ttype == GS_EOF
+ || (ttype == 'd' && pos2 == pos1 + 3
+ && memcmp(ffline + pos1, "def", 3) == 0
+ && get_gs_token(&gsf, pos2, &pos2, "encoding") == GS_EOF)))
+ longjmp(err_env, 1);
+
+ if (pos1 >= ffline_len) expandline(pos1 + 1);
+ ffline[pos1] = '\0';
+ str = xmemdup(ffline + 1, pos1);
+ for (i = 0; i < 256; ++i)
+ encp->vec[i] =
+ (identindex[i] != 0 ? str + identindex[i] - 1 : NULL);
+
+ encp->valid = True;
+ }
+ else /* if error */
+ Fprintf(stderr,
+ "%s: invalid format in encoding file %s; giving up.\n", prog,
+ encp->key);
+
+ Fclose(f);
+ ++n_files_left;
+}
+
+#endif /* FREETYPE || PS */
+
+
+void
+init_font_open()
+{
+ char *size_list;
+ int *sp, *sp1;
+ unsigned int n;
+ char *p;
+#if FREETYPE || PS
+ FILE *f;
+ _Xconst char *dvipsrc;
+#endif
+
+ Sprintf(bdpi_string, "%d", pixels_per_inch);
+
+#if CFGFILE
+
+#ifndef XDVIFONTS_ONLY
+ if ((search_pkgf.path1 = getenv("XDVIFONTS")) == NULL
+ && (search_pkgf.path1 = getenv("PKFONTS")) == NULL
+ && (search_pkgf.path1 = getenv("TEXPKS")) == NULL)
+ search_pkgf.path1 = getenv("TEXFONTS");
+#else
+ search_pkgf.path1 = getenv("XDVIFONTS");
+#endif
+#ifdef DOSNAMES
+ search_pkgf_dos.path1 = search_pkgf.path1;
+#endif
+ search_pkgf.envptr = ffgetenv("PKFONTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_pkgf.envptr != NULL && search_pkgf.envptr->value == NULL)
+ search_pkgf.envptr = NULL;
+#ifdef DOSNAMES
+ search_pkgf_dos.envptr = search_pkgf.envptr;
+#endif
+
+#else /* not CFGFILE */
+
+ if ((search_pkgf.path1 = getenv("XDVIFONTS")) == NULL
+#ifndef XDVIFONTS_ONLY
+ && (search_pkgf.path1 = getenv("PKFONTS")) == NULL
+ && (search_pkgf.path1 = getenv("TEXPKS")) == NULL
+ && (search_pkgf.path1 = getenv("TEXFONTS")) == NULL
+#endif
+ ) {
+ search_pkgf.path1 = search_pkgf.path2;
+ search_pkgf.path2 = NULL;
+ }
+#ifdef DOSNAMES
+ search_pkgf_dos.path1 = search_pkgf.path1;
+ search_pkgf_dos.path2 = search_pkgf.path2;
+#endif
+
+#endif /* not CFGFILE */
+
+ /*
+ * pk/gf searching is the only kind that uses more than three
+ * characters in fF_etc, so these can be initialized once and then
+ * forgotten.
+ */
+
+ fF_values[2] = dpi_string;
+ fF_values[3] = bdpi_string;
+#ifndef USE_GF
+ fF_values[4] = "pk";
+#endif
+ fF_values[5] = resource.mfmode;
+
+#if CFGFILE
+
+#ifndef XDVIFONTS_ONLY
+ if ((search_vf.path1 = getenv("XDVIVFS")) == NULL)
+ search_vf.path1 = getenv("VFFONTS");
+#else
+ search_vf.path1 = getenv("XDVIVFS");
+#endif
+ search_vf.envptr = ffgetenv("VFFONTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_vf.envptr != NULL && search_vf.envptr->value == NULL)
+ search_vf.envptr = NULL;
+
+#else /* not CFGFILE */
+
+ if ((search_vf.path1 = getenv("XDVIVFS")) == NULL
+#ifndef XDVIFONTS_ONLY
+ && (search_vf.path1 = getenv("VFFONTS")) == NULL
+#endif
+ ) {
+ search_vf.path1 = search_vf.path2;
+ search_vf.path2 = NULL;
+ }
+
+#endif /* not CFGFILE */
+
+ size_list = getenv("XDVISIZES");
+ n = 1; /* count number of sizes */
+ if (size_list == NULL || *size_list == '\0' || *size_list == PATH_SEP)
+ for (p = default_size_list; (p = index(p, PATH_SEP)) != NULL; ++p)
+ ++n;
+ if (size_list != NULL)
+ for (p = size_list; (p = index(p, PATH_SEP)) != NULL; ++p) ++n;
+ sizes = xmalloc(n * sizeof(int));
+ sizend = sizes; /* get the actual sizes */
+ if (size_list == NULL || *size_list == '\0' || *size_list == PATH_SEP)
+ get_sizes(default_size_list, &sizend);
+ if (size_list != NULL && *size_list != '\0')
+ get_sizes(size_list, &sizend);
+
+ /* sort the sizes (insertion sort) */
+ for (sp = sizes + 1; sp < sizend; ++sp)
+ if (*sp < sp[-1]) {
+ int i = *sp;
+
+ sp1 = sp;
+ do
+ *sp1 = sp1[-1];
+ while (--sp1 > sizes && i < sp1[-1]);
+ *sp1 = i;
+ }
+
+ /* eliminate duplicates and erroneous values */
+ n = 0; /* previous value */
+ for (sp = sp1 = sizes; sp < sizend; ++sp)
+ if (*sp != n)
+ n = *sp1++ = *sp;
+ sizend = sp1;
+
+#if FREETYPE || PS
+ /*
+ * Initialize reading of Type 1 fonts and map files
+ * (PS uses T1 fonts for MetaPost figures).
+ */
+
+# if CFGFILE
+
+ if ((search_dvips_cf.path1 = getenv("XDVITYPE1CONFIG")) == NULL)
+ search_dvips_cf.path1 = getenv("TEXCONFIG");
+ search_dvips_cf.envptr = ffgetenv("TEXCONFIG");
+ /* clear it if it's a getenv() placeholder */
+ if (search_dvips_cf.envptr != NULL
+ && search_dvips_cf.envptr->value == NULL)
+ search_dvips_cf.envptr = NULL;
+
+ if ((search_fontmap.path1 = getenv("XDVIFONTMAPS")) == NULL
+ && (search_fontmap.path1 = getenv("TEXFONTMAPS")) == NULL)
+ search_fontmap.path1 = getenv("TEXFONTS");
+ search_fontmap.envptr = ffgetenv("TEXFONTMAPS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_fontmap.envptr != NULL
+ && search_fontmap.envptr->value == NULL)
+ search_fontmap.envptr = NULL;
+
+# else /* not CFGFILE */
+
+ if ((search_dvips_cf.path1 = getenv("XDVITYPE1CONFIG")) == NULL
+ && (search_dvips_cf.path1 = getenv("TEXCONFIG")) == NULL) {
+ search_dvips_cf.path1 = search_dvips_cf.path2;
+ search_dvips_cf.path2 = NULL;
+ }
+
+ if ((search_fontmap.path1 = getenv("XDVIFONTMAPS")) == NULL
+ && (search_fontmap.path1 = getenv("TEXFONTMAPS")) == NULL
+ && (search_fontmap.path1 = getenv("TEXFONTS")) == NULL) {
+ search_fontmap.path1 = search_fontmap.path2;
+ search_fontmap.path2 = NULL;
+ }
+
+# endif /* not CFGFILE */
+
+ if (ffline == NULL) expandline(80);
+
+ f = filefind("config.ps", &search_dvips_cf, NULL);
+ if (f != NULL)
+ getdefaults(f);
+
+ dvipsrc = getenv("DVIPSRC");
+ if (dvipsrc == NULL) {
+ dvipsrc = getenv("HOME");
+ if (dvipsrc != NULL) {
+ n = strlen(dvipsrc);
+ if (n + 10 > ffline_len) expandline(n + 10);
+ memcpy(ffline, dvipsrc, n);
+ memcpy(ffline + n, "/.dvipsrc", 10);
+ dvipsrc = ffline;
+ }
+ }
+ if (dvipsrc != NULL) {
+ f = xfopen(dvipsrc, OPEN_MODE);
+ if (f != NULL)
+ getdefaults(f);
+ }
+
+ f = filefind("config.xdvi", &search_dvips_cf, NULL);
+ if (f != NULL)
+ getdefaults(f);
+
+ *p_tail = NULL;
+
+ /*
+ * Look for the first (openable) map file. Others will be read later
+ * as needed.
+ */
+
+ while (p_head != NULL) {
+ mapfile = filefind(p_head->value, &search_fontmap, NULL);
+ if (mapfile != NULL) {
+ if (debug & DBG_OPEN)
+ printf("Map file: %s\n", p_head->value);
+ break;
+ }
+ Fprintf(stderr, "Cannot open map file %s\n", p_head->value);
+ p_head = p_head->next;
+ }
+#endif /* FREETYPE || PS */
+}
+
+/*
+ * Try a given size.
+ */
+
+static FILE *
+try_size(font, dpi, ret_path)
+ _Xconst char *font;
+ int dpi;
+ _Xconst char **ret_path;
+{
+#ifdef DOSNAMES
+ FILE *retval;
+#endif
+
+ Sprintf(dpi_string, "%d", dpi);
+
+#ifdef DOSNAMES
+ retval = filefind(font, &search_pkgf, ret_path);
+ if (retval != NULL) return retval;
+ return filefind(font, &search_pkgf_dos, ret_path);
+#else
+ return filefind(font, &search_pkgf, ret_path);
+#endif
+}
+
+
+#ifdef MKTEXPK
+
+#ifndef MKTEXPK_PATH
+#ifdef MAKETEXPK
+#define MKTEXPK_PATH "MakeTeXPK"
+#else
+#define MKTEXPK_PATH "mktexpk"
+#endif
+#endif
+
+#ifdef MAKETEXPK
+#define MKPK_DEFAULT_MODE "default"
+#else
+#define MKPK_DEFAULT_MODE "/"
+#endif
+
+#if HAVE_GOOD_SETSID_VFORK
+# if HAVE_VFORK_H
+# include <vfork.h>
+# endif
+#else
+ /* Mac OS X 10.3 (Panther) (11/2003) doesn't allow setsid() within vfork() */
+# undef vfork
+# define vfork fork
+#endif
+
+#ifndef EXIT_SUCCESS
+#ifndef VMS
+#define EXIT_SUCCESS 0
+#else
+#define EXIT_SUCCESS 1
+#endif
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+#ifdef EWOULDBLOCK
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+#else /* EAGAIN */
+#define AGAIN_CONDITION (errno == EWOULDBLOCK)
+#endif /* EAGAIN */
+#else /* EWOULDBLOCK */
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EAGAIN)
+#endif /* EAGAIN */
+#endif /* EWOULDBLOCK */
+
+#define NOBUILD 29999
+
+/*
+ * ffmemcpy - Copy the given number of bytes to the given position
+ */
+
+static unsigned int
+ffmemcpy(pos, src, len)
+ unsigned int pos;
+ _Xconst char *src;
+ unsigned int len;
+{
+ if (pos + len >= ffline_len)
+ expandline(pos + len);
+ memcpy(ffline + pos, src, len);
+ return pos + len;
+}
+
+/*
+ * ffstrcpy - Copy string to ffline at the given position
+ */
+
+static unsigned int
+ffstrcpy(pos, str)
+ unsigned int pos;
+ _Xconst char *str;
+{
+ return ffmemcpy(pos, str, strlen(str));
+}
+
+/*
+ * ff2memcpy - Copy the given number of bytes to the given position
+ * *within* ffline.
+ */
+
+static unsigned int
+ff2memcpy(pos, src, len)
+ unsigned int pos;
+ unsigned int src;
+ unsigned int len;
+{
+ if (pos + len >= ffline_len)
+ expandline(pos + len);
+ memcpy(ffline + pos, ffline + src, len);
+ return pos + len;
+}
+
+/*
+ * Stuff to handle child process termination
+ */
+
+static Boolean mkpk_done;
+static int mkpk_status;
+
+static void
+mkpk_term(status)
+ int status;
+{
+ mkpk_done = True;
+ mkpk_status = status;
+ ev_flags |= EV_ACK;
+}
+
+static struct xchild mkpk_child = {NULL, 0, False, mkpk_term};
+static Boolean mkpk_timer_set;
+
+static void
+mkpk_alarm(arg)
+ struct xtimer *arg;
+{
+ mkpk_timer_set = False;
+ ev_flags |= EV_ACK;
+}
+
+static struct xtimer mkpk_timer = TIMER_INIT(mkpk_alarm);
+
+/*
+ * Stuff to handle child process output
+ */
+
+static void mkpk_get_result ARGS((void));
+
+static unsigned int mkpk_pos;
+
+static struct xio mkpk_result = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ mkpk_get_result, NULL};
+
+static void
+mkpk_get_result()
+{
+ int bytes;
+
+ for (;;) {
+ bytes = read(mkpk_result.fd, ffline + mkpk_pos,
+
+ ffline_len - mkpk_pos);
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi: mkpk_result read");
+ break;
+ }
+ if (bytes == 0) break;
+
+ mkpk_pos += bytes;
+ if (mkpk_pos >= ffline_len)
+ expandline(ffline_len);
+ }
+}
+
+
+/*
+ * makefont - call system() to make the font.
+ */
+
+static FILE *
+makefont(font, dpi, name, magstepval)
+ _Xconst char *font;
+ int dpi;
+ _Xconst char **name;
+ int magstepval;
+{
+ int pipefds[2];
+ Boolean used_fontname = False;
+ Boolean used_mfmode = False;
+ int redirect_to = 1;
+ _Xconst char *p;
+ unsigned int argc;
+ unsigned int pos_end, pos1, destpos;
+ _Xconst char *actual_command;
+ char **argv;
+ unsigned int pos;
+ static Boolean did_putenv = False;
+ FILE *f;
+ char *q;
+ unsigned int i;
+
+ if (xpipe(pipefds) != 0) { /* create the pipe */
+ perror("[xdvi] pipe");
+ return NULL;
+ }
+
+ /*
+ * Generate the mktexpk command line.
+ */
+
+ if (makepkcmd == NULL) {
+ makepkcmd = getenv("XDVIMAKEPK");
+ if (makepkcmd == NULL) makepkcmd = MKTEXPK_PATH;
+ }
+ p = makepkcmd;
+ pos = 1;
+ if (pos >= ffline_len)
+ expandline(ffline_len);
+ ffline[0] = '\0';
+ argc = 0;
+
+ for (;;) {
+ if (*p == '%') {
+ char buf[32];
+
+ switch (*++p) {
+ case 'n':
+ pos = ffstrcpy(pos, font);
+ used_fontname = True;
+ break;
+ case 'd':
+ Sprintf(buf, "%d", dpi);
+ pos = ffstrcpy(pos, buf);
+ break;
+ case 'b':
+ Sprintf(buf, "%d", pixels_per_inch);
+ pos = ffstrcpy(pos, buf);
+ break;
+ case 'm':
+ if (magstepval == NOMAGSTP)
+ Sprintf(buf, "%d+%d/%d", dpi / pixels_per_inch,
+ dpi % pixels_per_inch, pixels_per_inch);
+ else if (magstepval >= 0)
+ Sprintf(buf, "magstep(%d%s)", magstepval / 2,
+ magstepval % 2 ? ".5" :"");
+ else
+ Sprintf(buf, "magstep(-%d%s)", -magstepval / 2,
+ magstepval % 2 ? ".5" :"");
+ pos = ffstrcpy(pos, buf);
+ break;
+ case 'o':
+ pos = ffstrcpy(pos, resource.mfmode != NULL
+ ? resource.mfmode : MKPK_DEFAULT_MODE);
+ used_mfmode = True;
+ break;
+ case 'r':
+ pos = ffmemcpy(pos, ">&3", 3);
+ redirect_to = 3;
+ break;
+ case '%':
+ if (pos + 1 >= ffline_len)
+ expandline(pos + 1);
+ ffline[pos++] = '%';
+ break;
+ case '\0':
+ --p;
+ break;
+ default:
+ if (pos + 2 >= ffline_len)
+ expandline(pos + 1);
+ ffline[pos++] = '%';
+ ffline[pos++] = *p;
+ break;
+ }
+ }
+ else if (*p == '\0')
+ if (used_fontname) break;
+ else {
+#ifndef MAKETEXPK
+ p = " --mfmode %o --bdpi %b --mag %m --dpi %d %n %r";
+#else
+#ifdef MKPK_REDIRECT
+ p = " %n %d %b %m %o '' %r";
+#else
+ p = " %n %d %b %m";
+#endif
+#endif
+ continue;
+ }
+ else if (*p == ' ' || *p == '\t') {
+ if (ffline[pos - 1] != '\0') {
+ ++argc;
+ ffline[pos++] = '\0';
+ }
+ }
+ else {
+ if (pos + 1 >= ffline_len)
+ expandline(pos + 1);
+ ffline[pos++] = *p;
+ }
+ ++p;
+ }
+
+ if (resource.mfmode != NULL && !used_mfmode)
+ pos = ffstrcpy(pos, resource.mfmode);
+
+ if (ffline[pos - 1] != '\0') {
+ ++argc;
+ ffline[pos++] = '\0';
+ }
+
+ /* Form command line string */
+ pos1 = 1;
+ destpos = pos;
+ if (destpos >= ffline_len)
+ expandline(ffline_len);
+ ffline[destpos++] = '-';
+ for (;;) { /* loop over args */
+ if (pos1 >= pos) break; /* if end of args */
+ ffline[destpos++] = ' '; /* Convert \0 to space */
+ pos_end = pos1 + strlen(ffline + pos1);
+ for (;;) {
+ unsigned int pos2, pos3;
+
+ p = memchr(ffline + pos1, '\'', pos_end - pos1);
+ pos2 = (p == NULL ? pos_end : p - ffline);
+ for (pos3 = pos1;; ++pos3)
+ if (pos3 >= pos2) {
+ destpos = ff2memcpy(destpos, pos1, pos2 - pos1);
+ break;
+ }
+ else if (index(" \t`\"()$&<>~*?\\", ffline[pos3]) != NULL) {
+ if (destpos >= ffline_len)
+ expandline(ffline_len);
+ ffline[destpos++] = '\'';
+ destpos = ff2memcpy(destpos, pos1, pos2 - pos1);
+ if (destpos >= ffline_len)
+ expandline(ffline_len);
+ ffline[destpos++] = '\'';
+ break;
+ }
+ pos1 = pos2 + 1;
+ if (p == NULL) break;
+ destpos = ffmemcpy(destpos, "\\'", 2);
+ }
+ }
+
+ ffline[destpos++] = '\0';
+ actual_command = xmemdup(ffline + pos, destpos - pos);
+ Puts(actual_command);
+
+ argv = xmalloc((argc + 1) * sizeof(*argv));
+ q = ffline + 1;
+ for (i = 0; i < argc; ++i) {
+ argv[i] = q;
+ q += strlen(q) + 1;
+ }
+ argv[argc] = NULL;
+
+ /*
+ * Put the metafont mode into the environment, if available.
+ */
+
+ if (!did_putenv) {
+ if (resource.mfmode != NULL)
+ xputenv("MAKETEX_MODE", resource.mfmode);
+ did_putenv = True;
+ }
+
+ /*
+ * Create a child process.
+ */
+
+ Fflush(stderr); /* avoid double buffering */
+ mkpk_child.pid = vfork();
+ if (mkpk_child.pid == 0) { /* if child */
+ (void) close(pipefds[0]);
+ if (redirect_to != pipefds[1]) {
+ (void) dup2(pipefds[1], redirect_to);
+ (void) close(pipefds[1]);
+ }
+ if (setsid() == -1) { /* so we can kill the process group */
+ perror("setsid");
+ Fflush(stderr);
+ _exit(1);
+ }
+ (void) execvp(*argv, argv);
+ Fprintf(stderr, "Execvp of %s failed.\n", *argv);
+ Fflush(stderr);
+ _exit(1);
+ }
+
+ (void) close(pipefds[1]);
+ ++n_files_left;
+ free(argv);
+
+ if (mkpk_child.pid == -1) {
+ (void) close(pipefds[0]);
+ ++n_files_left;
+ perror("[xdvi] fork");
+ free((void *) actual_command);
+ return NULL;
+ }
+
+ /*
+ * Now wait until the process terminates, reading whatever it writes
+ * to the pipe. An eof on the pipe assumes that the child terminated.
+ */
+
+ set_chld(&mkpk_child);
+
+ prep_fd(pipefds[0], True); /* set fd for non-blocking I/O */
+
+ mkpk_pos = 0;
+ mkpk_result.fd = pipefds[0];
+ set_io(&mkpk_result);
+
+ mkpk_done = False;
+ for (;;) {
+ (void) read_events(EV_GE_NEWDOC | EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (ev_flags & EV_GE_NEWDOC) { /* if we're aborting */
+ kill(-mkpk_child.pid, SIGINT);
+ set_timer(&mkpk_timer, 3000);
+ mkpk_timer_set = True;
+ for (;;) {
+ (void) read_events(EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (mkpk_done) {
+ if (mkpk_timer_set)
+ cancel_timer(&mkpk_timer);
+ break;
+ }
+ if (!mkpk_timer_set) {
+ kill(-mkpk_child.pid, SIGKILL);
+ clear_chld(&mkpk_child);
+ break;
+ }
+ }
+ if (ev_flags & EV_GE_TERM)
+ xdvi_exit(0);
+ clear_io(&mkpk_result);
+ (void) close(pipefds[0]);
+ ++n_files_left;
+ free((void *) actual_command);
+ return NULL;
+ }
+
+ if (mkpk_done)
+ break;
+ }
+
+ clear_io(&mkpk_result);
+ (void) close(pipefds[0]);
+ ++n_files_left;
+
+ if (!WIFEXITED(mkpk_status) || WEXITSTATUS(mkpk_status) != EXIT_SUCCESS)
+ {
+ WARN1(XmDIALOG_WARNING,
+ "The following command for building a font file has failed:\n%s",
+ actual_command + 2);
+ free((void *) actual_command);
+ return NULL;
+ }
+
+ if (mkpk_pos != 0 && ffline[mkpk_pos - 1] == '\n')
+ --mkpk_pos; /* trim off last \n */
+
+ /* if no response, then it probably failed, but look anyway */
+ if (mkpk_pos == 0) {
+ if (debug & DBG_OPEN)
+ Printf("No response from %s\n", actual_command + 2);
+ free((void *) actual_command);
+ return try_size(font, dpi, name);
+ }
+
+ if (mkpk_pos >= ffline_len)
+ expandline(mkpk_pos);
+ ffline[mkpk_pos++] = '\0';
+
+ if (debug & DBG_OPEN)
+ Printf("%s ---> %s\n", actual_command + 2, ffline);
+ free((void *) actual_command);
+
+ f = xfopen(ffline, OPEN_MODE);
+ if (f == NULL) {
+ perror(ffline);
+ return NULL;
+ }
+
+ if (debug & DBG_OPEN)
+ puts("--Success--\n");
+ *name = xmemdup(ffline, mkpk_pos);
+ return f;
+}
+
+#endif /* MKTEXPK */
+
+/*
+ * Try a given font name
+ */
+
+#if MKTEXPK
+# define PRE_FONT_OPEN(fontp, fontname, fdpi, magstepval, name_ret, dpi_ret) \
+ pre_font_open(fontp, fontname, fdpi, magstepval, name_ret, dpi_ret)
+#else
+# define PRE_FONT_OPEN(fontp, fontname, fdpi, magstepval, name_ret, dpi_ret) \
+ pre_font_open(fontp, fontname, fdpi, name_ret, dpi_ret)
+#endif
+
+static Boolean
+PRE_FONT_OPEN(fontp, fontname, fdpi, magstepval, name_ret, dpi_ret)
+ struct font *fontp;
+ _Xconst char *fontname;
+ double fdpi;
+#if MKTEXPK
+ int magstepval;
+#endif
+ _Xconst char **name_ret;
+ int *dpi_ret;
+{
+ FILE *f;
+ int *p1, *p2;
+ int dpi;
+ int tempdpi;
+
+ *dpi_ret = dpi = fdpi + 0.5;
+
+#if FREETYPE
+ /*
+ * First look for a scalable font.
+ */
+
+ if (resource.freetype) {
+ struct avl_t1 *t1p = lookup_t1_font(fontp);
+ _Xconst char *path;
+
+ if (t1p != NULL) { /* if font found */
+ if (debug & DBG_OPEN)
+ Printf("lookup_t1_font(%s) --> found %s\n", fontp->fontname,
+ t1p->fontfile != NULL ? t1p->fontfile : t1p->psname);
+
+ return True;
+ }
+
+ if (debug & DBG_OPEN)
+ Printf("lookup_t1_font(%s) --> not found\n", fontp->fontname);
+ }
+#endif
+
+ /*
+ * Loop over sizes. Try actual size first, then closest sizes.
+ * If the pathname is absolutely or explicitly relative, don't
+ * use the usual paths to search for it; just look for it in the
+ * directory specified.
+ */
+
+ f = try_size(fontname, dpi, name_ret);
+ if (f != NULL) {
+ fontp->file = f;
+ return True;
+ }
+
+ /* Try at one away from the size we just tried, to account
+ for rounding error. */
+ tempdpi = dpi + (dpi < fdpi ? 1 : -1);
+ f = try_size(fontname, tempdpi, name_ret);
+ if (f != NULL) {
+ fontp->file = f;
+ *dpi_ret = tempdpi;
+ return True;
+ }
+
+ /* Try a virtual font. */
+ f = filefind(fontname, &search_vf, name_ret);
+ if (f != NULL) {
+ fontp->file = f;
+ return True;
+ }
+
+#ifdef MKTEXPK
+ /* Try to create the font. */
+ if (magstepval != NOBUILD && resource.makepk) {
+ f = makefont(fontname, dpi, name_ret, magstepval);
+ if (f != NULL || ev_flags & EV_GE_NEWDOC) {
+ fontp->file = f;
+ return True;
+ }
+ }
+#endif
+
+ /* Now try at all the sizes. */
+ for (p2 = sizes; p2 < sizend; ++p2) if (*p2 >= dpi) break;
+ p1 = p2;
+ for (;;) {
+ /* find another resolution */
+ if (p1 <= sizes)
+ if (p2 >= sizend) return False;
+ else tempdpi = *p2++;
+ else if (p2 >= sizend || (long) dpi * dpi <= (long) p1[-1] * *p2)
+ tempdpi = *--p1;
+ else tempdpi = *p2++;
+ f = try_size(fontname, *dpi_ret = tempdpi, name_ret);
+ if (f != NULL) {
+ fontp->file = f;
+ return True;
+ }
+ }
+}
+
+/*
+ * font_open()
+ *
+ * This is the publicly accessible routine. It uses the following fields
+ * in the font structure:
+ * fontname
+ * magstepval
+ * fsize
+ * filename
+ * ft
+ * next_size
+ * size
+ */
+
+/* ARGSUSED */
+Boolean
+font_open(fontp, font_ret, dpi_ret)
+ struct font *fontp;
+ char **font_ret;
+ int *dpi_ret;
+{
+ Boolean val;
+ int actual_pt, low_pt, high_pt, trial_pt;
+ char *fn, *fnend;
+
+ val = PRE_FONT_OPEN(fontp, fontp->fontname, fontp->fsize,
+ fontp->magstepval, &fontp->filename, dpi_ret);
+ if (val || ev_flags & EV_GE_NEWDOC) {
+ *font_ret = NULL;
+ return val;
+ }
+
+ fn = xmalloc(strlen(fontp->fontname) + 2);
+ Strcpy(fn, fontp->fontname);
+ fnend = fn + strlen(fn);
+ while (fnend > fn && fnend[-1] >= '0' && fnend[-1] <= '9') --fnend;
+ actual_pt = low_pt = high_pt = atoi(fnend);
+ if (actual_pt) {
+ low_pt = actual_pt - 1;
+ high_pt = actual_pt + 1;
+ for (;;) {
+ if (2 * low_pt >= actual_pt &&
+ (low_pt * high_pt > actual_pt * actual_pt ||
+ high_pt > actual_pt + 5))
+ trial_pt = low_pt--;
+ else if (high_pt > actual_pt + 5) break;
+ else trial_pt = high_pt++;
+ Sprintf(fnend, "%d", trial_pt);
+ if (PRE_FONT_OPEN(fontp, fn,
+ fontp->fsize * actual_pt / trial_pt,
+ NOBUILD, &fontp->filename, dpi_ret)) {
+ *font_ret = fn;
+ return True;
+ }
+ }
+ }
+ free(fn);
+
+ if (alt_font != NULL) {
+ if (PRE_FONT_OPEN(fontp, alt_font, fontp->fsize, fontp->magstepval,
+ &fontp->filename, dpi_ret)) {
+ *font_ret = xstrdup(alt_font);
+ return True;
+ }
+ }
+ return False;
+}
diff --git a/ft.c b/ft.c
@@ -0,0 +1,474 @@
+/*========================================================================*\
+
+Copyright (c) 2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * FreeType (PostScript Type 1 and TrueType) font reading routines.
+ * Public routines are load_ft_font and read_ft_char.
+ */
+
+#include "xdvi.h"
+
+#include <math.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_SIZES_H
+
+static FT_Library library = NULL;
+
+static struct avl_enc *enc_head = NULL;
+
+/* From xc/lib/X11/PutImage.c */
+
+#if !WORDS_BIGENDIAN
+static _Xconst unsigned char reverse_byte[0x100] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+#endif /* !WORDS_BIGENDIAN */
+
+
+/*
+ * FreeType I/O stream functions
+ */
+
+static unsigned long
+xdvi_stream_read(stream, offset, buffer, count)
+ FT_Stream stream;
+ unsigned long offset;
+ unsigned char *buffer;
+ unsigned long count;
+{
+ struct font *fontp;
+
+ fontp = ((struct ftfont *) stream->descriptor.pointer)->first_size;
+ open_font_file(fontp);
+ fseek(fontp->file, offset, SEEK_SET);
+ return (unsigned long) fread(buffer, 1, count, fontp->file);
+}
+
+static void
+xdvi_stream_close(stream)
+ FT_Stream stream;
+{
+ /* do nothing */
+}
+
+
+/*
+ * Public routines
+ */
+
+static void
+#if NeedFunctionPrototypes
+read_ft_char(struct font *fontp, wide_ubyte ch)
+#else /* !NeedFunctionPrototypes */
+read_ft_char(fontp, ch)
+ struct font *fontp;
+ ubyte ch;
+#endif /* NeedFunctionPrototypes */
+{
+ struct glyph *g;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ int bytes_wide;
+ int err;
+
+ if (debug & DBG_PK)
+ Printf("Loading FreeType char %d", ch);
+
+ /*
+ * Load it unscaled first, so that we can get a more accurate
+ * (non-hinted) value of the horizontal advance.
+ */
+
+ g = &fontp->glyph[ch];
+ face = fontp->ft->face;
+ FT_Activate_Size(fontp->size);
+ err = FT_Load_Glyph(face, g->addr, FT_LOAD_NO_SCALE);
+ if (err != 0)
+ oops("FT_Load_Glyph: error = %d", err);
+
+ g->dvi_adv = face->glyph->metrics.horiAdvance * fontp->ft->expn
+ * fontp->spsize / face->units_per_EM + 0.5;
+
+ /* Now do the real loading. */
+
+ err = FT_Load_Glyph(face, g->addr, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
+ if (err != 0)
+ oops("FT_Load_Glyph: error = %d", err);
+
+ slot = face->glyph;
+ g->bitmap.w = slot->bitmap.width;
+ g->bitmap.h = slot->bitmap.rows;
+
+ if (debug & DBG_PK)
+ Printf(", size=%dx%d, dvi_adv=%ld\n", g->bitmap.w, g->bitmap.h,
+ g->dvi_adv);
+
+ alloc_bitmap(&g->bitmap);
+ bytes_wide = ROUNDUP((int) g->bitmap.w, BMBITS) * BMBYTES;
+
+ if (slot->bitmap.width > 0) {
+ int i;
+ unsigned char *p;
+ BMUNIT *q;
+
+ p = slot->bitmap.buffer;
+ q = (BMUNIT *) g->bitmap.bits;
+ for (i = g->bitmap.h; i > 0; --i) {
+#if WORDS_BIGENDIAN
+ memcpy(q, p, (slot->bitmap.width + 7) / 8);
+#else
+ unsigned char *p1 = p;
+ BMUNIT *q1 = q;
+ BMUNIT data = 0;
+ int shift = 0;
+ int j;
+
+ for (j = (slot->bitmap.width + 7) / 8; j > 0; --j) {
+ if (shift >= BMBITS) {
+ *q1++ = data;
+ data = 0;
+ shift = 0;
+ }
+ data |= reverse_byte[*p1++] << shift;
+ shift += 8;
+ }
+ *q1 = data;
+#endif
+ p += slot->bitmap.pitch;
+ *((char **) &q) += bytes_wide;
+ }
+ }
+
+ /* The offset of (-1,-1) is from comparing bitmaps of 'R' and 'a'
+ between cmr10.pfb and cmr10.300pk. */
+ g->x = -1 - slot->bitmap_left;
+ g->y = slot->bitmap_top - 1;
+}
+
+/*
+ * Do the ScaleFont, etc. directives.
+ */
+
+static Boolean
+set_transform(ftp, str)
+ struct ftfont *ftp;
+ _Xconst char *str;
+{
+ double x = 1.0;
+ double y = 0.0;
+
+ for (;;) {
+ while (isspace(*str)) ++str;
+ if (*str == '\0')
+ break;
+
+ if (isdigit(*str) || *str == '.' || *str == '-') {
+ double arg = strtod(str, (char **) &str);
+
+ while (isspace(*str)) ++str;
+
+ if (memcmp(str, "ObliqueSlant", 12) == 0
+ && (isspace(str[12]) || str[12] == '\0')) {
+ arg = -tan(arg);
+ str += 12;
+ while (isspace(*str)) ++str;
+ }
+
+ if (memcmp(str, "SlantFont", 9) == 0
+ && (isspace(str[9]) || str[9] == '\0')) {
+ y += arg;
+ str += 9;
+ }
+ else if (memcmp(str, "ExtendFont", 10) == 0
+ && (isspace(str[10]) || str[10] == '\0')) {
+ x *= arg;
+ str += 10;
+ }
+ else return False;
+ }
+ else { /* other characters; presume encoding name */
+ while (!isspace(*str) && *str != '\0') ++str;
+ while (isspace(*str)) ++str;
+ if (memcmp(str, "ReEncodeFont", 12) == 0
+ && (isspace(str[12]) || str[12] == '\0'))
+ str += 12;
+ else
+ return False;
+ }
+ }
+
+ if (x != 1.0 || y != 0.0) {
+ FT_Matrix mat;
+
+ mat.xx = (FT_Fixed) (x * 0x10000 + 0.5);
+ mat.xy = (FT_Fixed) (y * 0x10000 + 0.5);
+ mat.yx = 0;
+ mat.yy = 0x10000;
+
+ FT_Set_Transform(ftp->face, &mat, NULL);
+ ftp->expn = x;
+ }
+
+ return True;
+}
+
+
+/*
+ * When a document uses many freetype fonts, it can take a while to read
+ * them all (due mostly to disk access issues). So, we delay loading
+ * freetype fonts until they're needed.
+ *
+ * Therefore, this routine is not called until it is time to render a
+ * character from the font (see set_ft_char() in dvi-draw.c).
+ *
+ * It loads and sets up the font.
+ */
+
+Boolean
+load_ft_font(fontp)
+ struct font *fontp;
+{
+ struct ftfont *ftp;
+ struct avl_t1 *t1p;
+ struct font *fontp2;
+ FT_Face face;
+ FT_Size size;
+ int err;
+ _Xconst char *path;
+ FILE *f;
+
+ ftp = fontp->ft;
+ t1p = ftp->t1;
+ fontp2 = ftp->first_size;
+
+ if (!resource.freetype) {
+ if (debug & DBG_OPEN)
+ Puts("load_ft_font returning: freetype has been turned off");
+ return False;
+ }
+
+ if (t1p->bad) {
+ if (debug & DBG_OPEN)
+ Printf("Font %s was flagged as bad; skipping (size %d)\n",
+ fontp->fontname, (int) (fontp->fsize + 0.5));
+ return False;
+ }
+
+ face = ftp->face;
+ if (face != NULL) { /* if this face is already in use */
+ err = FT_New_Size(face, &size);
+ if (err != 0) {
+ Fprintf(stderr, "Could not load FreeType font %s at %d: FreeType FT_New_Size error = %d.\nWill try pixel version instead.\nPlease see the FreeType documentation for details about this.\n",
+ fontp->fontname, (int) (fontp->fsize + 0.5), err);
+ return False;
+ }
+ }
+ else {
+ FT_Open_Args args;
+
+ f = open_t1_font(t1p, &path);
+ if (f == NULL)
+ return False;
+
+ if (library == NULL) {
+ err = FT_Init_FreeType(&library);
+ if (err != 0) {
+ Fprintf(stderr, "Could not initialize FreeType library: FreeType FT_Init_FreeType error = %d.\nTurning off use of FreeType.\nPlease see the FreeType documentation for details about this.\n",
+ err);
+ resource.freetype = False;
+ free((char *) path);
+ Fclose(f);
+ ++n_files_left;
+ return False;
+ }
+ }
+
+ fontp2->filename = path;
+ fontp2->file = f;
+
+ fseek(f, 0L, SEEK_END);
+ ftp->stream.size = ftell(f);
+ fseek(f, 0L, SEEK_SET); /* this might not be necessary */
+
+ ftp->stream.descriptor.pointer = ftp;
+ ftp->stream.read = xdvi_stream_read;
+ ftp->stream.close = xdvi_stream_close;
+
+ args.flags = FT_OPEN_STREAM;
+ args.stream = &ftp->stream;
+ err = FT_Open_Face(library, &args, 0, &face);
+ if (err != 0) {
+ Fprintf(stderr, "Could not load FreeType font %s: FreeType FT_Open_Face error = %d.\nWill try pixel version instead.\nPlease see the FreeType documentation for details about this.\n",
+ fontp->fontname, err);
+ free((char *) path);
+ Fclose(f);
+ ++n_files_left;
+ fontp2->file = NULL;
+ fontp2->filename = NULL;
+ return False;
+ }
+ ftp->face = face;
+
+ if (!FT_IS_SCALABLE(face)) {
+ Fprintf(stderr, "%s: Font %s is not scalable.\n", prog,
+ fontp->fontname);
+ FT_Done_Face(face);
+ free((char *) path);
+ Fclose(f);
+ ++n_files_left;
+ fontp2->file = NULL;
+ fontp2->filename = NULL;
+ return False;
+ }
+
+ ftp->expn = 1.0;
+ if (t1p->addinfo != NULL)
+ if (!set_transform(ftp, t1p->addinfo)) {
+ FT_Done_Face(face);
+ free((char *) path);
+ Fclose(f);
+ ++n_files_left;
+ fontp2->file = NULL;
+ fontp2->filename = NULL;
+ return False;
+ }
+
+ if (face->charmap == NULL) {
+ if (face->num_charmaps > 0) {
+ if ((debug & DBG_PK) && face->num_charmaps > 1)
+ printf("Choosing the first of %d charmaps.\n",
+ face->num_charmaps);
+ }
+ FT_Set_Charmap(face, face->charmaps[0]);
+ }
+ else if (face->charmap->encoding == ft_encoding_unicode
+ && FT_Select_Charmap(face, ft_encoding_adobe_custom) != 0
+ && FT_Select_Charmap(face, ft_encoding_adobe_standard) != 0
+ && FT_Select_Charmap(face, ft_encoding_adobe_expert) != 0) {
+ if (debug & DBG_PK)
+ puts("Using unicode charmap for font.");
+ Fputs("Using unicode charmap\n", stderr); /* ||| */
+ }
+
+ ftp->enc = NULL;
+ if (t1p->encname != NULL) { /* if there's an encoding */
+ struct avl_enc *encp;
+
+ encp = (struct avl_enc *) avladd(t1p->encname,
+ strlen(t1p->encname),
+ (struct avl **) &enc_head, sizeof *encp);
+ if (encp->key == t1p->encname) /* if new record */
+ read_encoding(encp);
+ if (encp->valid)
+ ftp->enc = encp;
+ }
+
+ size = face->size;
+ }
+
+ /* Get character indices (store them in addr) */
+
+ if (debug & DBG_PK)
+ Printf("Character indices for %s:\n", fontp->fontname);
+
+ FT_Activate_Size(size);
+
+ err = FT_Set_Char_Size(face,
+ (int) (fontp->spsize * (72<<6) / (pixels_per_inch << 16) + 0.5), 0,
+ pixels_per_inch, pixels_per_inch);
+ if (err != 0)
+ oops("FT_Set_Char_Size: error = %d\n", err);
+
+ /* Look for already-computed character indices */
+ for (fontp2 = ftp->first_size;; fontp2 = fontp2->next_size) {
+ int i;
+
+ if (fontp2 == NULL) { /* if not found */
+ struct avl_enc *encp = ftp->enc;
+
+ for (i = 0; i < 256; ++i) {
+ int ci;
+
+ if (encp == NULL)
+ ci = FT_Get_Char_Index(face, i);
+ else {
+ _Xconst char *glyphname = encp->vec[i];
+
+ if (glyphname == NULL)
+ ci = 0;
+ else
+ ci = FT_Get_Name_Index(face,
+ (FT_String *) glyphname);
+ }
+
+ fontp->glyph[i].addr = ci;
+ if (debug & DBG_PK)
+ printf("%3d->%3d%s", i, ci, (i + 1) % 8 ? " " : "\n");
+ }
+ break;
+ }
+ if (fontp2->size != NULL) { /* found the information */
+ for (i = 0; i < 256; ++i)
+ fontp->glyph[i].addr = fontp2->glyph[i].addr;
+ break;
+ }
+ }
+
+ fontp->size = size; /* it needed to be NULL in the above loop */
+ fontp->read_char = read_ft_char;
+
+ return True;
+}
diff --git a/gf.c b/gf.c
@@ -0,0 +1,328 @@
+/*========================================================================*\
+
+Copyright (c) 1990-1999 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * GF font reading routines.
+ * Public routines are read_GF_index and read_GF_char.
+ */
+
+#include "xdvi.h"
+
+#define PAINT_0 0
+#define PAINT1 64
+#define PAINT2 65
+#define PAINT3 66
+#define BOC 67
+#define BOC1 68
+#define EOC 69
+#define SKIP0 70
+#define SKIP1 71
+#define SKIP2 72
+#define SKIP3 73
+#define NEW_ROW_0 74
+#define NEW_ROW_MAX 238
+#define XXX1 239
+#define XXX2 240
+#define XXX3 241
+#define XXX4 242
+#define YYY 243
+#define NO_OP 244
+#define CHAR_LOC 245
+#define CHAR_LOC0 246
+#define PRE 247
+#define POST 248
+#define POST_POST 249
+
+#define GF_ID_BYTE 131
+#define TRAILER 223 /* Trailing bytes at end of file */
+
+static FILE *GF_file;
+
+static void
+expect(ch)
+ ubyte ch;
+{
+ ubyte ch1 = one(GF_file);
+
+ if (ch1 != ch)
+ oops("Bad GF file: %d expected, %d received.", ch, ch1);
+}
+
+static void
+too_many_bits(ch)
+ ubyte ch;
+{
+ oops("Too many bits found when loading character %d", ch);
+}
+
+/*
+ * Public routines
+ */
+
+
+static void
+#if NeedFunctionPrototypes
+read_GF_char(struct font *fontp, wide_ubyte ch)
+#else /* !NeedFunctionPrototypes */
+read_GF_char(fontp, ch)
+ struct font *fontp;
+ ubyte ch;
+#endif /* NeedFunctionPrototypes */
+{
+ struct glyph *g;
+ ubyte cmnd;
+ int min_m, max_m, min_n, max_n;
+ BMUNIT *cp, *basep, *maxp;
+ int bytes_wide;
+ Boolean paint_switch;
+#define White False
+#define Black True
+ Boolean new_row;
+ int count;
+ int word_weight;
+
+ g = &fontp->glyph[ch];
+ GF_file = fontp->file;
+
+ if(debug & DBG_PK)
+ Printf("Loading gf char %d", ch);
+
+ for (;;) {
+ switch (cmnd = one(GF_file)) {
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ Fseek(GF_file, (long) num(GF_file,
+ WIDENINT cmnd - XXX1 + 1), 1);
+ continue;
+ case YYY:
+ (void) four(GF_file);
+ continue;
+ case BOC:
+ (void) four(GF_file); /* skip character code */
+ (void) four(GF_file); /* skip pointer to prev char */
+ min_m = sfour(GF_file);
+ max_m = sfour(GF_file);
+ g->x = -min_m;
+ min_n = sfour(GF_file);
+ g->y = max_n = sfour(GF_file);
+ g->bitmap.w = max_m - min_m + 1;
+ g->bitmap.h = max_n - min_n + 1;
+ break;
+ case BOC1:
+ (void) one(GF_file); /* skip character code */
+ g->bitmap.w = one(GF_file); /* max_m - min_m */
+ g->x = g->bitmap.w - one(GF_file); /* ditto - max_m */
+ ++g->bitmap.w;
+ g->bitmap.h = one(GF_file) + 1;
+ g->y = one(GF_file);
+ break;
+ default:
+ oops("Bad BOC code: %d", cmnd);
+ }
+ break;
+ }
+ paint_switch = White;
+
+ if (debug & DBG_PK)
+ Printf(", size=%dx%d, dvi_adv=%d\n", g->bitmap.w, g->bitmap.h,
+ g->dvi_adv);
+
+ alloc_bitmap(&g->bitmap);
+ cp = basep = (BMUNIT *) g->bitmap.bits;
+/*
+ * Read character data into *basep
+ */
+ bytes_wide = ROUNDUP((int) g->bitmap.w, BMBITS) * BMBYTES;
+ maxp = ADD(basep, g->bitmap.h * bytes_wide);
+ bzero(g->bitmap.bits, g->bitmap.h * bytes_wide);
+ new_row = False;
+ word_weight = BMBITS;
+ for (;;) {
+ count = -1;
+ cmnd = one(GF_file);
+ if (cmnd < 64) count = cmnd;
+ else if (cmnd >= NEW_ROW_0 && cmnd <= NEW_ROW_MAX) {
+ count = cmnd - NEW_ROW_0;
+ paint_switch = White; /* it'll be complemented later */
+ new_row = True;
+ }
+ else switch (cmnd) {
+ case PAINT1:
+ case PAINT2:
+ case PAINT3:
+ count = num(GF_file, WIDENINT cmnd - PAINT1 + 1);
+ break;
+ case EOC:
+ if (cp >= ADD(basep, bytes_wide)) too_many_bits(ch);
+ return;
+ case SKIP1:
+ case SKIP2:
+ case SKIP3:
+ *((char **) &basep) +=
+ num(GF_file, WIDENINT cmnd - SKIP0) * bytes_wide;
+ case SKIP0:
+ new_row = True;
+ paint_switch = White;
+ break;
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ Fseek(GF_file, (long) num(GF_file,
+ WIDENINT cmnd - XXX1 + 1), 1);
+ break;
+ case YYY:
+ (void) four(GF_file);
+ break;
+ case NO_OP:
+ break;
+ default:
+ oops("Bad command in GF file: %d", cmnd);
+ } /* end switch */
+ if (new_row) {
+ *((char **) &basep) += bytes_wide;
+ if (basep >= maxp || cp >= basep) too_many_bits(ch);
+ cp = basep;
+ word_weight = BMBITS;
+ new_row = False;
+ }
+ if (count >= 0) {
+ while (count)
+ if (count <= word_weight) {
+#ifndef WORDS_BIGENDIAN
+ if (paint_switch)
+ *cp |= bit_masks[count] << (BMBITS - word_weight);
+#endif
+ word_weight -= count;
+#ifdef WORDS_BIGENDIAN
+ if (paint_switch)
+ *cp |= bit_masks[count] << word_weight;
+#endif
+ break;
+ }
+ else {
+ if (paint_switch)
+#ifndef WORDS_BIGENDIAN
+ *cp |= bit_masks[word_weight] <<
+ (BMBITS - word_weight);
+#else
+ *cp |= bit_masks[word_weight];
+#endif
+ cp++;
+ count -= word_weight;
+ word_weight = BMBITS;
+ }
+ paint_switch = 1 - paint_switch;
+ }
+ } /* end for */
+}
+
+
+void
+read_GF_index(fontp, hushcs)
+ struct font *fontp;
+ wide_bool hushcs;
+{
+ int hppp, vppp;
+ ubyte ch, cmnd;
+ struct glyph *g;
+ long checksum;
+
+ fontp->read_char = read_GF_char;
+ GF_file = fontp->file;
+ if (debug & DBG_PK)
+ Printf("Reading GF pixel file %s\n", fontp->filename);
+/*
+ * Find postamble.
+ */
+ Fseek(GF_file, (long) -4, 2);
+ while (four(GF_file) != ((unsigned long) TRAILER << 24 | TRAILER << 16
+ | TRAILER << 8 | TRAILER))
+ Fseek(GF_file, (long) -5, 1);
+ Fseek(GF_file, (long) -5, 1);
+ for (;;) {
+ ch = one(GF_file);
+ if (ch != TRAILER) break;
+ Fseek(GF_file, (long) -2, 1);
+ }
+ if (ch != GF_ID_BYTE) oops("Bad end of font file %s", fontp->fontname);
+ Fseek(GF_file, (long) -6, 1);
+ expect(POST_POST);
+ Fseek(GF_file, sfour(GF_file), 0); /* move to postamble */
+/*
+ * Read postamble.
+ */
+ expect(POST);
+ (void) four(GF_file); /* pointer to last eoc + 1 */
+ (void) four(GF_file); /* skip design size */
+ checksum = four(GF_file);
+ if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
+ && !hushcs)
+ Fprintf(stderr,
+ "Checksum mismatch (dvi = %lu, gf = %lu) in font file %s\n",
+ fontp->checksum, checksum, fontp->filename);
+ hppp = sfour(GF_file);
+ vppp = sfour(GF_file);
+ if (hppp != vppp && (debug & DBG_PK))
+ Printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp);
+ (void) four(GF_file); /* skip min_m */
+ (void) four(GF_file); /* skip max_m */
+ (void) four(GF_file); /* skip min_n */
+ (void) four(GF_file); /* skip max_n */
+/*
+ * Prepare glyph array.
+ */
+ fontp->glyph = xmalloc(256 * sizeof(struct glyph));
+ bzero((char *) fontp->glyph, 256 * sizeof(struct glyph));
+/*
+ * Read glyph directory.
+ */
+ while ((cmnd = one(GF_file)) != POST_POST) {
+ int addr;
+
+ ch = one(GF_file); /* character code */
+ g = &fontp->glyph[ch];
+ switch (cmnd) {
+ case CHAR_LOC:
+ /* g->pxl_adv = sfour(GF_file); */
+ (void) four(GF_file);
+ (void) four(GF_file); /* skip dy */
+ break;
+ case CHAR_LOC0:
+ /* g->pxl_adv = one(GF_file) << 16; */
+ (void) one(GF_file);
+ break;
+ default:
+ oops("Non-char_loc command found in GF preamble: %d",
+ cmnd);
+ }
+ g->dvi_adv = fontp->dimconv * sfour(GF_file);
+ addr = four(GF_file);
+ if (addr != -1) g->addr = addr;
+ if (debug & DBG_PK)
+ Printf("Read GF glyph for character %d; dy = %d, addr = %d\n",
+ ch, g->dvi_adv, addr);
+ }
+}
diff --git a/install-sh b/install-sh
@@ -0,0 +1,250 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/mksedscript b/mksedscript
@@ -0,0 +1,236 @@
+#! /bin/sh
+
+# Values from config.h
+
+mk_XAW=
+mk_MOTIF=
+mk_COLOR=
+mk_GREY=
+mk_BUTTONS=
+mk_MKTEXPK=
+mk_MAKETEXPK=
+mk_MKTEXPK_PATH=
+mk_PS_GS=
+mk_GS_PATH='gs'
+mk_PS_DPS=
+mk_PS_NEWS=
+mk_DEFAULT_CONFIG_PATH=
+mk_SELFAUTO=
+mk_EXTRA_APP_DEFAULTS=
+mk_DOSNAMES=
+mk_A4=
+mk_FREETYPE=
+mk_DEFAULT_TEXMF_PATH=
+mk_DEFAULT_FONT_PATH=
+mk_DEFAULT_VF_PATH=
+mk_DEFAULT_FIG_PATH=
+mk_DEFAULT_HEADER_PATH=
+mk_DEFAULT_DVIPS_CF_PATH=
+mk_DEFAULT_FONTMAP_PATH=
+mk_DEFAULT_ENC_PATH=
+mk_DEFAULT_TYPE1_PATH=
+mk_DEFAULT_GS_LIB_PATH=
+
+# Optional values from CFLAGS
+
+mk_MFMODE='unspecified'
+mk_BDPI=300
+mk_DEFAULT_FONT_SIZES='m0:m0.5:m1:m2:m3:m4:m5'
+mk_SHRINK=3
+mk_XDVIFONTS_ONLY=
+mk_MKPK_REDIRECT=
+
+# Get arguments from CFLAGS
+
+for mk_arg
+do
+ case "$mk_arg" in
+ -D*=*)
+ eval "`echo \"$mk_arg\" | sed 's/^-D/mk_/'`"
+ ;;
+ -D*)
+ eval "`echo \"$mk_arg\" | sed 's/^-D/mk_/'`=1"
+ ;;
+ esac
+done
+
+# Get arguments from config.h
+
+eval "`grep '^[ ]*#[ ]*define[ ]' config.h \
+ | sed 's/^[ ]*#[ ]*define[ ][ ]*/mk_/' \
+ | sed 's/[ ][ ]*/=/'`"
+
+# Process simple boolean arguments.
+
+if test -n "$mk_XAW" -o -n "$mk_MOTIF"; then echo 's/^#tool//';
+ else mk_EXTRA_APP_DEFAULTS=; mk_BUTTONS=
+ echo '/^#iftool/,/^#/d'; fi
+if test -z "$mk_COLOR"; then echo '/^#ifcolor/,/^#/d'; fi
+if test -z "$mk_GREY"; then echo '/^#ifgrey/,/^#/d'; fi
+if test -z "$mk_BUTTONS"; then echo '/^#ifbuttons/,/^#/d'; fi
+if test -z "$mk_PS_DPS"; then echo '/^#ifdps/,/^#/d'; fi
+if test -z "$mk_PS_NEWS"; then echo '/^#ifnews/,/^#/d'; fi
+if test -z "$mk_DOSNAMES"; then echo '/^#ifdosnames/,/^#/d'; fi
+if test -n "$mk_XDVIFONTS_ONLY";then echo '/^#iftexfonts/,/^#/d'; fi
+if test -z "$mk_FREETYPE"; then echo '/^#ifft/,/^#/d'; fi
+
+# Process arguments having to do with mktexpk/MakeTeXPK
+
+if test -n "$mk_MKTEXPK" || test -n "$mk_MAKETEXPK"; then
+ if test -z "$mk_MKTEXPK_PATH"; then
+ if test -n "$mk_MAKETEXPK"; then
+ mk_MKTEXPK_PATH=MakeTeXPK
+ else
+ mk_MKTEXPK_PATH=mktexpk
+ fi
+ fi
+ echo "s^@MKTEXPK_PATH@^$mk_MKTEXPK_PATH^"
+ if test -n "$mk_MAKETEXPK"; then
+ echo "s/@MKTEXPK_DEFAULT_MODE@/default/"
+ if test -n "$mk_MKPK_REDIRECT"; then
+ echo "s/@MKTEXPK_TAIL@/%n %d %b %m %o '' %r/"
+ else
+ echo "s/@MKTEXPK_TAIL@/%n %d %b %m %o/"
+ fi
+ else
+ echo "s^@MKTEXPK_DEFAULT_MODE@^/^"
+ echo "s/@MKTEXPK_TAIL@/--mfmode %o --bdpi %b --mag %m --dpi %d %n %r/"
+ fi
+else
+ echo '/^#ifmakepk/,/^#/d'
+fi
+
+# Process remaining PostScript emulation arguments
+
+if test -z "$mk_PS_GS"; then
+ echo '/^#ifghost/,/^#/d'
+else
+ echo "s^@GS_PATH@^$mk_GS_PATH^"
+fi
+
+if test -n "$mk_PS_GS" || test -n "$mk_PS_DPS" || test -n "$mk_PS_NEWS"; then
+ mk_PS=y
+ echo '/^#ifnops/,/^#/d'
+else
+ mk_PS=
+ echo '/^#ifps/,/^#/d'
+fi
+
+# Process arguments describing a config file
+
+if test -n "$mk_EXTRA_APP_DEFAULTS"; then
+ mk_SELFAUTO=y
+else
+ echo '/^#ifextraappdef/,/^#/d'
+fi
+
+if test -n "$mk_SELFAUTO"; then
+ if test -z "$mk_DEFAULT_CONFIG_PATH"; then
+ mk_DEFAULT_CONFIG_PATH='$SELFAUTODIR:$SELFAUTOPARENT'
+ fi
+else
+ echo '/^#ifselfauto/,/^#/d'
+fi
+
+# Miscellaneous args
+
+if test -n "$mk_A4"; then
+ echo 's/@DEFAULT_PAGE_SIZE@/21 x 29.7 cm (A4 size)/'
+ echo 's/@DEFAULT_UNIT@/cm " (centimeters)"/'
+else
+ echo 's/@DEFAULT_PAGE_SIZE@/8.5 x 11 inches/'
+ echo 's/@DEFAULT_UNIT@/in " (inches)"/'
+fi
+
+echo "s^@MFMODE@^$mk_MFMODE^"
+echo "s/@BDPI@/$mk_BDPI/"
+echo "s/@SHRINK@/$mk_SHRINK/"
+
+# Process paths.
+
+if test -z "$mk_DEFAULT_CONFIG_PATH"; then
+ echo '/^#ifconfig/,/^#/d'
+else
+ echo "s^@DEFAULT_CONFIG_PATH@ ^.TP 40\\
+.B $mk_DEFAULT_CONFIG_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+fi
+
+if test -z "$mk_DEFAULT_TEXMF_PATH"; then
+ echo '/@DEFAULT_TEXMF_PATH@/d'
+else
+ echo "s^@DEFAULT_TEXMF_PATH@ ^.TP 40\\
+.B $mk_DEFAULT_TEXMF_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+fi
+
+echo "s^@DEFAULT_FONT_PATH@ ^.B $mk_DEFAULT_FONT_PATH\\
+^" | sed -e "s@:@\\\\\\
+.TP\\\\\\
+.B @g"
+
+if test -z "$mk_DEFAULT_VF_PATH"; then
+ echo '/@DEFAULT_VF_PATH@/d'
+else
+ echo "s^@DEFAULT_VF_PATH@ ^.TP\\
+.B $mk_DEFAULT_VF_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+fi
+
+echo "s^@DEFAULT_FIG_PATH@ ^.B $mk_DEFAULT_FIG_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s^@DEFAULT_HEADER_PATH@ ^.B $mk_DEFAULT_HEADER_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s^@DEFAULT_DVIPS_CF_PATH@ ^.B $mk_DEFAULT_DVIPS_CF_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s^@DEFAULT_FONTMAP_PATH@ ^.B $mk_DEFAULT_FONTMAP_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s^@DEFAULT_ENC_PATH@ ^.B $mk_DEFAULT_ENC_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s^@DEFAULT_TYPE1_PATH@ ^.B $mk_DEFAULT_TYPE1_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s^@DEFAULT_GS_LIB_PATH@ ^.B $mk_DEFAULT_GS_LIB_PATH\\
+^" | sed -e "s^:^\\\\\\
+.TP\\\\\\
+.B ^g"
+
+echo "s/@DEFAULT_FONT_SIZES@/$mk_DEFAULT_FONT_SIZES/" | sed -e "s/:/ :\\\\\\
+/g"
+
+# Combination changes.
+
+if test -z "$mk_PS" || test -z "$mk_DEFAULT_CONFIG_PATH"; then
+ echo '/^#ifconfigps/,/^#/d'
+fi
+
+# Remove all remaining '#' lines
+
+echo '/^#/d'
+
+# Done
+
+exit 0
diff --git a/pk.c b/pk.c
@@ -0,0 +1,363 @@
+/*========================================================================*\
+
+Copyright (c) 1990-1999 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+/*
+ * PK font reading routines.
+ * Public routines are read_PK_index and read_PK_char.
+ */
+
+#include "xdvi.h"
+
+#define PK_ID 89
+#define PK_CMD_START 240
+#define PK_X1 240
+#define PK_X2 241
+#define PK_X3 242
+#define PK_X4 243
+#define PK_Y 244
+#define PK_POST 245
+#define PK_NOOP 246
+#define PK_PRE 247
+
+static int PK_flag_byte;
+static unsigned PK_input_byte;
+static int PK_bitpos;
+static int PK_dyn_f;
+static int PK_repeat_count;
+
+static int
+PK_get_nyb(fp)
+ FILE *fp;
+{
+ unsigned temp;
+ if (PK_bitpos < 0) {
+ PK_input_byte = one(fp);
+ PK_bitpos = 4;
+ }
+ temp = PK_input_byte >> PK_bitpos;
+ PK_bitpos -= 4;
+ return (temp & 0xf);
+}
+
+
+static int
+PK_packed_num(fp)
+ FILE *fp;
+{
+ int i,j;
+
+ if ((i = PK_get_nyb(fp)) == 0) {
+ do {
+ j = PK_get_nyb(fp);
+ ++i;
+ }
+ while (j == 0);
+ while (i > 0) {
+ j = (j << 4) | PK_get_nyb(fp);
+ --i;
+ }
+ return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f);
+ }
+ else {
+ if (i <= PK_dyn_f) return i;
+ if (i < 14)
+ return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp)
+ + PK_dyn_f + 1);
+ if (i == 14) PK_repeat_count = PK_packed_num(fp);
+ else PK_repeat_count = 1;
+ return PK_packed_num(fp);
+ }
+}
+
+
+static void
+PK_skip_specials(fontp)
+ struct font *fontp;
+{
+ int i, j;
+ FILE *fp = fontp->file;
+
+ do {
+ PK_flag_byte = one(fp);
+ if (PK_flag_byte >= PK_CMD_START) {
+ switch (PK_flag_byte) {
+ case PK_X1 :
+ case PK_X2 :
+ case PK_X3 :
+ case PK_X4 :
+ i = 0;
+ for (j = PK_CMD_START; j <= PK_flag_byte; ++j)
+ i = (i << 8) | one(fp);
+ while (i--) (void) one(fp);
+ break;
+ case PK_Y :
+ (void) four(fp);
+ break;
+ case PK_POST :
+ case PK_NOOP :
+ break;
+ default :
+ oops("Unexpected %d in PK file %s", PK_flag_byte,
+ fontp->filename);
+ break;
+ }
+ }
+ }
+ while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START);
+}
+
+/*
+ * Public routines
+ */
+
+static void
+#if NeedFunctionPrototypes
+read_PK_char(struct font *fontp, wide_ubyte ch)
+#else /* !NeedFunctionPrototypes */
+read_PK_char(fontp, ch)
+ struct font *fontp;
+ ubyte ch;
+#endif /* NeedFunctionPrototypes */
+{
+ int i, j;
+ int n;
+ int row_bit_pos;
+ Boolean paint_switch;
+ BMUNIT *cp;
+ struct glyph *g;
+ FILE *fp = fontp->file;
+ long fpwidth;
+ BMUNIT word;
+ int word_weight, bytes_wide;
+ int rows_left, h_bit, count;
+
+ g = &fontp->glyph[ch];
+ PK_flag_byte = g->x2;
+ PK_dyn_f = PK_flag_byte >> 4;
+ paint_switch = ((PK_flag_byte & 8) != 0);
+ PK_flag_byte &= 0x7;
+ if (PK_flag_byte == 7) n = 4;
+ else if (PK_flag_byte > 3) n = 2;
+ else n = 1;
+
+ if (debug & DBG_PK) Printf("loading pk char %d, char type %d ", ch, n);
+
+ /*
+ * now read rest of character preamble
+ */
+ if (n != 4) fpwidth = num(fp, 3);
+ else {
+ fpwidth = sfour(fp);
+ (void) four(fp); /* horizontal escapement */
+ }
+ (void) num(fp, n); /* vertical escapement */
+ {
+ unsigned long w, h;
+
+ w = num(fp, n);
+ h = num(fp, n);
+ if (w > 0x7fff || h > 0x7fff)
+ oops("Character %d too large in file %s", ch, fontp->fontname);
+ g->bitmap.w = w;
+ g->bitmap.h = h;
+ }
+ g->x = snum(fp, n);
+ g->y = snum(fp, n);
+
+ g->dvi_adv = fontp->dimconv * fpwidth;
+
+ if (debug & DBG_PK) {
+ if (g->bitmap.w != 0)
+ Printf(", size=%dx%d, dvi_adv=%ld", g->bitmap.w, g->bitmap.h,
+ g->dvi_adv);
+ Putchar('\n');
+ }
+
+ alloc_bitmap(&g->bitmap);
+ cp = (BMUNIT *) g->bitmap.bits;
+
+ /*
+ * read character data into *cp
+ */
+ bytes_wide = ROUNDUP((int) g->bitmap.w, BMBITS) * BMBYTES;
+ PK_bitpos = -1;
+ if (PK_dyn_f == 14) { /* get raster by bits */
+ bzero(g->bitmap.bits, (int) g->bitmap.h * bytes_wide);
+ for (i = 0; i < (int) g->bitmap.h; i++) { /* get all rows */
+ cp = ADD(g->bitmap.bits, i * bytes_wide);
+#ifndef WORDS_BIGENDIAN
+ row_bit_pos = -1;
+#else
+ row_bit_pos = BMBITS;
+#endif
+ for (j = 0; j < (int) g->bitmap.w; j++) { /* get one row */
+ if (--PK_bitpos < 0) {
+ word = one(fp);
+ PK_bitpos = 7;
+ }
+#ifndef WORDS_BIGENDIAN
+ if (++row_bit_pos >= BMBITS) {
+ cp++;
+ row_bit_pos = 0;
+ }
+#else
+ if (--row_bit_pos < 0) {
+ cp++;
+ row_bit_pos = BMBITS - 1;
+ }
+#endif
+ if (word & (1 << PK_bitpos)) *cp |= 1 << row_bit_pos;
+ }
+ }
+ }
+ else { /* get packed raster */
+ rows_left = g->bitmap.h;
+ h_bit = g->bitmap.w;
+ PK_repeat_count = 0;
+ word_weight = BMBITS;
+ word = 0;
+ while (rows_left > 0) {
+ count = PK_packed_num(fp);
+ while (count > 0) {
+ if (count < word_weight && count < h_bit) {
+#ifndef WORDS_BIGENDIAN
+ if (paint_switch)
+ word |= bit_masks[count] << (BMBITS - word_weight);
+#endif
+ h_bit -= count;
+ word_weight -= count;
+#ifdef WORDS_BIGENDIAN
+ if (paint_switch)
+ word |= bit_masks[count] << word_weight;
+#endif
+ count = 0;
+ }
+ else if (count >= h_bit && h_bit <= word_weight) {
+ if (paint_switch)
+ word |= bit_masks[h_bit] <<
+#ifndef WORDS_BIGENDIAN
+ (BMBITS - word_weight);
+#else
+ (word_weight - h_bit);
+#endif
+ *cp++ = word;
+ /* "output" row(s) */
+ for (i = PK_repeat_count * bytes_wide / BMBYTES;
+ i > 0; --i) {
+ *cp = *SUB(cp, bytes_wide);
+ ++cp;
+ }
+ rows_left -= PK_repeat_count + 1;
+ PK_repeat_count = 0;
+ word = 0;
+ word_weight = BMBITS;
+ count -= h_bit;
+ h_bit = g->bitmap.w;
+ }
+ else {
+ if (paint_switch)
+#ifndef WORDS_BIGENDIAN
+ word |= bit_masks[word_weight] <<
+ (BMBITS - word_weight);
+#else
+ word |= bit_masks[word_weight];
+#endif
+ *cp++ = word;
+ word = 0;
+ count -= word_weight;
+ h_bit -= word_weight;
+ word_weight = BMBITS;
+ }
+ }
+ paint_switch = 1 - paint_switch;
+ }
+ if (cp != ((BMUNIT *) (g->bitmap.bits + bytes_wide * g->bitmap.h)))
+ oops("Wrong number of bits stored: char. %d, font %s", ch,
+ fontp->fontname);
+ if (rows_left != 0 || h_bit != g->bitmap.w)
+ oops("Bad pk file (%s), too many bits", fontp->fontname);
+ }
+}
+
+void
+read_PK_index(fontp, hushcs)
+ struct font *fontp;
+ wide_bool hushcs;
+{
+ int hppp, vppp;
+ long checksum;
+
+ fontp->read_char = read_PK_char;
+ if (debug & DBG_PK)
+ Printf("Reading PK pixel file %s\n", fontp->filename);
+
+ Fseek(fontp->file, (long) one(fontp->file), 1); /* skip comment */
+
+ (void) four(fontp->file); /* skip design size */
+ checksum = four(fontp->file);
+ if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
+ && !hushcs)
+ Fprintf(stderr,
+ "Checksum mismatch (dvi = %lu, pk = %lu) in font file %s\n",
+ fontp->checksum, checksum, fontp->filename);
+ hppp = sfour(fontp->file);
+ vppp = sfour(fontp->file);
+ if (hppp != vppp && (debug & DBG_PK))
+ Printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp);
+ /*
+ * Prepare glyph array.
+ */
+ fontp->glyph = xmalloc(256 * sizeof(struct glyph));
+ bzero((char *) fontp->glyph, 256 * sizeof(struct glyph));
+ /*
+ * Read glyph directory (really a whole pass over the file).
+ */
+ for (;;) {
+ int bytes_left, flag_low_bits;
+ unsigned int ch;
+
+ PK_skip_specials(fontp);
+ if (PK_flag_byte == PK_POST) break;
+ flag_low_bits = PK_flag_byte & 0x7;
+ if (flag_low_bits == 7) {
+ bytes_left = four(fontp->file);
+ ch = four(fontp->file);
+ } else if (flag_low_bits > 3) {
+ bytes_left = ((flag_low_bits - 4) << 16) + two(fontp->file);
+ ch = one(fontp->file);
+ } else {
+ bytes_left = (flag_low_bits << 8) + one(fontp->file);
+ ch = one(fontp->file);
+ }
+ fontp->glyph[ch].addr = ftell(fontp->file);
+ fontp->glyph[ch].x2 = PK_flag_byte;
+ Fseek(fontp->file, (long) bytes_left, 1);
+ if (debug & DBG_PK)
+ Printf("Scanning pk char %u, at %ld.\n", ch,
+ fontp->glyph[ch].addr);
+ }
+}
diff --git a/popups.c b/popups.c
@@ -0,0 +1,4540 @@
+/*========================================================================*\
+
+Copyright (c) 2001-2004 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * Code for popup windows.
+ */
+
+#include "xdvi.h"
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+/* Xlib and Xutil are already included */
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#if XAW
+# include <X11/Shell.h>
+# if XAW3D
+# include <X11/Xaw3d/Form.h>
+# include <X11/Xaw3d/Label.h>
+# include <X11/Xaw3d/Command.h>
+# include <X11/Xaw3d/Toggle.h>
+# include <X11/Xaw3d/AsciiText.h>
+# include <X11/Xaw3d/Viewport.h>
+# else
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+# include <X11/Xaw/Viewport.h>
+# endif
+# if XtSpecificationRelease < 5
+# define XawChainLeft XtChainLeft
+# define XawChainRight XtChainRight
+# define XawChainTop XtChainTop
+# define XawChainBottom XtChainBottom
+# endif
+# if XtSpecificationRelease < 6
+# define XawFmt8Bit FMT8BIT
+# endif
+#else /* MOTIF */
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/MessageB.h>
+# include <Xm/FileSB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+#endif /* MOTIF */
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#if NeedVarargsPrototypes
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy __va_copy
+# else
+# define va_copy(aq, ap) aq = ap
+# endif
+#endif
+
+#if HAVE_GOOD_SETSID_VFORK
+# if HAVE_VFORK_H
+# include <vfork.h>
+# endif
+#else
+ /* Mac OS X 10.3 (Panther) (11/2003) doesn't allow setsid() within vfork() */
+# undef vfork
+# define vfork fork
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(status) (((status) & 255) == 0)
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(status) ((unsigned)(status) >> 8)
+#endif
+#ifndef WIFSIGNALED
+# ifndef WIFSTOPPED
+# define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+# endif
+# define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
+#endif
+#ifndef WTERMSIG
+# define WTERMSIG(status) ((status) & 0x7f)
+#endif
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+# define O_NONBLOCK O_NDELAY
+#endif
+
+#ifdef EWOULDBLOCK
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+# else
+# define AGAIN_CONDITION (errno == EWOULDBLOCK)
+# endif
+#else /* EWOULDBLOCK */
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EAGAIN)
+# endif
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+
+/*
+ * New variants on printf.
+ */
+
+static int uintlen(i)
+ unsigned int i;
+{
+ int len = 0;
+
+ do {
+ ++len;
+ i /= 10;
+ }
+ while (i != 0);
+
+ return len;
+}
+
+/*
+ * (v)nprintf(fmt, ...) - return the length of the string produced.
+ */
+
+#if HAVE_GOOD_VSNPRINTF
+
+# define vnprintf(fmt, ap) vsnprintf(NULL, 0, fmt, ap)
+
+#else /* !HAVE_GOOD_VSNPRINTF */
+
+static int
+vnprintf(format, args)
+ _Xconst char *format;
+ va_list args;
+{
+ _Xconst char *p, *p_end, *q;
+ int len;
+
+ p = format;
+ p_end = p + strlen(p);
+ len = 0;
+ for (;;) {
+ q = memchr(p, '%', p_end - p);
+ if (q == NULL) {
+ len += p_end - p;
+ break;
+ }
+ len += q - p;
+ p = q + 1;
+ switch (*p++) {
+ case '%':
+ ++len;
+ break;
+ case 'd':
+ {
+ int i = va_arg(args, int);
+
+ len += (i < 0 ? uintlen(-i) + 1 : uintlen(i));
+ }
+ break;
+ case 's':
+ len += strlen(va_arg(args, _Xconst char *));
+ break;
+ default:
+ oops("Invalid designator `%c' in format string \"%s\"\n",
+ p[-1], format);
+ }
+ }
+
+ return len;
+}
+
+
+#if 0 /* not needed (yet) */
+
+static int
+#if NeedVarargsPrototypes
+nprintf(_Xconst char *format, ...)
+#else
+/* VARARGS */
+nprintf(va_alist)
+ va_dcl
+#endif
+{
+#if !NeedVarargsPrototypes
+ _Xconst char *format;
+#endif
+ va_list args;
+ int len;
+
+#if NeedVarargsPrototypes
+ va_start(args, format);
+#else
+ va_start(args);
+ format = va_arg(args, _Xconst char *);
+#endif
+
+ len = vnprintf(format, args);
+ va_end(args);
+ return len;
+}
+
+#endif /* if 0 */
+
+#endif /* !HAVE_GOOD_VSNPRINTF */
+
+/*
+ * (v)mprintf(fmt, ...) - printf to allocated string.
+ */
+
+static char *
+vmprintf(format, args)
+ _Xconst char *format;
+ va_list args;
+{
+#if !HAVE_VASPRINTF
+ va_list args2;
+ int len;
+#endif
+ char *result;
+
+#if HAVE_VASPRINTF
+ if (vasprintf(&result, format, args) < 0)
+ oops("! Out of memory (call to vasprintf() with format \"%s\").\n",
+ format);
+#else
+ va_copy(args2, args);
+ len = vnprintf(format, args2) + 1;
+ va_end(args2);
+
+ result = xmalloc(len);
+# if HAVE_VSNPRINTF
+ (void) vsnprintf(result, len, format, args);
+# else
+ (void) vsprintf(result, format, args);
+# endif
+#endif /* ! HAVE_VASPRINTF */
+
+ return result;
+}
+
+static char *
+#if NeedVarargsPrototypes
+mprintf(_Xconst char *format, ...)
+#else
+/* VARARGS */
+mprintf(va_alist)
+ va_dcl
+#endif
+{
+#if !NeedVarargsPrototypes
+ _Xconst char *format;
+#endif
+ va_list args;
+ char *result;
+
+#if NeedVarargsPrototypes
+ va_start(args, format);
+#else
+ va_start(args);
+ format = va_arg(args, _Xconst char *);
+#endif
+
+ result = vmprintf(format, args);
+ va_end(args);
+ return result;
+}
+
+
+#if XAW
+
+/*
+ * Realize the widget and set the callback for the WM_DESTROY protocol.
+ */
+
+static void
+XdviXawRealizePopup(shell, callback)
+ Widget shell;
+ XtCallbackProc callback;
+{
+ XtRealizeWidget(shell);
+
+ XSetWMProtocols(DISP, XtWindow(shell), &XA_WM_DELETE_WINDOW, 1);
+ XtAddEventHandler(shell, NoEventMask, True, handle_messages, callback);
+}
+
+#endif /* XAW */
+
+
+/*
+ * Simple popup - Just a text message. May not be done before realizing
+ * the main window.
+ */
+
+/*
+ * In reality, the "simple" popup is not so simple, because certain
+ * window managers (e.g., twm, fvwm1) leave the window showing if you
+ * pop it down too soon after popping it up. To remedy this, we delay
+ * calling XtPopdown() until the previous call to XtPopup() has generated
+ * a MapNotify event. Likewise, we delay XtPopup() until the previous
+ * XtPopdown() call has produced an UnmapNotify event.
+ *
+ * To make it just a little more complicated, for some reason the popup
+ * may get mapped after being unmapped. If so, we call XtPopup() to
+ * inform the toolkit of its mistake, and arrange to expect some spurious
+ * events. To reproduce this bug, remove the "spurious" code, run xdvi,
+ * move the mouse a little, then hit "n" a few times. This happens only
+ * with twm.
+ */
+
+/* ARGSUSED */
+static void
+handle_popup_events(widget, rec, ev, cont)
+ Widget widget;
+ XtPointer rec;
+ XEvent *ev;
+ Boolean *cont; /* unused */
+{
+#define prec ((struct status_popup *) rec)
+
+ if (ev->type == MapNotify) {
+ if (prec->expected_type == MapNotify) {
+ prec->expected_type = 0;
+ if (!prec->popped) {
+ prec->expected_type = UnmapNotify;
+ XtPopdown(prec->shell);
+ }
+ }
+ else {
+ if (debug & DBG_EVENT)
+ fprintf(stderr,
+ "handle_popup_events: got spurious MapNotify\n");
+ prec->expected_type = UnmapNotify;
+ prec->spurious = True;
+ XtPopup(prec->shell, XtGrabNone);
+ }
+ }
+ else if (ev->type == UnmapNotify) {
+ if (prec->expected_type == UnmapNotify) {
+ prec->expected_type = 0;
+ if (prec->spurious) {
+ prec->expected_type = MapNotify;
+ prec->spurious = False;
+ }
+ else if (prec->popped) {
+ prec->expected_type = MapNotify;
+ XtPopup(prec->shell, XtGrabNone);
+ }
+ }
+ else
+ if (debug & DBG_EVENT)
+ fprintf(stderr,
+ "handle_popup_events: got spurious UnmapNotify\n");
+ }
+
+#undef prec
+}
+
+
+#if XAW
+
+void
+simple_popup(rec, message, callback)
+ struct status_popup *rec;
+ _Xconst char *message;
+ XtCallbackProc callback;
+{
+ Position x, y;
+ Dimension w1, h1, w2, h2;
+ Boolean old_rec_popped = rec->popped;
+
+ rec->popped = True;
+ if (rec->shell == NULL) {
+ rec->shell = XtVaCreatePopupShell("status",
+ transientShellWidgetClass, top_level,
+ XtNtitle, "Xdvi status",
+ XtNmappedWhenManaged, False,
+ XtNallowShellResize, True,
+ XtNtransientFor, top_level,
+ NULL);
+ XtAddEventHandler(rec->shell, StructureNotifyMask, False,
+ handle_popup_events, (XtPointer) rec);
+
+ rec->label = XtVaCreateManagedWidget("label", labelWidgetClass,
+ rec->shell,
+ XtNlabel, message,
+ NULL);
+
+ XdviXawRealizePopup(rec->shell, callback);
+ }
+ else
+ XtVaSetValues(rec->label, XtNlabel, message, NULL);
+
+ if (mane.win != (Window) 0)
+ XtVaGetValues(top_level, XtNx, &x, XtNy, &y,
+ XtNwidth, &w1, XtNheight, &h1, NULL);
+ else {
+ x = y = 0;
+ w1 = WidthOfScreen(SCRN);
+ h1 = HeightOfScreen(SCRN);
+ }
+
+ /* Get the size of the popup window */
+ XtVaGetValues(rec->label, XtNwidth, &w2, XtNheight, &h2, NULL);
+
+ /* Center the popup over the main window */
+ XtVaSetValues(rec->shell, XtNx, x + (w1 - w2) / 2,
+ XtNy, y + (h1 - h2) / 2, NULL);
+
+ if (!rec->expected_type && !old_rec_popped) {
+ rec->expected_type = MapNotify;
+ XtPopup(rec->shell, XtGrabNone);
+ }
+}
+
+#else /* MOTIF */
+
+void
+simple_popup(rec, message, callback)
+ struct status_popup *rec;
+ _Xconst char *message;
+ XtCallbackProc callback;
+{
+ Widget bb;
+ XmString str;
+ Boolean old_rec_popped = rec->popped;
+
+ rec->popped = True;
+ str = XmStringCreateLtoR((char *) message, XmFONTLIST_DEFAULT_TAG);
+ if (rec->shell == NULL) {
+ rec->shell = XtVaCreatePopupShell("status",
+ xmDialogShellWidgetClass, top_level,
+ XmNallowShellResize, True,
+ XmNdeleteResponse, XmDO_NOTHING,
+ XmNtitle, "Xdvi status",
+ NULL);
+ XtAddEventHandler(rec->shell, StructureNotifyMask, False,
+ handle_popup_events, (XtPointer) rec);
+ XmAddWMProtocolCallback(rec->shell, XA_WM_DELETE_WINDOW, callback,
+ NULL);
+
+ bb = XtCreateWidget("bulletin", xmBulletinBoardWidgetClass,
+ rec->shell, NULL, 0);
+
+ rec->label = XtVaCreateManagedWidget("label", xmLabelGadgetClass,
+ bb,
+ XmNlabelString, str,
+ NULL);
+
+ XtManageChild(bb);
+ }
+ else
+ XtVaSetValues(rec->label, XmNlabelString, str, NULL);
+
+ XmStringFree(str);
+
+ if (!rec->expected_type && !old_rec_popped) {
+ rec->expected_type = MapNotify;
+ XtPopup(rec->shell, XtGrabNone);
+ }
+}
+
+#endif
+
+void
+simple_popdown(rec)
+ struct status_popup *rec;
+{
+ rec->popped = False;
+ if (!rec->expected_type) {
+ rec->expected_type = UnmapNotify;
+ XtPopdown(rec->shell);
+ }
+}
+
+
+/*
+ * Warning popup - used for most error and notice conditions.
+ * It includes a message and a button (and, in the case of the Motif
+ * toolkit, a bitmap).
+ */
+
+/* ARGSUSED */
+static void
+warn_callback(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ /* XtIsShell(w) holds if this is caused by the WM_DESTROY protocol */
+ XtDestroyWidget(XtIsShell(w) ? w : (Widget) client_data);
+}
+
+#if XAW
+
+void
+do_popup(shell)
+ Widget shell;
+{
+ Position x, y;
+ Dimension w1, h1, w2, h2;
+
+ /* Get the size and location of the main window */
+ x = y = 0;
+ w1 = WidthOfScreen(SCRN);
+ h1 = HeightOfScreen(SCRN);
+ if (mane.win != (Window) 0)
+ XtVaGetValues(top_level, XtNx, &x, XtNy, &y,
+ XtNwidth, &w1, XtNheight, &h1, NULL);
+
+ /* Get the size of the popup window */
+ XtVaGetValues(shell, XtNwidth, &w2, XtNheight, &h2, NULL);
+
+ /* Center the popup over the main window */
+ XtVaSetValues(shell, XtNx, x + (w1 - w2) / 2,
+ XtNy, y + (h1 - h2) / 2, NULL);
+
+ XtPopup(shell, XtGrabNone);
+}
+
+Widget
+warning_popup(message, button_name, callback)
+ _Xconst char *message;
+ _Xconst char *button_name;
+ XtCallbackProc callback;
+{
+ Widget shell, form, label, button;
+ Dimension w1, w2, bw;
+ int dist;
+
+ shell = XtVaCreatePopupShell("warn", transientShellWidgetClass,
+ top_level,
+ XtNtitle, "Xdvi warning",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, top_level,
+ NULL);
+ form = XtCreateManagedWidget("form", formWidgetClass, shell,
+ NULL, 0);
+ label = XtVaCreateManagedWidget("label", labelWidgetClass, form,
+ XtNlabel, message,
+ XtNborderWidth, 0,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+ button = XtVaCreateManagedWidget(button_name, commandWidgetClass, form,
+ XtNaccelerators, accels_cr_click,
+ XtNfromVert, label,
+ NULL);
+ XtAddCallback(button, XtNcallback,
+ callback != NULL ? callback : warn_callback, shell);
+ XtInstallAccelerators(form, button);
+
+ /* Center button under message */
+ XtVaGetValues(label, XtNwidth, &w1, NULL);
+ XtVaGetValues(button, XtNwidth, &w2, XtNborderWidth, &bw, NULL);
+ w2 += 2 * bw;
+ if (w1 > w2) {
+ XtVaGetValues(button, XtNhorizDistance, &dist, NULL);
+ XtVaSetValues(button, XtNhorizDistance, dist + (w1 - w2) / 2, NULL);
+ }
+ else if (w1 < w2) {
+ XtVaGetValues(label, XtNhorizDistance, &dist, NULL);
+ XtVaSetValues(label, XtNhorizDistance, dist + (w2 - w1) / 2, NULL);
+ }
+
+ XdviXawRealizePopup(shell, callback != NULL ? callback : warn_callback);
+
+ if (postpone_popups) {
+ /* save it for later */
+ if (n_init_popups >= alloc_init_popups) {
+ if (alloc_init_popups != 0)
+ init_popups = xrealloc(init_popups,
+ (alloc_init_popups += 2) * sizeof (*init_popups));
+ else
+ init_popups = xmalloc((alloc_init_popups = 2)
+ * sizeof (*init_popups));
+ }
+ init_popups[n_init_popups++] = shell;
+ }
+ else
+ do_popup(shell);
+
+ return shell;
+}
+
+#else /* MOTIF */
+
+void
+do_popup(dialog)
+ Widget dialog;
+{
+ XtManageChild(dialog);
+ XtPopup(XtParent(dialog), XtGrabNone);
+}
+
+Widget
+warning_popup(message, mtype, button_name, callback)
+ _Xconst char *message;
+ int mtype;
+ _Xconst char *button_name;
+ XtCallbackProc callback;
+{
+ Widget shell;
+ Widget dialog;
+ XmString str;
+
+ shell = XtVaCreatePopupShell("warn", xmDialogShellWidgetClass,
+ top_level,
+ XmNdeleteResponse, XmDO_NOTHING,
+ XmNtitle, "Xdvi warning",
+ NULL);
+ XmAddWMProtocolCallback(shell, XA_WM_DELETE_WINDOW,
+ callback != NULL ? callback : warn_callback, NULL);
+
+ dialog = XtVaCreateWidget("dialog", xmMessageBoxWidgetClass, shell,
+ XmNdialogType, mtype,
+ NULL);
+ XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
+ XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
+
+ XtAddCallback(dialog, XmNokCallback,
+ callback != NULL ? callback : warn_callback, shell);
+
+ str = XmStringCreateLtoR((char *) message, XmFONTLIST_DEFAULT_TAG);
+ XtVaSetValues(dialog, XmNmessageString, str, NULL);
+ XmStringFree(str);
+
+ if (button_name != NULL) {
+ str = XmStringCreateLocalized((char *) button_name);
+ XtVaSetValues(dialog, XmNokLabelString, str, NULL);
+ XmStringFree(str);
+ }
+
+ XtInstallAllAccelerators(dialog,
+ XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON));
+
+ if (postpone_popups) {
+ /* save it for later */
+ if (n_init_popups >= alloc_init_popups) {
+ if (alloc_init_popups != 0)
+ init_popups = xrealloc(init_popups,
+ (alloc_init_popups += 2) * sizeof (*init_popups));
+ else
+ init_popups = xmalloc((alloc_init_popups = 2)
+ * sizeof (*init_popups));
+ }
+ init_popups[n_init_popups++] = dialog;
+ }
+ else
+ do_popup(dialog);
+
+ return shell;
+}
+
+#endif /* MOTIF */
+
+Widget
+#if NeedVarargsPrototypes
+warning_popup_long(_Xconst char *format,
+# if MOTIF
+ int mtype,
+# endif
+ _Xconst char *button_name, XtCallbackProc callback, ...)
+#else /* ! NeedVarargsPrototypes */
+# if XAW
+warning_popup_long(format, button_name, callback, va_alist)
+ _Xconst char *format;
+ _Xconst char *button_name;
+ XtCallbackProc callback;
+# else /* MOTIF */
+warning_popup_long(format, mtype, button_name, callback, va_alist)
+ _Xconst char *format;
+ int mtype;
+ _Xconst char *button_name;
+ XtCallbackProc callback;
+# endif
+ va_dcl
+#endif /* ! NeedVarargsPrototypes */
+{
+ va_list args;
+ char *str;
+ Widget w;
+
+#if NeedVarargsPrototypes
+ va_start(args, callback);
+#else
+ va_start(args);
+#endif
+ str = vmprintf(format, args);
+ va_end(args);
+
+#if XAW
+ w = warning_popup(str, button_name, callback);
+#else /* MOTIF */
+ w = warning_popup(str, mtype, button_name, callback);
+#endif
+
+ free(str);
+
+ return w;
+}
+
+
+#if XAW
+
+/*
+ * Confirm popup - Pop up a window and ask a yes/no question.
+ */
+
+Widget
+confirm_popup(message, button_name, callback, yes_answer, no_answer)
+ _Xconst char *message;
+ _Xconst char *button_name;
+ XtCallbackProc callback;
+ XtPointer yes_answer, no_answer;
+{
+ Widget shell, form, label, button1, button2;
+ int ddist;
+ Dimension w0, w1, w2, bw1, bw2, tw;
+
+ shell = XtVaCreatePopupShell("confirm", transientShellWidgetClass,
+ top_level,
+ XtNtitle, "Xdvi question",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, top_level,
+ NULL);
+ form = XtCreateManagedWidget("form", formWidgetClass, shell,
+ NULL, 0);
+ label = XtVaCreateManagedWidget("label", labelWidgetClass, form,
+ XtNlabel, message,
+ XtNborderWidth, 0,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+
+ button1 = XtVaCreateManagedWidget(button_name, commandWidgetClass, form,
+ XtNaccelerators, accels_cr,
+ XtNfromVert, label,
+ NULL);
+ XtAddCallback(button1, XtNcallback, callback, yes_answer);
+ XtInstallAccelerators(form, button1);
+
+ button2 = XtVaCreateManagedWidget("Cancel", commandWidgetClass, form,
+ XtNfromVert, label,
+ XtNfromHoriz, button1,
+ NULL);
+ XtAddCallback(button2, XtNcallback, callback, no_answer);
+
+ /* Move cancel button to the right */
+ XtVaGetValues(label, XtNwidth, &w0, NULL);
+ XtVaGetValues(button1, XtNwidth, &w1, XtNborderWidth, &bw1, NULL);
+ XtVaGetValues(button2, XtNwidth, &w2, XtNborderWidth, &bw2, NULL);
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+ tw = w1 + w2 + 2 * (bw1 + bw2);
+ if (tw < w0 + ddist)
+ XtVaSetValues(button2, XtNhorizDistance, w0 - tw, NULL);
+
+ XdviXawRealizePopup(shell, callback);
+ do_popup(shell);
+
+ return shell;
+}
+
+#else /* MOTIF */
+
+Widget
+confirm_popup(message, button_name, callback, yes_answer, no_answer)
+ char *message;
+ char *button_name;
+ XtCallbackProc callback;
+ XtPointer yes_answer, no_answer;
+{
+ Widget dialog;
+ XmString msg, yes, no;
+
+ {
+ static Arg cq_args[] = {
+ {XmNdeleteResponse, XmDO_NOTHING},
+ };
+
+ dialog = XmCreateQuestionDialog(top_level, "confirm",
+ cq_args, XtNumber(cq_args));
+ XmAddWMProtocolCallback(XtParent(dialog), XA_WM_DELETE_WINDOW,
+ callback, NULL);
+ }
+ msg = XmStringCreateLocalized(message);
+ yes = XmStringCreateLocalized(button_name);
+ no = XmStringCreateLocalized("Cancel");
+ XtVaSetValues(dialog,
+ XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL,
+ XmNmessageString, msg,
+ XmNokLabelString, yes,
+ XmNcancelLabelString, no,
+ NULL);
+ XmStringFree(msg);
+ XmStringFree(yes);
+ XmStringFree(no);
+
+ XtAddCallback(dialog, XmNokCallback, callback, yes_answer);
+ XtAddCallback(dialog, XmNcancelCallback, callback, no_answer);
+ XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
+
+ XtManageChild(dialog);
+ dialog = XtParent(dialog);
+ XtPopup(dialog, XtGrabNone);
+
+ return dialog;
+}
+
+#endif /* MOTIF */
+
+
+/*
+ * File popup - pop up a window to allow the user to switch dvi files.
+ */
+
+/* Common data for XAW and MOTIF */
+
+static Boolean file_active = False; /* if file window is showing */
+static Widget file_shell = NULL; /* shell widget of popup */
+static Boolean reposition = False; /* we want to reposition it */
+
+/* Common routines */
+
+/* ARGSUSED */
+static void
+cb_file_cancel(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ XtPopdown(file_shell);
+ file_active = False;
+
+ if (mane.win == (Window) 0)
+ exit(1);
+}
+
+#if XAW
+
+static Widget f1text, f2vport, f2clip, f2form, f3text, f4text;
+static Widget *widget_list; /* list of file entries */
+static size_t wl_num = 0; /* actual number of widgets */
+static Widget file_highlit = NULL; /* highlighted widget */
+static int file_hl_seq = -1; /* sequence # of the above */
+static char *dirbuf = NULL; /* buffer containing dir name */
+static size_t dirlen = 0; /* length of above buffer */
+static XtTranslations file_xlats; /* for use in file entries */
+static int file_entry_height = 0; /* line height in viewport */
+static Position f2ddist; /* size of list border */
+
+struct suffix {
+ _Xconst char *str;
+ size_t len;
+};
+static struct suffix *suffixes = NULL;
+static struct suffix *suff_end = NULL;
+static size_t suff_max = 0; /* size of array allocated */
+
+/* Icon bitmap of directory */
+
+#define filedir_width 16
+#define filedir_height 13
+static unsigned char filedir_bits[] = {
+ 0xf0, 0x00, 0x08, 0x01, 0x06, 0x7e, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
+ 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xfe, 0x7f, 0x00, 0x00,
+ 0x00, 0x00};
+
+static char fileblank_bits[sizeof filedir_bits];
+static Pixmap filedir_pm = (Pixmap) 0;
+static Pixmap fileblank_pm = (Pixmap) 0;
+
+/* Bitmap of check mark */
+#define filechk_width 13
+#define filechk_height 13
+static unsigned char filechk_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x03,
+ 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00};
+
+static char fileunchk_bits[sizeof filechk_bits];
+static Pixmap filechk_pm = (Pixmap) 0;
+static Pixmap fileunchk_pm = (Pixmap) 0;
+static char filehide = '.';
+
+/* If the file widget is used before the dvi window goes up, then we destroy
+ * it because it might not have the right colormap and visual. We want to save
+ * the settings between these two incarnations, though. For the directory and
+ * the hidden-file checkbox, these are OK, but we need to do the same for the
+ * suffixes. */
+
+static _Xconst char *file_save_suff = ".dvi";
+
+static void act_file_go ARGS((Widget, XEvent *, String *, Cardinal *));
+static void act_file_click ARGS((Widget, XEvent *, String *, Cardinal *));
+static void act_file_suffixes ARGS((Widget, XEvent *, String *, Cardinal *));
+static void act_file_scroll ARGS((Widget, XEvent *, String *, Cardinal *));
+static void act_file_arrow ARGS((Widget, XEvent *, String *, Cardinal *));
+static void act_file_home ARGS((Widget, XEvent *, String *, Cardinal *));
+static void act_file_end ARGS((Widget, XEvent *, String *, Cardinal *));
+
+static XtActionsRec file_actions[] = {
+ {"file-go", act_file_go},
+ {"file-click", act_file_click},
+ {"file-suff", act_file_suffixes},
+ {"file-scroll", act_file_scroll},
+ {"file-arrow", act_file_arrow},
+ {"file-home", act_file_home},
+ {"file-end", act_file_end},
+};
+
+#ifndef FILEINDENT
+# define FILEINDENT 25
+#endif
+
+#ifndef DIR_SIZE_INCR
+# define DIR_SIZE_INCR 64
+#endif
+
+
+/*
+ * Refresh list of files in the chosen directory.
+ */
+
+struct dirnode {
+ struct dirnode *next;
+ _Xconst char *name;
+};
+
+static struct dirnode *
+ll_sort(np)
+ struct dirnode *np;
+{
+ struct dirnode *np1, *np2;
+ struct dirnode **npp;
+ struct dirnode *np0;
+
+ if (np == NULL || (np2 = np->next) == NULL)
+ return np;
+
+ np1 = np;
+ for (;;) {
+ np2 = np2->next;
+ if (np2 == NULL) break;
+ np2 = np2->next;
+ if (np2 == NULL) break;
+ np1 = np1->next;
+ }
+
+ np2 = ll_sort(np1->next);
+ np1->next = NULL;
+ np1 = ll_sort(np);
+
+ npp = &np0;
+ for (;;)
+ if (strcmp(np1->name, np2->name) < 0) {
+ *npp = np1;
+ npp = &np1->next;
+ np1 = np1->next;
+ if (np1 == NULL) {
+ *npp = np2;
+ break;
+ }
+ }
+ else {
+ *npp = np2;
+ npp = &np2->next;
+ np2 = np2->next;
+ if (np2 == NULL) {
+ *npp = np1;
+ break;
+ }
+ }
+
+ return np0;
+}
+
+static Boolean
+suffix_check(s, len)
+ _Xconst char *s;
+ size_t len;
+{
+ struct suffix *sp;
+
+ if (suffixes == suff_end)
+ return True;
+
+ for (sp = suffixes; sp < suff_end; ++sp)
+ if (len >= sp->len
+ && memcmp(s + len - sp->len, sp->str, sp->len) == 0)
+ return True;
+
+ return False;
+}
+
+static void
+file_refresh()
+{
+ struct dirnode *head;
+ struct dirnode *np;
+ struct dirnode **npp;
+ DIR *dirp;
+ size_t count;
+ Widget prev;
+ int i;
+ static Widget *icon_list;
+ static unsigned wl_max = 0; /* allocated space in list */
+
+ if (f3text != NULL)
+ XtVaSetValues(f3text, XtNstring, "", NULL);
+ else
+ wl_num = 0;
+
+ dirp = xopendir(dirbuf);
+ npp = &head;
+ count = 0;
+ if (dirp != NULL) {
+ char *dirbuf2;
+ size_t dirlen2;
+ size_t len;
+
+ dirbuf2 = xmemdup(dirbuf, dirlen);
+ dirlen2 = dirlen;
+ len = strlen(dirbuf2);
+ dirbuf2[len++] = '/';
+
+ for (;;) {
+ struct dirent *dp;
+ struct stat buf;
+ size_t len2;
+ char dirchar;
+ char *s;
+
+ dp = readdir(dirp);
+ if (dp == NULL) break;
+ len2 = NAMLEN(dp);
+ if (dp->d_name[0] == '.' && (len2 == 1
+ || (len2 == 2 && dp->d_name[1] == '.'))) /* if . or .. */
+ continue;
+ if (dp->d_name[0] == filehide) /* if hidden */
+ continue;
+
+ if (dirlen2 <= len + len2) {
+ dirlen2 = ((len + len2) / DIR_SIZE_INCR + 1)
+ * DIR_SIZE_INCR;
+ dirbuf2 = xrealloc(dirbuf2, dirlen2);
+ }
+ s = dirbuf2 + len;
+ memcpy(s, dp->d_name, len2);
+ s[len2] = '\0';
+ dirchar = '0';
+ if (stat(dirbuf2, &buf) != 0 || !S_ISDIR(buf.st_mode)) {
+ dirchar = '1';
+ if (!suffix_check(s, len2))
+ continue;
+ }
+ ++len2;
+ s = xmalloc(len2 + 1);
+ *s = dirchar;
+ memcpy(s + 1, dirbuf2 + len, len2);
+
+ np = xmalloc(sizeof *np);
+ np->name = s;
+ *npp = np;
+ npp = &np->next;
+ ++count;
+ }
+ closedir(dirp);
+ }
+ *npp = NULL;
+
+ head = ll_sort(head);
+
+ if (count > wl_max) {
+ if (wl_max == 0) {
+ widget_list = xmalloc(count * sizeof(Widget));
+ icon_list = xmalloc(count * sizeof(Widget));
+ }
+ else {
+ widget_list = xrealloc(widget_list, count * sizeof(Widget));
+ icon_list = xrealloc(icon_list, count * sizeof(Widget));
+ }
+ wl_max = count;
+ }
+
+ if (XtIsManaged(f2form)) {
+ XtUnmanageChild(f2form);
+ if (file_highlit != NULL) {
+ XtCallActionProc(file_highlit, "reset", NULL, NULL, 0);
+ file_highlit = NULL;
+ file_hl_seq = -1;
+ }
+ }
+
+ if (head != NULL) {
+ if (filedir_pm == (Pixmap) 0)
+ filedir_pm = XCreateBitmapFromData(DISP,
+ mane.win != (Window) 0 ? mane.win
+ : RootWindowOfScreen(SCRN),
+ (_Xconst char *) filedir_bits,
+ filedir_width, filedir_height);
+ if (*head->name != '0' && fileblank_pm == (Pixmap) 0)
+ fileblank_pm = XCreateBitmapFromData(DISP,
+ mane.win != (Window) 0 ? mane.win
+ : RootWindowOfScreen(SCRN),
+ fileblank_bits, filedir_width, filedir_height);
+ }
+
+ i = 0;
+ if (count > 0 && wl_num > 0) {
+ XtVaSetValues(*icon_list,
+ XtNbitmap, *head->name == '0' ? filedir_pm : fileblank_pm,
+ NULL);
+ for (;;) {
+ XtVaSetValues(widget_list[i], XtNlabel, head->name + 1, NULL);
+ np = head->next;
+ free((char *) head->name);
+ free(head);
+ head = np;
+ ++i;
+ if (i >= count || i >= wl_num)
+ break;
+ if (*head->name == '0') {
+ if (icon_list[i] == NULL) {
+ char s[3 * sizeof(int) + 1];
+
+#if HAVE_VSNPRINTF
+ (void) snprintf(s, sizeof s, "i%u", i);
+#else
+ (void) sprintf(s2, "i%u", i);
+#endif
+ icon_list[i] = XtVaCreateManagedWidget(s,
+ labelWidgetClass, f2form,
+ XtNbitmap, filedir_pm,
+ XtNborderWidth, 0,
+ XtNfromVert, widget_list[i - 1],
+ XtNvertDistance, 0,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainTop,
+ NULL);
+ }
+ }
+ else if (icon_list[i] != NULL) {
+ XtDestroyWidget(icon_list[i]);
+ icon_list[i] = NULL;
+ }
+ }
+ }
+ if (head != NULL) {
+ if (i == 0) {
+ Dimension h, bw;
+
+ prev = *icon_list = XtVaCreateManagedWidget("i0",
+ labelWidgetClass, f2form,
+ XtNbitmap, *head->name == '0' ? filedir_pm : fileblank_pm,
+ XtNborderWidth, 0,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainTop,
+ NULL);
+ prev = *widget_list = XtVaCreateManagedWidget("0",
+ commandWidgetClass, f2form,
+ XtNlabel, head->name + 1,
+ XtNtranslations, file_xlats,
+ XtNborderWidth, 0,
+ XtNresizable, True,
+ XtNfromHoriz, prev,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainTop,
+ NULL);
+ np = head->next;
+ free((char *) head->name);
+ free(head);
+ head = np;
+ ++i;
+ XtVaGetValues(prev,
+ XtNy, &f2ddist,
+ XtNheight, &h,
+ XtNborderWidth, &bw,
+ NULL);
+ file_entry_height = h + 2 * bw;
+ }
+ else prev = widget_list[i - 1];
+ while (head != NULL) {
+ char s[3 * sizeof(int) + 1];
+
+#if HAVE_VSNPRINTF
+ (void) snprintf(s, sizeof s, "i%u", i);
+#else
+ (void) sprintf(s2, "i%u", i);
+#endif
+ icon_list[i] = *head->name != '0' ? NULL
+ : XtVaCreateManagedWidget(s, labelWidgetClass, f2form,
+ XtNbitmap, filedir_pm,
+ XtNborderWidth, 0,
+ XtNfromVert, prev,
+ XtNvertDistance, 0,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainTop,
+ NULL);
+ prev = widget_list[i] = XtVaCreateManagedWidget(s + 1,
+ commandWidgetClass, f2form,
+ XtNlabel, head->name + 1,
+ XtNtranslations, file_xlats,
+ XtNborderWidth, 0,
+ XtNresizable, True,
+ XtNfromHoriz, *icon_list,
+ XtNfromVert, prev,
+ XtNvertDistance, 0,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainTop,
+ NULL);
+ np = head->next;
+ free((char *) head->name);
+ free(head);
+ head = np;
+ ++i;
+ }
+ }
+
+ while (wl_num > count) {
+ XtDestroyWidget(widget_list[--wl_num]);
+ if (icon_list[wl_num] != NULL)
+ XtDestroyWidget(icon_list[wl_num]);
+ }
+
+ wl_num = count;
+
+ XtManageChild(f2form);
+}
+
+/* ARGSUSED */
+static void
+cb_file_up(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ char *p;
+
+ p = rindex(dirbuf, '/');
+ if (p == NULL)
+ return;
+
+ if (p == dirbuf) {
+ if (dirbuf[1] == '\0')
+ return;
+ ++p;
+ }
+
+ *p = '\0';
+ XtVaSetValues(f1text, XtNstring, dirbuf, NULL);
+ file_refresh();
+}
+
+/* ARGSUSED */
+static void
+cb_file_home(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ _Xconst char *d;
+ size_t l;
+
+ d = getenv("HOME");
+ if (d == NULL)
+ return;
+
+ l = strlen(d) + 1;
+ if (l > dirlen) {
+ dirlen = ((l - 1) / DIR_SIZE_INCR + 1) * DIR_SIZE_INCR;
+ free(dirbuf);
+ dirbuf = xmalloc(dirlen);
+ }
+
+ memcpy(dirbuf, d, l);
+ XtVaSetValues(f1text, XtNstring, dirbuf, NULL);
+ file_refresh();
+}
+
+/* ARGSUSED */
+static void
+cb_file_hidechk(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (filehide == '.') {
+ filehide = '\0';
+ XtVaSetValues(w, XtNbitmap, filechk_pm, NULL);
+ }
+ else {
+ filehide = '.';
+ XtVaSetValues(w, XtNbitmap, fileunchk_pm, NULL);
+ }
+
+ file_refresh();
+}
+
+static Boolean
+xdvi_get_cwd()
+{
+ if (dirbuf == NULL)
+ dirbuf = xmalloc(dirlen = DIR_SIZE_INCR);
+
+ for (;;) {
+ if (getcwd(dirbuf, dirlen) != NULL)
+ return True;
+ if (errno != ERANGE)
+ break;
+ free(dirbuf);
+ dirbuf = xmalloc(dirlen += DIR_SIZE_INCR);
+ }
+ dirbuf[0] = '.';
+ dirbuf[1] = '\0';
+ return False;
+}
+
+static Boolean
+get_dir_name(str, len)
+ _Xconst char *str;
+ size_t len;
+{
+ int fd;
+ Boolean val;
+
+ if (dirbuf == NULL)
+ dirbuf = xmalloc(dirlen = DIR_SIZE_INCR);
+
+ /* Normalize directory name */
+ while (len > 0 && str[len - 1] == '/') --len;
+ if (len == 0) {
+ dirbuf[0] = '/';
+ dirbuf[1] = '\0';
+ return True;
+ }
+
+ /* Save current directory */
+ fd = xopen(".", O_RDONLY);
+ if (fd == -1)
+ return False;
+
+ /* Change to new directory */
+ if (str[len] == '\0') {
+ if (chdir(str) != 0) {
+ close(fd);
+ return False;
+ }
+ }
+ else {
+ char *str2;
+
+ str2 = xmemdup(str, len + 1);
+ str2[len] = '\0';
+ if (chdir(str2) != 0) {
+ free(str2);
+ fchdir(fd);
+ close(fd);
+ return False;
+ }
+ free(str2);
+ }
+
+ val = xdvi_get_cwd();
+ fchdir(fd);
+ close(fd);
+ return val;
+}
+
+static Boolean
+path_is_clean(str, p1)
+ char *str;
+ char *p1;
+{
+ char *p_end = p1 + strlen(p1);
+ char *p;
+ char c;
+ struct stat buf;
+ int val;
+
+ for (;;) {
+ ++p1;
+ p = memchr(p1, '/', p_end - p1);
+ if (p == NULL)
+ p = p_end;
+
+ /* check for double slash or slash at end or "." or ".." */
+ if (p == p1 || (*p1 == '.' && (p == p1 + 1 ||
+ (p1[1] == '.' && p == p1 + 2))))
+ break;
+
+ c = *p;
+ *p = '\0';
+ val = lstat(str, &buf);
+ *p = c;
+
+ if (val != 0 || S_ISLNK(buf.st_mode))
+ break;
+
+ p1 = p;
+ if (p1 == p_end)
+ return True;
+ }
+
+ return False;
+}
+
+/* ARGSUSED */
+static void
+cb_file_go(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ char *s, *str;
+ char *p1;
+ struct stat buf;
+
+ XtVaGetValues(f3text, XtNstring, &s, NULL);
+
+ if (*s == '\0') { /* if no string */
+ file_refresh();
+ return;
+ }
+
+ if (*s == '/') /* if ignoring the chosen directory */
+ p1 = str = s;
+ else {
+ size_t l1, l2;
+
+ l1 = strlen(dirbuf);
+ l2 = strlen(s) + 1;
+ str = xmalloc(l1 + l2 + 1);
+ memcpy(str, dirbuf, l1);
+ p1 = str + l1;
+ *p1 = '/';
+ memcpy(p1 + 1, s, l2);
+ }
+
+ if (stat(str, &buf) != 0) { /* if file does not exist (or error) */
+ warning_popup_long("Error opening file: %s\n%s.", "OK", NULL, str,
+ strerror(errno));
+ }
+ else if (S_ISDIR(buf.st_mode)) { /* if directory */
+ if (path_is_clean(str, p1) || !get_dir_name(str, strlen(str))) {
+ size_t l;
+
+ l = strlen(str) + 1;
+ if (l > dirlen) {
+ dirlen = ((l - 1) / DIR_SIZE_INCR + 1) * DIR_SIZE_INCR;
+ free(dirbuf);
+ dirbuf = xmalloc(dirlen);
+ }
+
+ memcpy(dirbuf, str, l);
+ }
+ XtVaSetValues(f1text, XtNstring, dirbuf, NULL);
+ file_refresh();
+ }
+ else { /* if not directory (file, we hope) */
+ FILE *f;
+
+ /* Normally, dvi files are are not part of the fd-counting
+ provided by xfopen(), since there is only one of them.
+ However, in this case we're opening one before closing the
+ old one, so we have to use xfopen() in this case. */
+ f = xfopen(str, OPEN_MODE);
+ if (f == NULL)
+ warning_popup_long("Error opening file: %s\n%s.", "OK", NULL,
+ str, strerror(errno));
+ else {
+ ino_t old_inode;
+
+ ++n_files_left;
+ if (dvi_file != NULL)
+ fclose(dvi_file);
+ dvi_file = f;
+
+ if (dvi_name != NULL)
+ free(dvi_name);
+
+ if (str != s) {
+ dvi_name = str;
+ str = s;
+ }
+ else
+ dvi_name = xstrdup(str);
+
+ dvi_time = buf.st_mtime;
+
+ old_inode = dvi_inode;
+ form_dvi_property(buf.st_ino);
+ titles_are_stale = True;
+
+ if (mane.win != (Window) 0) { /* if not in startup code */
+ if (dvi_inode != old_inode)
+ set_dvi_property();
+
+ goto_page(0, home);
+ }
+ else
+ reposition = True;
+
+ XtPopdown(file_shell);
+ file_active = False;
+
+ ev_flags |= EV_NEWDOC;
+ }
+ }
+
+ if (str != s)
+ free(str);
+}
+
+/* ARGSUSED */
+static void
+act_file_go P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ cb_file_go(NULL, NULL, NULL);
+}
+
+static void
+select_file_entry(w)
+ Widget w;
+{
+ char *s;
+ Position fy; /* (minus) position of list in vport */
+ Dimension ch; /* height of clip widget */
+ Position ey; /* position of entry */
+ Dimension eh, eb; /* dimensions of entry */
+ ptrdiff_t dist;
+ Widget sbar;
+
+ if (file_highlit != NULL && file_highlit != w) {
+ XtCallActionProc(file_highlit, "reset", NULL, NULL, 0);
+ file_hl_seq = -1;
+ }
+ file_highlit = w;
+
+ XtVaGetValues(w, XtNlabel, &s, NULL);
+ XtVaSetValues(f3text, XtNstring, s, NULL);
+ XawTextSetInsertionPoint(f3text, strlen(s));
+
+ /* Make sure the entry is fully viewable */
+ XtVaGetValues(f2form, XtNy, &fy, NULL);
+ XtVaGetValues(f2clip, XtNheight, &ch, NULL);
+ XtVaGetValues(file_highlit,
+ XtNy, &ey,
+ XtNheight, &eh,
+ XtNborderWidth, &eb,
+ NULL);
+ eh += 2 * eb; /* real height of entry */
+ dist = ey + fy; /* position relative to viewable area */
+ if (dist < 0) {
+ sbar = XtNameToWidget(f2vport, "vertical");
+ if (sbar != NULL)
+ XtCallCallbacks(sbar, XtNscrollProc, (XtPointer) dist);
+ }
+ else {
+ dist += eh - ch;
+ if (dist > 0) {
+ sbar = XtNameToWidget(f2vport, "vertical");
+ if (sbar != NULL)
+ XtCallCallbacks(sbar, XtNscrollProc, (XtPointer) dist);
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+act_file_click P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ select_file_entry(w);
+}
+
+static void
+select_by_seq(seq)
+ int seq;
+{
+ Widget w = widget_list[seq];
+
+ select_file_entry(w);
+ file_hl_seq = seq;
+ XtCallActionProc(w, "highlight", NULL, NULL, 0);
+}
+
+/* ARGSUSED */
+static void
+act_file_arrow P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ Dimension ch; /* height of clip widget */
+ Position fy; /* (minus) position of list in vport */
+ Position ey; /* position of highlit entry */
+ Dimension eh, eb;
+ int hl_seq;
+
+ if (wl_num == 0)
+ return;
+
+ /* determine whether currently highlighted widget is visible */
+ hl_seq = -1;
+ XtVaGetValues(f2form, XtNy, &fy, NULL);
+ if (file_highlit != NULL) {
+ XtVaGetValues(f2clip, XtNheight, &ch, NULL);
+ XtVaGetValues(f2form, XtNy, &fy, NULL);
+ XtVaGetValues(file_highlit,
+ XtNy, &ey,
+ XtNheight, &eh,
+ XtNborderWidth, &eb,
+ NULL);
+ eh += eb; /* only one border is counted here */
+ ey += fy; /* position relative to viewable area */
+ if (ey + (Position) eh > 0 && ey < (Position) ch) {
+ /* Widget is visible. Find its sequence number. */
+ hl_seq = file_hl_seq;
+ if (hl_seq < 0) {
+ for (hl_seq = 0;; ++hl_seq) {
+ if (hl_seq >= wl_num) {
+ /* this shouldn't happen */
+ file_highlit = NULL;
+ file_hl_seq = -1;
+ return;
+ }
+ if (widget_list[hl_seq] == file_highlit)
+ break;
+ }
+ }
+ if (*num_params > 0 && **params == '-') { /* if up */
+ if (hl_seq == 0) hl_seq = wl_num;
+ --hl_seq;
+ }
+ else { /* down */
+ ++hl_seq;
+ if (hl_seq >= wl_num) hl_seq = 0;
+ }
+ }
+ }
+
+ if (hl_seq < 0) { /* if not visible */
+ if (*num_params > 0 && **params == '-') { /* if up */
+ /* select the lowest visible widget */
+ XtVaGetValues(f2clip, XtNheight, &ch, NULL);
+ hl_seq = ((Position) ch - fy - f2ddist - 1) / file_entry_height;
+ }
+ else { /* down */
+ /* select the highest visible widget */
+ hl_seq = (-fy - f2ddist) / file_entry_height;
+ }
+ if (hl_seq < 0) hl_seq = 0;
+ if (hl_seq >= wl_num) hl_seq = wl_num - 1;
+ }
+
+ /* Select the new widget. */
+ select_by_seq(hl_seq);
+}
+
+/* ARGSUSED */
+static void
+act_file_home P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ if (wl_num != 0)
+ select_by_seq(0);
+}
+
+/* ARGSUSED */
+static void
+act_file_end P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ if (wl_num != 0)
+ select_by_seq(wl_num - 1);
+}
+
+/*
+ * Page-Up, Page-Down, and wheel actions are pure scrolling actions:
+ * they do not change the highlighted entry, even if it scrolls off
+ * the window.
+ */
+
+/* ARGSUSED */
+static void
+act_file_scroll P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ Dimension ch, fh; /* clip and form (child) heights */
+ Position y;
+ Widget sbar;
+ _Xconst char *arg;
+ ptrdiff_t sign;
+ ptrdiff_t dist;
+
+ if (wl_num == 0)
+ return;
+
+ XtVaGetValues(f2clip, XtNheight, &ch, NULL);
+ XtVaGetValues(f2form, XtNheight, &fh, XtNy, &y, NULL);
+ if (fh <= ch)
+ return; /* no scrolling possible */
+
+ sbar = XtNameToWidget(f2vport, "vertical");
+ if (sbar == NULL)
+ return;
+
+ arg = (*num_params != 0 ? *params : "");
+
+ sign = 1;
+ if (*arg == '-') {
+ sign = -1;
+ ++arg;
+ }
+
+ if (*arg == 'w') { /* if wheel action */
+ if (ch <= 16 * file_entry_height)
+ dist = (ch / (4 * file_entry_height) + 1) * file_entry_height;
+ else
+ dist = 5 * file_entry_height;
+ }
+ else {
+ if (ch <= 15 * file_entry_height)
+ dist = ch / 5;
+ else
+ dist = 3 * file_entry_height;
+ dist = ch - dist;
+ if (dist < file_entry_height) dist = file_entry_height;
+ }
+
+ XtCallCallbacks(sbar, XtNscrollProc, (XtPointer) (sign * dist));
+}
+
+static void
+rebuild_suffixes(s)
+ _Xconst char *s;
+{
+ struct suffix *sp;
+ size_t n;
+ _Xconst char *p, *p1;
+ char *q;
+
+ /* First free the old suffixes */
+ for (sp = suffixes; sp < suff_end; ++sp)
+ free((char *) sp->str);
+
+ /* Next count the suffixes */
+ n = 0;
+ p = s;
+ for (;;) {
+ while (*p == ' ' || *p == '\t' || *p == '\n' || *p == ',') ++p;
+ if (*p == '\0')
+ break;
+ ++n;
+ for (;;) {
+ if (*p == '\\' && p[1] != '\0') ++p;
+ else if (*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')
+ break;
+ ++p;
+ if (*p == '\0') break;
+ }
+ }
+
+ /* Allocate space */
+ if (n > suff_max) {
+ if (suff_max != 0) free(suffixes);
+ suff_max = n;
+ suffixes = xmalloc(n * sizeof (*suffixes));
+ }
+
+ /* Fill the space */
+ suff_end = suffixes;
+ p = s;
+ for (;;) {
+ while (*p == ' ' || *p == '\t' || *p == '\n' || *p == ',') ++p;
+ if (*p == '\0')
+ break;
+ n = 0;
+ p1 = p;
+ for (;;) {
+ if (*p1 == '\\' && p1[1] != '\0') ++p1;
+ else if (*p1 == ' ' || *p1 == '\t' || *p1 == '\n' || *p1 == ',')
+ break;
+ ++n;
+ ++p1;
+ if (*p1 == '\0') break;
+ }
+ suff_end->len = n;
+ suff_end->str = q = xmalloc(n);
+ ++suff_end;
+
+ while (p < p1) {
+ if (*p == '\\') ++p;
+ *q++ = *p++;
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+act_file_suffixes P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ char *s;
+
+ XtVaGetValues(f4text, XtNstring, &s, NULL);
+ rebuild_suffixes(s);
+ file_refresh();
+}
+
+static void
+right_justify_widget(w, form_width)
+ Widget w;
+ Dimension form_width;
+{
+ Dimension w1, w2, bw1;
+ Position x;
+
+ XtVaGetValues(w,
+ XtNx, &x,
+ XtNwidth, &w1,
+ XtNborderWidth, &bw1,
+ NULL);
+ w2 = form_width - x - 2 * bw1;
+ if (w2 > w1)
+ XtVaSetValues(w, XtNwidth, w2, NULL);
+}
+
+/* ARGSUSED */
+void
+Act_open_dvi_file P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ if (file_active) {
+ XRaiseWindow(DISP, XtWindow(file_shell));
+ return;
+ }
+
+ if (file_shell == NULL) {
+ Widget form;
+ Widget f1label, f1cmd1, f1cmd2;
+ Widget f3label;
+ Widget f4label;
+ Widget f5chk, f5label;
+ Widget f6ok, f6cancel;
+ static XtTranslations form_xlats, form_xlats2;
+ XtTranslations xlats;
+ int ddist;
+ char *p;
+
+ XtAddActions(file_actions, XtNumber(file_actions));
+ form_xlats = XtParseTranslationTable(
+#ifdef XK_KP_Left
+ "#override \
+<Key>Up:file-arrow(-)\n\
+<Key>Down:file-arrow()\n\
+<Key>Prior:file-scroll(-)\n\
+<Key>Next:file-scroll()\n\
+<Key>Home:file-home()\n\
+<Key>End:file-end()\n\
+<Key>KP_Up:file-arrow(-)\n\
+<Key>KP_Down:file-arrow()\n\
+<Key>KP_Prior:file-scroll(-)\n\
+<Key>KP_Next:file-scroll()\n\
+<Key>KP_Home:file-home()\n\
+<Key>KP_End:file-end()\n\
+<Btn4Down>:file-scroll(-w)\n\
+<Btn5Down>:file-scroll(w)"
+#else /* no XK_KP_Left */
+ "#override \
+<Key>Up:file-arrow(-)\n\
+<Key>Down:file-arrow()\n\
+<Key>Prior:file-scroll(-)\n\
+<Key>Next:file-scroll()\n\
+<Key>Home:file-home()\n\
+<Key>End:file-end()\n\
+<Btn4Down>:file-scroll(-w)\n\
+<Btn5Down>:file-scroll(w)"
+#endif /* no XK_KP_Left */
+ );
+ form_xlats2 = XtParseTranslationTable(
+ "#override \
+<Btn4Down>:file-scroll(-w)\n\
+<Btn5Down>:file-scroll(w)");
+ file_xlats = XtParseTranslationTable(
+ "#replace \
+<Btn1Down>:highlight()file-click()\n\
+<Btn1Down>(2):file-go()\n\
+<Btn4Down>:file-scroll(-w)\n\
+<Btn5Down>:file-scroll(w)");
+
+ /* Set initial directory name. */
+ if (dvi_name != NULL) {
+ p = rindex(dvi_name, '/');
+ if (p == NULL || !get_dir_name(dvi_name, p - dvi_name))
+ (void) xdvi_get_cwd();
+ }
+ else
+ (void) xdvi_get_cwd();
+
+ /* Create shell widget and its child form widget. */
+
+ file_shell = XtVaCreatePopupShell("file", transientShellWidgetClass,
+ top_level,
+ XtNtitle, "Open file",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, top_level,
+ XtNallowShellResize, True,
+ NULL);
+
+ form = XtVaCreateManagedWidget("form", formWidgetClass, file_shell,
+ XtNtranslations, form_xlats,
+ NULL);
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+
+ /* Row 1: Directory stuff. */
+
+ f1label = XtVaCreateManagedWidget("lookin", labelWidgetClass, form,
+ XtNlabel, "Look in:",
+ XtNborderWidth, 0,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ f1text = XtVaCreateManagedWidget("dir", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNuseStringInPlace, True,
+ XtNstring, dirbuf,
+ XtNlength, dirlen,
+ XtNwidth, 250,
+ XtNtranslations, form_xlats,
+ XtNresizable, True,
+ XtNfromHoriz, f1label,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ NULL);
+
+ f1cmd1 = XtVaCreateManagedWidget("up", commandWidgetClass,
+ form,
+ XtNlabel, "Up directory",
+ XtNtranslations, form_xlats2,
+ XtNfromVert, f1text,
+ XtNhorizDistance, ddist + FILEINDENT,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(f1cmd1, XtNcallback, cb_file_up, NULL);
+
+ f1cmd2 = XtVaCreateManagedWidget("home", commandWidgetClass,
+ form,
+ XtNlabel, "Home directory",
+ XtNtranslations, form_xlats2,
+ XtNfromHoriz, f1cmd1,
+ XtNfromVert, f1text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(f1cmd2, XtNcallback, cb_file_home, NULL);
+
+ /* Row 2: The viewport. */
+
+ f2vport = XtVaCreateManagedWidget("vport", viewportWidgetClass,
+ form,
+ XtNwidth, 300,
+ XtNheight, 200,
+ XtNallowHoriz, True,
+ XtNallowVert, True,
+ XtNuseRight, True,
+ XtNuseBottom, True,
+ XtNfromVert, f1cmd1,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ NULL);
+
+ f2clip = XtNameToWidget(f2vport, "clip");
+
+ f2form = XtCreateWidget("vform", formWidgetClass, f2vport,
+ NULL, 0);
+
+ rebuild_suffixes(file_save_suff);
+ file_refresh();
+
+ /* Rows 3 and 4: File name and suffixes. */
+
+ f3label = XtVaCreateManagedWidget("filename", labelWidgetClass,
+ form,
+ XtNlabel, "File name:",
+ XtNborderWidth, 0,
+ XtNfromVert, f2vport,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ f3text = XtVaCreateManagedWidget("filetext", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNtranslations, form_xlats,
+ XtNresizable, True,
+ XtNfromHoriz, f3label,
+ XtNfromVert, f2vport,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ NULL);
+ xlats = XtParseTranslationTable("<Key>Return:file-go()");
+ XtOverrideTranslations(f3text, xlats);
+
+ f4label = XtVaCreateManagedWidget("sufflabel", labelWidgetClass,
+ form,
+ XtNlabel, "Suffixes:",
+ XtNborderWidth, 0,
+ XtNfromVert, f3text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ f4text = XtVaCreateManagedWidget("sufftext", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNstring, file_save_suff,
+ XtNtranslations, form_xlats,
+ XtNresizable, True,
+ XtNfromHoriz, f4label,
+ XtNfromVert, f3text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ NULL);
+ XawTextSetInsertionPoint(f4text, strlen(file_save_suff));
+ xlats = XtParseTranslationTable("<Key>Return:file-suff()");
+ XtOverrideTranslations(f4text, xlats);
+
+ { /* align left edges of asciitext widgets */
+ Dimension w3, w4;
+
+ XtVaGetValues(f3label, XtNwidth, &w3, NULL);
+ XtVaGetValues(f4label, XtNwidth, &w4, NULL);
+ if (w4 > w3)
+ XtVaSetValues(f3text, XtNhorizDistance, ddist + (w4 - w3),
+ NULL);
+ else if (w3 > w4)
+ XtVaSetValues(f4text, XtNhorizDistance, ddist + (w3 - w4),
+ NULL);
+ }
+
+ /* Row 5: Checkbox for showing hidden files. */
+
+ filechk_pm = XCreateBitmapFromData(DISP,
+ mane.win != (Window) 0 ? mane.win : RootWindowOfScreen(SCRN),
+ (_Xconst char *) filechk_bits, filechk_width, filechk_height);
+
+ fileunchk_pm = XCreateBitmapFromData(DISP,
+ mane.win != (Window) 0 ? mane.win : RootWindowOfScreen(SCRN),
+ fileunchk_bits, filechk_width, filechk_height);
+
+ f5chk = XtVaCreateManagedWidget("hidchk", commandWidgetClass, form,
+ XtNbitmap, filehide == '.' ? fileunchk_pm : filechk_pm,
+ XtNtranslations, form_xlats2,
+ XtNfromVert, f4text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(f5chk, XtNcallback, cb_file_hidechk, NULL);
+
+ f5label = XtVaCreateManagedWidget("hidlabel", labelWidgetClass,
+ form,
+ XtNlabel, "Show hidden files and directories",
+ XtNborderWidth, 0,
+ XtNfromHoriz, f5chk,
+ XtNfromVert, f4text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ /* Row 6: Action buttons. */
+
+ f6ok = XtVaCreateManagedWidget("ok", commandWidgetClass, form,
+ XtNlabel, "Open",
+ XtNtranslations, form_xlats2,
+ XtNaccelerators, accels_cr,
+ XtNfromVert, f5chk,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(f6ok, XtNcallback, cb_file_go, NULL);
+ XtInstallAccelerators(form, f6ok);
+ XtInstallAccelerators(f3text, f6ok);
+
+ f6cancel = XtVaCreateManagedWidget("cancel", commandWidgetClass,
+ form,
+ XtNlabel, "Cancel",
+ XtNtranslations, form_xlats2,
+ XtNfromHoriz, f6ok,
+ XtNfromVert, f5chk,
+ XtNleft, XawChainRight,
+ XtNright, XawChainRight,
+ NULL);
+ XtAddCallback(f6cancel, XtNcallback, cb_file_cancel, NULL);
+
+ /* Realize and set destroy callback */
+ XdviXawRealizePopup(file_shell, cb_file_cancel);
+
+ { /* Move various things to the right margin */
+ Dimension fw, w1, w2, bw1, bw2, tw;
+
+ /* get the form width */
+ XtVaGetValues(form, XtNwidth, &fw, NULL);
+ fw -= ddist;
+
+ /* stretch various widgets to the right */
+ right_justify_widget(f1text, fw);
+ XtVaSetValues(f2vport, XtNresizable, True, NULL);
+ right_justify_widget(f2vport, fw);
+ XtVaSetValues(f2vport, XtNresizable, False, NULL);
+ right_justify_widget(f3text, fw);
+ right_justify_widget(f4text, fw);
+
+ /* move the cancel button over */
+ XtVaGetValues(f6ok, XtNwidth, &w1, XtNborderWidth, &bw1, NULL);
+ XtVaGetValues(f6cancel, XtNwidth, &w2, XtNborderWidth, &bw2,
+ NULL);
+ tw = w1 + w2 + 2 * (bw1 + bw2 + ddist);
+ if (tw < fw)
+ XtVaSetValues(f6cancel, XtNhorizDistance, fw - tw + ddist,
+ NULL);
+ }
+
+ reposition = True;
+ }
+ else { /* if widget already exists */
+ file_refresh();
+ }
+
+ if (reposition) {
+ /* Center the popup over the main window */
+ Position x, y;
+ Dimension w1, h1, w2, h2;
+
+ /* Get the size and location of the main window */
+ x = y = 0;
+ w1 = WidthOfScreen(SCRN);
+ h1 = HeightOfScreen(SCRN);
+ if (mane.win != (Window) 0)
+ XtVaGetValues(top_level, XtNx, &x, XtNy, &y,
+ XtNwidth, &w1, XtNheight, &h1, NULL);
+
+ /* Get the size of the popup window */
+ XtVaGetValues(file_shell, XtNwidth, &w2, XtNheight, &h2, NULL);
+
+ /* Move the popup */
+ XtVaSetValues(file_shell, XtNx, x + (w1 - w2) / 2,
+ XtNy, y + (h1 - h2) / 2, NULL);
+
+ reposition = False;
+ }
+
+ XtPopup(file_shell, XtGrabNone);
+ file_active = True;
+}
+
+#else /* MOTIF */
+
+/* ARGSUSED */
+static void
+cb_file_go(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ char *str;
+ XmFileSelectionBoxCallbackStruct *cbs;
+ struct stat buf;
+
+ cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
+ if (!XmStringGetLtoR(cbs->value, XmFONTLIST_DEFAULT_TAG, &str))
+ return; /* shouldn't happen */
+
+ if (stat(str, &buf) != 0) { /* if file does not exist (or error) */
+ warning_popup_long("Error opening file: %s\n%s.", XmDIALOG_ERROR,
+ "OK", NULL, str, strerror(errno));
+ }
+ else {
+ FILE *f;
+
+ /* Normally, dvi files are are not part of the fd-counting
+ provided by xfopen(), since there is only one of them.
+ However, in this case we're opening one before closing the
+ old one, so we have to use xfopen() in this case. */
+ f = xfopen(str, OPEN_MODE);
+ if (f == NULL)
+ warning_popup_long("Error opening file: %s\n%s.",
+ XmDIALOG_ERROR, "OK", NULL, str, strerror(errno));
+ else {
+ ino_t old_inode;
+
+ ++n_files_left;
+ if (dvi_file != NULL)
+ fclose(dvi_file);
+ dvi_file = f;
+
+ if (dvi_name != NULL)
+ free(dvi_name);
+
+ dvi_name = xstrdup(str);
+ dvi_time = buf.st_mtime;
+
+ old_inode = dvi_inode;
+ form_dvi_property(buf.st_ino);
+ titles_are_stale = True;
+
+ if (mane.win != (Window) 0) { /* if not in startup code */
+ if (dvi_inode != old_inode)
+ set_dvi_property();
+
+ goto_page(0, home);
+ }
+ else
+ reposition = True;
+
+ XtPopdown(file_shell);
+ file_active = False;
+
+ ev_flags |= EV_NEWDOC;
+ }
+ }
+
+ XtFree(str);
+}
+
+/* ARGSUSED */
+void
+Act_open_dvi_file P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ Widget dialog;
+
+ if (file_active) {
+ XRaiseWindow(DISP, XtWindow(file_shell));
+ return;
+ }
+
+ if (file_shell == NULL) {
+ static Arg cf_args[] = {
+ {XmNdirectory, (XtArgVal) NULL},
+ {XmNpattern, (XtArgVal) NULL},
+ };
+
+ /* Set initial directory name. */
+ if (dvi_name != NULL) {
+ char *p;
+
+ p = rindex(dvi_name, '/');
+ if (p != NULL) {
+ char c;
+
+ for (;; --p) {
+ if (p <= dvi_name) {
+ ++p;
+ break;
+ }
+ if (p[-1] != '/')
+ break;
+ }
+ c = *p;
+ *p = '\0';
+ cf_args[0].value =
+ (XtArgVal) XmStringCreateLocalized(dvi_name);
+ *p = c;
+ }
+ }
+
+ cf_args[1].value = (XtArgVal) XmStringCreateLocalized("*.dvi");
+
+ dialog = XmCreateFileSelectionDialog(top_level, "file",
+ cf_args, XtNumber(cf_args));
+
+ if (cf_args[0].value != (XtArgVal) NULL) {
+ XmStringFree((XmString) cf_args[0].value);
+ cf_args[0].value = (XtArgVal) NULL;
+ }
+ XmStringFree((XmString) cf_args[1].value);
+
+ XtAddCallback(dialog, XmNokCallback, cb_file_go, NULL);
+ XtAddCallback(dialog, XmNcancelCallback, cb_file_cancel, NULL);
+ XtUnmanageChild(
+ XmFileSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
+
+ file_shell = XtParent(dialog);
+ XmAddWMProtocolCallback(file_shell, XA_WM_DELETE_WINDOW,
+ cb_file_cancel, NULL);
+ XtVaSetValues(file_shell, XmNtitle, "Xdvi: Open Dvi File", NULL);
+
+ XtManageChild(dialog);
+ }
+ else if (reposition) {
+ /* Center the popup over the main window */
+ Position x, y;
+ Dimension w1, h1, w2, h2;
+
+ /* Get the size and location of the main window */
+ x = y = 0;
+ XtVaGetValues(top_level, XtNx, &x, XtNy, &y,
+ XtNwidth, &w1, XtNheight, &h1, NULL);
+
+ /* Get the size of the popup window */
+ XtVaGetValues(file_shell, XtNwidth, &w2, XtNheight, &h2, NULL);
+
+ /* Move the popup */
+ XtVaSetValues(file_shell, XtNx, x + (w1 - w2) / 2,
+ XtNy, y + (h1 - h2) / 2, NULL);
+
+ reposition = False;
+ }
+
+ XtPopup(file_shell, XtGrabNone);
+}
+
+#endif
+
+
+/*
+ * Print popup - pop up a window to allow the user to print page(s)
+ * from the dvi file.
+ */
+
+static Boolean print_active = False; /* if print window is showing */
+static Widget print_shell = NULL; /* shell widget of popup */
+static Widget r1radio1, r1radio2;
+static Widget r2label, r2text;
+static Widget r3label, r3text;
+static Widget r4text;
+static Widget r6radio, r7radio;
+static Widget r7text1, r7text2;
+static Widget r8text;
+static Widget r9prev;
+
+/* &r1radio1 = printer, &r1radio2 = to file */
+static Widget *pr_current_fileradio = &r1radio1;
+
+/* &r6radio = whole file, &r7radio = page range */
+static Widget *pr_current_pageradio = &r6radio;
+
+/* Stuff to save between popups */
+
+static Widget *pr_save_fileradio = &r1radio1;
+static Widget *pr_save_pageradio = &r6radio;
+static _Xconst char *pr_save_cmd = NULL;
+static _Xconst char *pr_save_file = NULL;
+static _Xconst char *pr_save_printer= NULL;
+static _Xconst char *pr_save_xargs = NULL;
+
+/* Things to do with running the dvips process */
+
+static Boolean printlog_active = False; /* if the print log is active */
+static Widget printlog_shell = NULL;
+static Widget printlog_keep;
+
+/* Forward reference */
+
+static void print_precheck();
+
+
+static void
+set_sensitivity(fileradio)
+ Widget *fileradio;
+{
+ Boolean sensitivity;
+
+ if (fileradio == pr_current_fileradio) /* if no change */
+ return;
+
+ pr_current_fileradio = fileradio;
+
+ sensitivity = (fileradio == &r1radio1);
+ XtSetSensitive(r2label, sensitivity);
+ XtSetSensitive(r2text, sensitivity);
+
+ sensitivity ^= (True ^ False);
+ XtSetSensitive(r3label, sensitivity);
+ XtSetSensitive(r3text, sensitivity);
+}
+
+/* ARGSUSED */
+static void
+cb_print_cancel(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ XtPopdown(print_shell);
+ print_active = False;
+
+ if (w == r9prev && !printlog_active) {
+ XtSetSensitive(printlog_keep, False);
+ XtPopup(printlog_shell, XtGrabNone);
+ printlog_active = True;
+ }
+}
+
+/* ARGSUSED */
+static void
+cb_print(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ print_precheck();
+}
+
+#if XAW
+static void print_act_go ARGS((Widget, XEvent *, String *, Cardinal *));
+#endif
+static void printlog_act_close ARGS((Widget, XEvent *, String *, Cardinal *));
+static void printlog_act_keep ARGS((Widget, XEvent *, String *, Cardinal *));
+static void printlog_act_unkeep ARGS((Widget, XEvent *, String *, Cardinal *));
+static void printlog_act_cancel ARGS((Widget, XEvent *, String *, Cardinal *));
+
+static XtActionsRec print_actions[] = {
+#if XAW
+ {"printInternal", print_act_go},
+#endif
+ {"printlogIntClose", printlog_act_close},
+ {"printlogIntKeep", printlog_act_keep},
+ {"printlogIntUnkeep", printlog_act_unkeep},
+ {"printlogIntCancel", printlog_act_cancel},
+};
+
+#if XAW
+
+#ifndef PRINTINDENT
+# define PRINTINDENT 25
+#endif
+
+/* ARGSUSED */
+static void
+cb_print_vs_file(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ Widget *fileradio = XawToggleGetCurrent(r1radio1);
+
+ if (fileradio != NULL)
+ set_sensitivity(fileradio);
+}
+
+/* ARGSUSED */
+static void
+cb_range(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ Widget *pageradio = XawToggleGetCurrent(r6radio);
+
+ if (pageradio != NULL)
+ pr_current_pageradio = pageradio;
+}
+
+/* ARGSUSED */
+void
+range_handle_key(widget, closure, ev, cont)
+ Widget widget;
+ XtPointer closure;
+ XEvent *ev;
+ Boolean *cont;
+{
+ if (pr_current_pageradio != &r7radio)
+ XawToggleSetCurrent(r6radio, &r7radio);
+}
+
+/* ARGSUSED */
+static void
+print_act_go P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ print_precheck();
+}
+
+/* ARGSUSED */
+void
+Act_print P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ static Widget r7label3;
+ static Widget r9cancel;
+ static Dimension sw; /* shell width */
+ static int canceladjust;
+ char *ofstring;
+
+ if (print_active) {
+ XRaiseWindow(DISP, XtWindow(print_shell));
+ return;
+ }
+
+ if (printlog_active) {
+ XRaiseWindow(DISP, XtWindow(printlog_shell));
+ return;
+ }
+
+ if (dvi_file == NULL) {
+ WARN(XmDIALOG_ERROR, "No active dvi file");
+ return;
+ }
+
+ ofstring = (pageno_correct == 1 ? mprintf("of %d", total_pages)
+ : mprintf("of %d to %d", pageno_correct,
+ total_pages + pageno_correct - 1));
+
+ if (print_shell == NULL) {
+ Widget form;
+ Widget r1label;
+ Widget r4label;
+ Widget r5label;
+ Widget r6form;
+ Widget r7form, r7label1, r7label2;
+ Widget r8label;
+ Widget r9ok;
+ XtTranslations xlats, xlats2;
+ XtAccelerators accels2;
+ int ddist;
+
+ XtAddActions(print_actions, XtNumber(print_actions));
+ print_shell = XtVaCreatePopupShell("print",
+ transientShellWidgetClass,
+ top_level,
+ XtNtitle, "Print dvi file",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, top_level,
+ XtNallowShellResize, True,
+ NULL);
+
+ form = XtCreateManagedWidget("form", formWidgetClass, print_shell,
+ NULL, 0);
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+
+ r1label = XtVaCreateManagedWidget("printto", labelWidgetClass, form,
+ XtNlabel, "Print to:",
+ XtNborderWidth, 0,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ xlats = XtParseTranslationTable("<EnterWindow>:highlight(Always)\n\
+<LeaveWindow>:unhighlight()\n\
+<Btn1Down>,<Btn1Up>:set()notify()");
+ r1radio1 = XtVaCreateManagedWidget("toprinter", toggleWidgetClass,
+ form,
+ XtNlabel, "Printer",
+ XtNradioData, &r1radio1,
+ XtNstate, True,
+ XtNtranslations, xlats,
+ XtNfromHoriz, r1label,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(r1radio1, XtNcallback, cb_print_vs_file, NULL);
+
+ r1radio2 = XtVaCreateManagedWidget("tofile", toggleWidgetClass,
+ form,
+ XtNlabel, "File",
+ XtNradioGroup, r1radio1,
+ XtNradioData, &r1radio2,
+ XtNtranslations, xlats,
+ XtNfromHoriz, r1radio1,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(r1radio2, XtNcallback, cb_print_vs_file, NULL);
+
+ /* Rows 2, 3: Print command or file name */
+
+ r2label = XtVaCreateManagedWidget("prncommand", labelWidgetClass,
+ form,
+ XtNlabel, "Print command:",
+ XtNborderWidth, 0,
+ XtNfromVert, r1radio1,
+ XtNhorizDistance, ddist + PRINTINDENT,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ r2text = XtVaCreateManagedWidget("prntext", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, r2label,
+ XtNfromVert, r1radio1,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ xlats2 = XtParseTranslationTable("<Key>Return:printInternal()");
+ XtOverrideTranslations(r2text, xlats2);
+
+ r3label = XtVaCreateManagedWidget("filename", labelWidgetClass,
+ form,
+ XtNlabel, "File name:",
+ XtNsensitive, False,
+ XtNborderWidth, 0,
+ XtNfromVert, r2text,
+ XtNhorizDistance, ddist + PRINTINDENT,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ r3text = XtVaCreateManagedWidget("filetext", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNsensitive, False,
+ XtNfromHoriz, r3label,
+ XtNfromVert, r2text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtOverrideTranslations(r3text, xlats2);
+
+ { /* align left edges of asciitext widgets */
+ Dimension w2, w3;
+
+ XtVaGetValues(r2label, XtNwidth, &w2, NULL);
+ XtVaGetValues(r3label, XtNwidth, &w3, NULL);
+ if (w3 > w2)
+ XtVaSetValues(r2text, XtNhorizDistance, ddist + (w3 - w2),
+ NULL);
+ else if (w2 > w3)
+ XtVaSetValues(r3text, XtNhorizDistance, ddist + (w2 - w3),
+ NULL);
+ }
+
+ /* Row 4: printer name (for dvips) */
+
+ r4label = XtVaCreateManagedWidget("prname", labelWidgetClass,
+ form,
+ XtNlabel, "Printer name (used by dvips):",
+ XtNborderWidth, 0,
+ XtNfromVert, r3text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ r4text = XtVaCreateManagedWidget("prtext", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, r4label,
+ XtNfromVert, r3text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtOverrideTranslations(r4text, xlats2);
+
+ /* Rows 5-7: page selection */
+
+ r5label = XtVaCreateManagedWidget("rangelab", labelWidgetClass,
+ form,
+ XtNlabel, "Print range:",
+ XtNborderWidth, 0,
+ XtNfromVert, r4text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ r6form = XtVaCreateManagedWidget("rangeallform", formWidgetClass,
+ form,
+ XtNdefaultDistance, 0,
+ XtNborderWidth, 0,
+ XtNfromVert, r5label,
+ XtNhorizDistance, ddist + PRINTINDENT,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ accels2 = XtParseAcceleratorTable(
+ "<Btn1Down>,<Btn1Up>:set()notify()");
+ r6radio = XtVaCreateManagedWidget("rangeall", toggleWidgetClass,
+ r6form,
+ XtNlabel, " ",
+ XtNradioData, &r6radio,
+ XtNstate, True,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ NULL);
+ XtAddCallback(r6radio, XtNcallback, cb_range, NULL);
+ XtInstallAccelerators(r6form, r6radio);
+
+ (void) XtVaCreateManagedWidget("rangealllab", labelWidgetClass,
+ r6form,
+ XtNlabel, "All",
+ XtNborderWidth, 0,
+ XtNfromHoriz, r6radio,
+ XtNhorizDistance, ddist,
+ NULL);
+
+ r7form = XtVaCreateManagedWidget("rangefromtoform", formWidgetClass,
+ form,
+ XtNdefaultDistance, 0,
+ XtNborderWidth, 0,
+ XtNresizable, True,
+ XtNfromVert, r6form,
+ XtNhorizDistance, ddist + PRINTINDENT,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ r7radio = XtVaCreateManagedWidget("rangefromto", toggleWidgetClass,
+ r7form,
+ XtNlabel, " ",
+ XtNradioGroup, r6radio,
+ XtNradioData, &r7radio,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ NULL);
+ XtAddCallback(r7radio, XtNcallback, cb_range, NULL);
+ XtInstallAccelerators(r7form, r7radio);
+
+ r7label1 = XtVaCreateManagedWidget("rangefromlab", labelWidgetClass,
+ r7form,
+ XtNlabel, "From",
+ XtNborderWidth, 0,
+ XtNfromHoriz, r7radio,
+ XtNhorizDistance, ddist,
+ NULL);
+
+ r7text1 = XtVaCreateManagedWidget("rangefrom", asciiTextWidgetClass,
+ r7form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, r7label1,
+ XtNhorizDistance, ddist,
+ NULL);
+ XtOverrideTranslations(r7text1, xlats2);
+ XtAddEventHandler(r7text1, KeyPressMask, False,
+ range_handle_key, (XtPointer) NULL);
+
+ r7label2 = XtVaCreateManagedWidget("rangetolab", labelWidgetClass,
+ r7form,
+ XtNlabel, "to",
+ XtNborderWidth, 0,
+ XtNfromHoriz, r7text1,
+ XtNhorizDistance, ddist,
+ NULL);
+
+ r7text2 = XtVaCreateManagedWidget("rangeto", asciiTextWidgetClass,
+ r7form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, r7label2,
+ XtNhorizDistance, ddist,
+ NULL);
+ XtOverrideTranslations(r7text2, xlats2);
+ XtAddEventHandler(r7text2, KeyPressMask, False,
+ range_handle_key, (XtPointer) NULL);
+
+ r7label3 = XtVaCreateManagedWidget("rangeof", labelWidgetClass,
+ r7form,
+ XtNlabel, ofstring,
+ XtNborderWidth, 0,
+ XtNresizable, True,
+ XtNfromHoriz, r7text2,
+ XtNhorizDistance, ddist,
+ NULL);
+
+ /* Row 8: additional dvips args */
+
+ r8label = XtVaCreateManagedWidget("xargsname", labelWidgetClass,
+ form,
+ XtNlabel, "Additional dvips arguments (optional):",
+ XtNborderWidth, 0,
+ XtNfromVert, r7form,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+
+ r8text = XtVaCreateManagedWidget("xargstext", asciiTextWidgetClass,
+ form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNresizable, True,
+ XtNfromVert, r8label,
+ XtNhorizDistance, ddist + PRINTINDENT,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ NULL);
+ XtOverrideTranslations(r8text, xlats2);
+
+ /* Row 9: action buttons */
+
+ r9ok = XtVaCreateManagedWidget("ok", commandWidgetClass, form,
+ XtNlabel, "OK",
+ XtNaccelerators, accels_cr,
+ XtNfromVert, r8text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(r9ok, XtNcallback, cb_print, NULL);
+ XtInstallAccelerators(form, r9ok);
+ XtInstallAccelerators(r2text, r9ok);
+ XtInstallAccelerators(r3text, r9ok);
+
+ r9prev = XtVaCreateManagedWidget("prev", commandWidgetClass, form,
+ XtNlabel, "Show previous log",
+ XtNsensitive, False,
+ XtNfromHoriz, r9ok,
+ XtNfromVert, r8text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ NULL);
+ XtAddCallback(r9prev, XtNcallback, cb_print_cancel, NULL);
+
+ r9cancel = XtVaCreateManagedWidget("cancel", commandWidgetClass,
+ form,
+ XtNlabel, "Cancel",
+ XtNfromHoriz, r9prev,
+ XtNfromVert, r8text,
+ XtNleft, XawChainRight,
+ XtNright, XawChainRight,
+ NULL);
+ XtAddCallback(r9cancel, XtNcallback, cb_print_cancel, NULL);
+
+ /* Realize and set destroy callback */
+ XdviXawRealizePopup(print_shell, cb_print_cancel);
+
+ { /* Center the popup over the main window */
+ Dimension sh; /* sw was defined earlier */
+ Position tx, ty;
+ Dimension tw, th;
+
+ /* Get the size of the popup window */
+ XtVaGetValues(print_shell, XtNwidth, &sw, XtNheight, &sh, NULL);
+
+ /* Center the popup over the main window */
+ XtVaGetValues(top_level, XtNx, &tx, XtNy, &ty,
+ XtNwidth, &tw, XtNheight, &th, NULL);
+ XtVaSetValues(print_shell, XtNx, tx + (tw - sw) / 2,
+ XtNy, ty + (th - sh) / 2, NULL);
+ }
+
+ {
+ /* Set width of dvips-xargs text widget */
+ Dimension b;
+
+ XtVaGetValues(r8text, XtNborderWidth, &b, NULL);
+ XtVaSetValues(r8text,
+ XtNwidth, sw - 2 * (b + ddist) - PRINTINDENT,
+ NULL);
+ }
+
+ { /* Set canceladjust */
+ Dimension cw, cb;
+ Position cx;
+
+ XtVaGetValues(r9cancel, XtNwidth, &cw, XtNborderWidth, &cb,
+ XtNx, &cx, NULL);
+ canceladjust = cx + cw + 2 * cb - ddist;
+ }
+ }
+ else { /* if the window was already created */
+ XawToggleSetCurrent(r1radio1, pr_save_fileradio);
+ set_sensitivity(pr_save_fileradio);
+ XawToggleSetCurrent(r6radio, pr_save_pageradio);
+
+ XtVaSetValues(r7label3, XtNlabel, ofstring, NULL);
+
+ if (pr_save_printer != NULL) {
+ XtVaSetValues(r4text, XtNstring, pr_save_printer, NULL);
+ XawTextSetInsertionPoint(r4text, strlen(pr_save_printer));
+ }
+ else
+ XtVaSetValues(r4text, XtNstring, "", NULL);
+
+ if (pr_save_xargs != NULL) {
+ XtVaSetValues(r8text, XtNstring, pr_save_xargs, NULL);
+ XawTextSetInsertionPoint(r8text, strlen(pr_save_xargs));
+ }
+ else
+ XtVaSetValues(r8text, XtNstring, "", NULL);
+
+ XtVaGetValues(print_shell, XtNwidth, &sw, NULL);
+ }
+
+ free(ofstring);
+ XtVaSetValues(r9prev, XtNhorizDistance, (sw - canceladjust) / 2, NULL);
+ XtVaSetValues(r9cancel, XtNhorizDistance, (sw - canceladjust) / 2,
+ NULL);
+
+ { /* set initial values of print command and file name fields */
+ _Xconst char *s;
+ char s2[3 * sizeof(int) + 1];
+
+ s = pr_save_cmd;
+ if (s == NULL) s = "lpr";
+ /* for some reason two separate XtVaSetValues calls are necessary */
+ XtVaSetValues(r2text, XtNstring, s, NULL);
+ XawTextSetInsertionPoint(r2text, strlen(s));
+
+ if (pr_save_file == NULL) {
+ char *s2;
+ int n;
+
+ s = rindex(dvi_name, '/');
+ if (s == NULL) s = dvi_name;
+ else ++s;
+ n = strlen(s);
+ if (n >= 4 && memicmp(s + n - 4, ".dvi", 4) == 0) n -= 4;
+ s2 = xmalloc(n + 4);
+ memcpy(s2, s, n);
+ memcpy(s2 + n, ".ps", 4);
+ pr_save_file = s2;
+ }
+ s = pr_save_file;
+ XtVaSetValues(r3text, XtNstring, s, NULL);
+ XawTextSetInsertionPoint(r3text, strlen(s));
+
+#if HAVE_VSNPRINTF
+ (void) snprintf(s2, sizeof s2, "%d", current_page + pageno_correct);
+#else
+ (void) sprintf(s2, "%d", current_page + pageno_correct);
+#endif
+ XtVaSetValues(r7text1, XtNstring, s2, NULL);
+ XawTextSetInsertionPoint(r7text1, strlen(s2));
+ XtVaSetValues(r7text2, XtNstring, s2, NULL);
+ XawTextSetInsertionPoint(r7text2, strlen(s2));
+ }
+
+ XtPopup(print_shell, XtGrabNone);
+ print_active = True;
+}
+
+#else /* MOTIF */
+
+#ifndef DDIST
+# define DDIST 4
+#endif
+
+#ifndef DDIST_MAJOR
+# define DDIST_MAJOR 10
+#endif
+
+static Widget f1radiowidget;
+static Widget f2radiowidget;
+static Widget r7label1, r7label2, r7label3;
+
+/* These are needed so that *pr_save_fileradio will work. */
+#define r2radio r1radio1
+#define r3radio r1radio2
+
+/* ARGSUSED */
+static void
+cb_print_vs_file(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (((XmToggleButtonCallbackStruct *) call_data)->set) {
+ if (w != f1radiowidget) {
+ XmToggleButtonGadgetSetState(f1radiowidget, False, False);
+ f1radiowidget = w;
+ set_sensitivity(client_data);
+ XmProcessTraversal(
+ pr_current_fileradio == &r1radio1 ? r2text : r3text,
+ XmTRAVERSE_CURRENT);
+ }
+ }
+ else if (w == f1radiowidget)
+ XmToggleButtonGadgetSetState(w, True, False);
+}
+
+
+static void
+range_set_sensitivity(pageradio)
+ Widget *pageradio;
+{
+ Boolean sensitivity;
+
+ if (pageradio == pr_current_pageradio) /* if no change */
+ return;
+
+ pr_current_pageradio = pageradio;
+ sensitivity = (pageradio == &r7radio);
+
+ XtSetSensitive(r7label1, sensitivity);
+ XtSetSensitive(r7text1, sensitivity);
+ XtSetSensitive(r7label2, sensitivity);
+ XtSetSensitive(r7text2, sensitivity);
+ XtSetSensitive(r7label3, sensitivity);
+}
+
+/* ARGSUSED */
+static void
+cb_range(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (((XmToggleButtonCallbackStruct *) call_data)->set) {
+ if (w != f2radiowidget) {
+ XmToggleButtonGadgetSetState(f2radiowidget, False, False);
+ f2radiowidget = w;
+ range_set_sensitivity((Widget *) client_data);
+ if (pr_current_pageradio == &r7radio)
+ XmProcessTraversal(r7text1, XmTRAVERSE_CURRENT);
+ }
+ }
+ else if (w == f2radiowidget)
+ XmToggleButtonGadgetSetState(w, True, False);
+}
+
+/* ARGSUSED */
+void
+Act_print P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ char *ofstring;
+
+ if (print_active) {
+ XRaiseWindow(DISP, XtWindow(print_shell));
+ return;
+ }
+
+ if (printlog_active) {
+ XRaiseWindow(DISP, XtWindow(printlog_shell));
+ return;
+ }
+
+ if (dvi_file == NULL) {
+ WARN(XmDIALOG_ERROR, "No active dvi file");
+ return;
+ }
+
+ ofstring = (pageno_correct == 1 ? mprintf("of %d", total_pages)
+ : mprintf("of %d to %d", pageno_correct,
+ total_pages + pageno_correct - 1));
+
+ if (print_shell == NULL) {
+ Widget form;
+ Widget frame1, f1label, f1child;
+ Widget r4label;
+ Widget r8label;
+ Widget frame2, f2label, f2child;
+ Widget r9ok, r9cancel;
+ XmString str;
+
+ XtAddActions(print_actions, XtNumber(print_actions));
+ print_shell = XtVaCreatePopupShell("print",
+ xmDialogShellWidgetClass, top_level,
+ XmNtitle, "Print dvi file",
+ XmNallowShellResize, True,
+ XmNdeleteResponse, XmDO_NOTHING,
+ NULL);
+ XmAddWMProtocolCallback(print_shell, XA_WM_DELETE_WINDOW,
+ cb_print_cancel, NULL);
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass, print_shell,
+ XmNhorizontalSpacing, DDIST_MAJOR,
+ XmNverticalSpacing, DDIST_MAJOR,
+ XmNautoUnmanage, False,
+ NULL);
+
+ /* First frame (rows 1-3): print to printer or file */
+
+ frame1 = XtVaCreateWidget("printtoframe", xmFrameWidgetClass, form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ str = XmStringCreateLocalized("Print To");
+ f1label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame1,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f1child = XtVaCreateWidget("form", xmFormWidgetClass, frame1,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ NULL);
+
+ str = XmStringCreateLocalized("Printer");
+ f1radiowidget = r2radio = XtVaCreateManagedWidget("toprinter",
+ xmToggleButtonGadgetClass, f1child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNset, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r2radio, XmNvalueChangedCallback, cb_print_vs_file,
+ &r1radio1);
+
+ str = XmStringCreateLocalized("Print command:");
+ r2label = XtVaCreateManagedWidget("prncommand", xmLabelGadgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r2radio,
+ NULL);
+ XmStringFree(str);
+
+ r2text = XtVaCreateManagedWidget("prntext", xmTextFieldWidgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r2label,
+ NULL);
+ XtAddCallback(r2text, XmNactivateCallback, cb_print, NULL);
+
+ { /* straighten the row of widgets */
+ Dimension h1, h2;
+
+ XtVaGetValues(r2text, XmNheight, &h2, NULL);
+ XtVaGetValues(r2radio, XmNheight, &h1, NULL);
+ XtVaSetValues(r2radio, XmNtopOffset, (h2 - h1) / 2, NULL);
+ XtVaGetValues(r2label, XmNheight, &h1, NULL);
+ XtVaSetValues(r2label, XmNtopOffset, (h2 - h1) / 2, NULL);
+ }
+
+ str = XmStringCreateLocalized("File");
+ r3radio = XtVaCreateManagedWidget("tofile",
+ xmToggleButtonGadgetClass, f1child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r2text,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r3radio, XmNvalueChangedCallback, cb_print_vs_file,
+ &r1radio2);
+
+ str = XmStringCreateLocalized("File name:");
+ r3label = XtVaCreateManagedWidget("filename", xmLabelGadgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r2text,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r3radio,
+ NULL);
+ XmStringFree(str);
+
+ r3text = XtVaCreateManagedWidget("prntext", xmTextFieldWidgetClass,
+ f1child,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r2text,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r3label,
+ NULL);
+ XtAddCallback(r3text, XmNactivateCallback, cb_print, NULL);
+
+ { /* straighten the row of widgets */
+ Dimension h1, h2;
+
+ XtVaGetValues(r3text, XmNheight, &h2, NULL);
+ XtVaGetValues(r3radio, XmNheight, &h1, NULL);
+ XtVaSetValues(r3radio, XmNtopOffset, DDIST + (h2 - h1) / 2,
+ NULL);
+ XtVaGetValues(r3label, XmNheight, &h1, NULL);
+ XtVaSetValues(r3label, XmNtopOffset, DDIST + (h2 - h1) / 2,
+ NULL);
+ }
+
+ { /* align left edges of text widgets */
+ Dimension w2r, w3r, w2l, w3l;
+
+ XtVaGetValues(r2radio, XmNwidth, &w2r, NULL);
+ XtVaGetValues(r3radio, XmNwidth, &w3r, NULL);
+ XtVaGetValues(r2label, XmNwidth, &w2l, NULL);
+ XtVaGetValues(r3label, XmNwidth, &w3l, NULL);
+ if (w2l < w3l || w2r < w3r) {
+ Dimension offset;
+
+ offset = DDIST;
+ if (w2l < w3l) offset += w3l - w2l;
+ if (w2r < w3r) offset += w3r - w2r;
+ XtVaSetValues(r2label, XmNleftOffset, offset, NULL);
+ }
+ if (w2l > w3l || w2r > w3r) {
+ Dimension offset;
+
+ offset = DDIST;
+ if (w2l > w3l) offset += w2l - w3l;
+ if (w2r > w3r) offset += w2r - w3r;
+ XtVaSetValues(r3label, XmNleftOffset, offset, NULL);
+ }
+ }
+
+ XtManageChild(f1child);
+ XtManageChild(frame1);
+
+ /* Row 4: printer name (for dvips) */
+
+ str = XmStringCreateLocalized("Printer name (used by dvips):");
+ r4label = XtVaCreateManagedWidget("prname", xmLabelGadgetClass,
+ form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame1,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ r4text = XtVaCreateManagedWidget("prtext", xmTextFieldWidgetClass,
+ form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame1,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r4label,
+ XmNcolumns, 5,
+ NULL);
+ XtAddCallback(r4text, XmNactivateCallback, cb_print, NULL);
+
+ { /* straighten the row of widgets */
+ Dimension h1, h2;
+
+ XtVaGetValues(r4text, XmNheight, &h2, NULL);
+ XtVaGetValues(r4label, XmNheight, &h1, NULL);
+ XtVaSetValues(r4label,
+ XmNtopOffset, DDIST_MAJOR + (h2 - h1) / 2,
+ NULL);
+ }
+
+ /* Row 8 (row 4.5 for Motif): additional dvips args */
+
+ str = XmStringCreateLocalized(
+ "Additional dvips arguments (optional):");
+ r8label = XtVaCreateManagedWidget("xargsname", xmLabelGadgetClass,
+ form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r4text,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ r8text = XtVaCreateManagedWidget("xargstext",
+ xmTextFieldWidgetClass, form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r8label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, DDIST + DDIST_MAJOR,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, DDIST + DDIST_MAJOR,
+ NULL);
+ XtAddCallback(r8text, XmNactivateCallback, cb_print, NULL);
+
+ /* Second frame (rows 5-7): page selection */
+
+ frame2 = XtVaCreateWidget("printtoframe", xmFrameWidgetClass, form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r8text,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ str = XmStringCreateLocalized("Page Selection");
+ f2label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame2,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f2child = XtVaCreateWidget("form", xmFormWidgetClass, frame2,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ NULL);
+
+ str = XmStringCreateLocalized("All");
+ f2radiowidget = r6radio = XtVaCreateManagedWidget("all",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNset, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r6radio, XmNvalueChangedCallback, cb_range,
+ &r6radio);
+
+ str = XmStringCreateLocalized("Range:");
+ r7radio = XtVaCreateManagedWidget("range",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r6radio,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r7radio, XmNvalueChangedCallback, cb_range,
+ &r7radio);
+
+ str = XmStringCreateLocalized("From");
+ r7label1 = XtVaCreateManagedWidget("from", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r6radio,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r7radio,
+ NULL);
+ XmStringFree(str);
+
+ r7text1 = XtVaCreateManagedWidget("frompage",
+ xmTextFieldWidgetClass, f2child,
+ XmNcolumns, 5,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r6radio,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r7label1,
+ NULL);
+ XtAddCallback(r7text1, XmNactivateCallback, cb_print, NULL);
+
+ str = XmStringCreateLocalized("to");
+ r7label2 = XtVaCreateManagedWidget("to", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r6radio,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r7text1,
+ NULL);
+ XmStringFree(str);
+
+ r7text2 = XtVaCreateManagedWidget("topage", xmTextFieldWidgetClass,
+ f2child,
+ XmNcolumns, 5,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r6radio,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r7label2,
+ NULL);
+ XtAddCallback(r7text2, XmNactivateCallback, cb_print, NULL);
+
+ str = XmStringCreateLocalized(ofstring);
+ r7label3 = XtVaCreateManagedWidget("of", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, r6radio,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r7text2,
+ NULL);
+ XmStringFree(str);
+
+ { /* straighten the row of widgets */
+ Dimension h1, h2;
+
+ XtVaGetValues(r7text1, XmNheight, &h2, NULL);
+ XtVaGetValues(r7radio, XmNheight, &h1, NULL);
+ XtVaSetValues(r7radio, XmNtopOffset, DDIST + (h2 - h1) / 2,
+ NULL);
+ XtVaGetValues(r7label1, XmNheight, &h1, NULL);
+ XtVaSetValues(r7label1, XmNtopOffset, DDIST + (h2 - h1) / 2,
+ NULL);
+ XtVaSetValues(r7label2, XmNtopOffset, DDIST + (h2 - h1) / 2,
+ NULL);
+ XtVaSetValues(r7label3, XmNtopOffset, DDIST + (h2 - h1) / 2,
+ NULL);
+ }
+
+ XtManageChild(f2child);
+ XtManageChild(frame2);
+
+ str = XmStringCreateLocalized("OK");
+ r9ok = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass,
+ form,
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame2,
+ XmNtopOffset, DDIST_MAJOR + DDIST,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r9ok, XmNactivateCallback, cb_print, NULL);
+ XtOverrideTranslations(r9ok, XtParseTranslationTable(
+ "<Key>Return:ArmAndActivate()"));
+ XmProcessTraversal(r9ok, XmTRAVERSE_CURRENT);
+
+ str = XmStringCreateLocalized("Show previous log");
+ r9prev = XtVaCreateManagedWidget("prev",
+ xmPushButtonWidgetClass, form,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame2,
+ XmNtopOffset, DDIST_MAJOR + DDIST,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, r9ok,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r9prev, XmNactivateCallback, cb_print_cancel, NULL);
+
+ str = XmStringCreateLocalized("Cancel");
+ r9cancel = XtVaCreateManagedWidget("cancel",
+ xmPushButtonWidgetClass, form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame2,
+ XmNtopOffset, DDIST_MAJOR + DDIST,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(r9cancel, XmNactivateCallback, cb_print_cancel, NULL);
+
+ { /* straighten the row of widgets */
+ Dimension h1, h2;
+
+ XtVaGetValues(r9ok, XmNheight, &h1, NULL);
+ XtVaGetValues(r9prev, XmNheight, &h2, NULL);
+ XtVaSetValues(r9prev,
+ XmNtopOffset, DDIST_MAJOR + DDIST + (h1 - h2) / 2, NULL);
+ XtVaGetValues(r9cancel, XmNheight, &h2, NULL);
+ XtVaSetValues(r9cancel,
+ XmNtopOffset, DDIST_MAJOR + DDIST + (h1 - h2) / 2, NULL);
+ }
+
+ XtManageChild(form);
+
+ { /* center middle button in bottom row */
+ Dimension w, b;
+ Position x1, x3;
+
+ XtVaGetValues(r9ok, XmNx, &x1, XmNwidth, &w, NULL);
+ x1 += w;
+ XtVaGetValues(r9prev, XmNwidth, &w, NULL);
+ XtVaGetValues(r9cancel, XmNx, &x3, NULL);
+ XtVaSetValues(r9prev, XmNleftOffset, (x3 - x1 - w) / 2, NULL);
+ }
+ }
+ else { /* if the window was already created */
+ XmString str;
+
+ if (pr_save_fileradio != pr_current_fileradio)
+ XmToggleButtonGadgetSetState(*pr_save_fileradio, True, True);
+ if (pr_save_pageradio != pr_current_pageradio)
+ XmToggleButtonGadgetSetState(*pr_save_pageradio, True, True);
+
+ str = XmStringCreateLocalized(ofstring);
+ XtVaSetValues(r7label3, XmNlabelString, str, NULL);
+ XmStringFree(str);
+
+ if (pr_save_printer != NULL) {
+ XtVaSetValues(r4text, XmNvalue, pr_save_printer,
+ XmNcursorPosition, strlen(pr_save_printer), NULL);
+ }
+ else
+ XtVaSetValues(r4text, XmNvalue, "", NULL);
+
+ if (pr_save_xargs != NULL) {
+ XtVaSetValues(r8text, XmNvalue, pr_save_xargs,
+ XmNcursorPosition, strlen(pr_save_xargs), NULL);
+ }
+ else
+ XtVaSetValues(r8text, XmNvalue, "", NULL);
+ }
+
+ free(ofstring);
+
+ { /* set initial values of print command and file name fields */
+ _Xconst char *s;
+ char s2[3 * sizeof(int) + 1];
+
+ s = pr_save_cmd;
+ if (s == NULL) s = "lpr";
+ XtVaSetValues(r2text, XmNvalue, s, XmNcursorPosition, strlen(s),
+ NULL);
+
+ if (pr_save_file == NULL) {
+ char *s2;
+ int n;
+
+ s = rindex(dvi_name, '/');
+ if (s == NULL) s = dvi_name;
+ else ++s;
+ n = strlen(s);
+ if (n >= 4 && memicmp(s + n - 4, ".dvi", 4) == 0) n -= 4;
+ s2 = xmalloc(n + 4);
+ memcpy(s2, s, n);
+ memcpy(s2 + n, ".ps", 4);
+ pr_save_file = s2;
+ }
+ s = pr_save_file;
+ XtVaSetValues(r3text, XmNvalue, s, XmNcursorPosition, strlen(s),
+ NULL);
+
+#if HAVE_VSNPRINTF
+ (void) snprintf(s2, sizeof s2, "%d", current_page + pageno_correct);
+#else
+ (void) sprintf(s2, "%d", current_page + pageno_correct);
+#endif
+ XtVaSetValues(r7text1, XmNvalue, s2, XmNcursorPosition, strlen(s2),
+ NULL);
+ XtVaSetValues(r7text2, XmNvalue, s2, XmNcursorPosition, strlen(s2),
+ NULL);
+ }
+
+ XtPopup(print_shell, XtGrabNone);
+ print_active = True;
+}
+
+#endif /* MOTIF */
+
+
+/*
+ * The actual printing
+ */
+
+static int pageno1, pageno2; /* page range */
+static Widget print_confirm = NULL;
+static Widget printlog_text;
+static Widget printlog_close;
+static Widget printlog_cancel;
+
+#if XAW
+static XawTextPosition printlog_length;
+#else /* MOTIF */
+static XmTextPosition printlog_length;
+#endif
+
+static void dvips_ended ARGS((int));
+static struct xchild print_child = {NULL, 0, True, dvips_ended};
+
+static void read_from_dvips ARGS((void));
+static struct xio print_xio = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_dvips, NULL};
+
+static void dvips_alarm ARGS((struct xtimer *));
+static struct xtimer dvips_timer = TIMER_INIT(dvips_alarm);
+static int dvips_status;
+#define DVIPS_STAT_NONE 0
+#define DVIPS_STAT_RUN 1
+#define DVIPS_STAT_WAIT 2
+static int dvips_sig; /* SIGINT or SIGKILL */
+
+/* Forward reference */
+
+static void print_do_it();
+
+static int
+getpageno(w)
+ Widget w;
+{
+ char *s, *p;
+
+#if XAW
+ XtVaGetValues(w, XtNstring, &s, NULL);
+#else /* MOTIF */
+ s = XmTextFieldGetString(w);
+#endif
+ p = s;
+ if (*p == '-') ++p;
+ if (!isdigit(*p)) return 0;
+ do ++p; while (isdigit(*p));
+ if (*p != '\0') return 0;
+
+#if XAW
+ return atoi(s) - pageno_correct + 1;
+#else /* MOTIF */
+ {
+ int i = atoi(s) - pageno_correct + 1;
+
+ XtFree(s);
+ return i;
+ }
+#endif
+}
+
+/* ARGSUSED */
+static void
+cb_print_confirm(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ XtDestroyWidget(print_confirm);
+ print_confirm = NULL;
+
+ if (client_data != NULL)
+ print_do_it();
+}
+
+static void
+print_precheck()
+{
+ char *dest;
+ struct stat statbuf;
+
+ /* Check for active confirm box */
+ if (print_confirm != NULL) {
+ XRaiseWindow(DISP, XtWindow(print_confirm));
+ return;
+ }
+
+ /* Validate page range (if given) */
+ if (pr_current_pageradio == &r7radio) { /* if page range selected */
+ pageno1 = getpageno(r7text1);
+ pageno2 = getpageno(r7text2);
+ if (pageno1 <= 0 || pageno1 > pageno2 || pageno2 > total_pages) {
+ WARN(XmDIALOG_ERROR, "Invalid page range");
+ return;
+ }
+ }
+
+ /* Pop down window */
+ cb_print_cancel(NULL, NULL, NULL);
+
+ /* Check for whether to clobber existing file */
+ if (pr_current_fileradio == &r1radio2) { /* if print to file */
+#if XAW
+ XtVaGetValues(r3text, XtNstring, &dest, NULL);
+#else /* MOTIF */
+ dest = XmTextFieldGetString(r3text);
+#endif
+ if (stat(dest, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) {
+ char *msg;
+
+ msg = mprintf("Overwrite existing file %s?", dest);
+ print_confirm = confirm_popup(msg, "OK", cb_print_confirm,
+ (XtPointer) print_shell, NULL);
+ free(msg);
+#if MOTIF
+ XtFree(dest);
+#endif
+ return;
+ }
+#if MOTIF
+ XtFree(dest);
+#endif
+ }
+
+ print_do_it();
+}
+
+
+static void cb_dvips_close ARGS((Widget, XtPointer, XtPointer));
+static void cb_dvips_keep ARGS((Widget, XtPointer, XtPointer));
+static void cb_dvips_cancel ARGS((Widget, XtPointer, XtPointer));
+static void cb_dvips_delete ARGS((Widget, XtPointer, XtPointer));
+static void printlog_append ARGS((_Xconst char *, int));
+
+struct dvips_env {
+ _Xconst char *envname;
+ _Xconst char *en1, *en2;
+ _Xconst char *envval;
+};
+
+static struct dvips_env dvips_envs[] = {
+ {NULL, "TEXPICTS", "TEXINPUTS", NULL},
+ {NULL, "TEXPSHEADERS", "PSHEADERS", NULL}};
+
+static void
+print_do_it()
+{
+ _Xconst char *dest;
+ _Xconst char *prn;
+ _Xconst char *xargs;
+ FILE *f;
+ unsigned int len; /* length of command line */
+ unsigned int argc;
+ char **argv;
+ char **argnext;
+ int print_io[2];
+ char *p, **pp;
+ _Xconst char *q;
+
+ if (dvi_file == NULL) {
+ WARN(XmDIALOG_ERROR, "No active dvi file");
+ return;
+ }
+
+ /* Save state of window for next time */
+ pr_save_fileradio = pr_current_fileradio;
+ pr_save_pageradio = pr_current_pageradio;
+
+#if XAW
+
+ if (pr_save_fileradio == &r1radio1) { /* if print to printer */
+ if (pr_save_cmd != NULL)
+ free((char *) pr_save_cmd);
+ XtVaGetValues(r2text, XtNstring, &dest, NULL);
+ dest = pr_save_cmd = xstrdup(dest);
+ }
+ else { /* if print to file */
+ if (pr_save_file != NULL)
+ free((char *) pr_save_file);
+ XtVaGetValues(r3text, XtNstring, &dest, NULL);
+ dest = pr_save_file = xstrdup(dest);
+ }
+
+ XtVaGetValues(r4text, XtNstring, &prn, NULL);
+ if (pr_save_printer != NULL)
+ free((char *) pr_save_printer);
+ if (*prn != '\0')
+ prn = pr_save_printer = xstrdup(prn);
+ else
+ prn = pr_save_printer = NULL;
+
+ XtVaGetValues(r8text, XtNstring, &xargs, NULL);
+ if (pr_save_xargs != NULL)
+ free((char *) pr_save_xargs);
+ if (*xargs != '\0')
+ xargs = pr_save_xargs = xstrdup(xargs);
+ else
+ xargs = pr_save_xargs = NULL;
+
+#else /* MOTIF */
+
+ if (pr_save_fileradio == &r1radio1) { /* if print to printer */
+ if (pr_save_cmd != NULL)
+ XtFree((char *) pr_save_cmd);
+ dest = pr_save_cmd = XmTextFieldGetString(r2text);
+ }
+ else { /* if print to file */
+ if (pr_save_file != NULL)
+ XtFree((char *) pr_save_file);
+ dest = pr_save_file = XmTextFieldGetString(r3text);
+ }
+
+ if (pr_save_printer != NULL)
+ XtFree((char *) pr_save_printer);
+ prn = XmTextFieldGetString(r4text);
+ if (*prn == '\0') {
+ XtFree((char *) prn);
+ prn = NULL;
+ }
+ pr_save_printer = prn;
+
+ if (pr_save_xargs != NULL)
+ XtFree((char *) pr_save_xargs);
+ xargs = XmTextFieldGetString(r8text);
+ if (*xargs == '\0') {
+ XtFree((char *) xargs);
+ xargs = NULL;
+ }
+ pr_save_xargs = xargs;
+
+#endif
+
+ /* Open file for writing (if necessary) */
+ if (pr_save_fileradio == &r1radio2) { /* if print to file */
+ f = xfopen(dest, "w");
+ if (f == NULL) {
+ WARN2(XmDIALOG_ERROR, "Error opening file: %s\n%s.", dest,
+ strerror(errno));
+ return;
+ }
+ }
+
+#if XAW
+ /* Create popup window */
+ if (printlog_shell == NULL) {
+ Widget form;
+ int ddist;
+ Dimension w0, w1, w2, w3, b;
+
+ XtSetSensitive(r9prev, True);
+ printlog_shell = XtVaCreatePopupShell("printlog",
+ transientShellWidgetClass, top_level,
+ XtNtitle, "Xdvi print process",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, top_level,
+ NULL);
+ form = XtCreateManagedWidget("form", formWidgetClass,
+ printlog_shell, NULL, 0);
+ printlog_text = XtVaCreateManagedWidget("text",
+ asciiTextWidgetClass, form,
+ XtNstring, "",
+ XtNdataCompression, False,
+ XtNeditType, XawtextAppend,
+ XtNscrollHorizontal, XawtextScrollAlways,
+ XtNscrollVertical, XawtextScrollAlways,
+ XtNwidth, 600,
+ XtNheight, 400,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtOverrideTranslations(printlog_text, XtParseTranslationTable(
+ "<Key>Return:printlogIntClose()\n\
+^<Key>c:printlogIntCancel()\n\
+^<Key>s:printlogIntKeep()\n\
+^<Key>q:printlogIntUnkeep()"));
+
+ printlog_close = XtVaCreateManagedWidget("close",
+ commandWidgetClass, form,
+ XtNlabel, "Close window",
+ XtNsensitive, False,
+ XtNfromVert, printlog_text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_close, XtNcallback, cb_dvips_close, NULL);
+
+ printlog_keep = XtVaCreateManagedWidget("keep", toggleWidgetClass,
+ form,
+ XtNlabel, "Keep window open",
+ XtNfromVert, printlog_text,
+ XtNfromHoriz, printlog_close,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_keep, XtNcallback, cb_dvips_keep, NULL);
+
+ printlog_cancel = XtVaCreateManagedWidget("cancel",
+ commandWidgetClass, form,
+ XtNlabel, "Cancel",
+ XtNfromVert, printlog_text,
+ XtNfromHoriz, printlog_keep,
+ XtNleft, XawChainRight,
+ XtNright, XawChainRight,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_cancel, XtNcallback, cb_dvips_cancel, NULL);
+
+ /* Move the buttons to the right spots */
+ XtVaGetValues(printlog_text, XtNwidth, &w0, NULL);
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+ XtVaGetValues(printlog_close, XtNwidth, &w1, XtNborderWidth, &b,
+ NULL);
+ w1 += 2 * b + ddist;
+ XtVaGetValues(printlog_keep, XtNwidth, &w2, XtNborderWidth, &b,
+ NULL);
+ w2 += 2 * b;
+ if (w0 > w2 + 2 * w1) {
+ XtVaSetValues(printlog_keep,
+ XtNhorizDistance, (w0 - w2) / 2 - w1, NULL);
+ w1 += (w0 - w2) / 2 - w1 - ddist;
+ }
+ w1 += w2;
+ XtVaGetValues(printlog_cancel, XtNwidth, &w3, XtNborderWidth, &b,
+ NULL);
+ w3 += 2 * b;
+ if (w1 + ddist + w3 < w0)
+ XtVaSetValues(printlog_cancel, XtNhorizDistance, w0 - w1 - w3,
+ NULL);
+
+ XdviXawRealizePopup(printlog_shell, cb_dvips_delete);
+ }
+ else {
+ XtVaSetValues(printlog_text, XtNstring, "", NULL);
+ XtSetSensitive(printlog_close, False);
+ XtSetSensitive(printlog_keep, True);
+ XtSetSensitive(printlog_cancel, True);
+ }
+
+#else /* MOTIF */
+
+ /* Create popup window */
+ if (printlog_shell == NULL) {
+ Widget form;
+ XmString str;
+
+ /* Under Motif 2.x (2.1.0 and 2.2.2 at least), XmNeditMode must be
+ set early in order to have an effect. */
+ static Arg args[] = {
+ {XmNeditable, False},
+ {XmNrows, 24},
+ {XmNcolumns, 80},
+ {XmNeditMode, (XtArgVal) XmMULTI_LINE_EDIT},
+ };
+
+ XtSetSensitive(r9prev, True);
+ printlog_shell = XtVaCreatePopupShell("printlog",
+ xmDialogShellWidgetClass, top_level,
+ XmNtitle, "Xdvi print process",
+ XmNdeleteResponse, XmDO_NOTHING,
+ NULL);
+ XmAddWMProtocolCallback(printlog_shell, XA_WM_DELETE_WINDOW,
+ cb_dvips_delete, NULL);
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass, printlog_shell,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNautoUnmanage, False,
+ NULL);
+
+ printlog_text = XmCreateScrolledText(form, "text",
+ args, XtNumber(args));
+ XtVaSetValues(XtParent(printlog_text),
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ XtOverrideTranslations(printlog_text, XtParseTranslationTable(
+ "<Key>Return:printlogIntClose()\n\
+^<Key>c:printlogIntCancel()\n\
+^<Key>s:printlogIntKeep()\n\
+^<Key>q:printlogIntUnkeep()"));
+ XtManageChild(printlog_text);
+
+ str = XmStringCreateLocalized(
+ "Keep window open after dvips finishes");
+ printlog_keep = XtVaCreateManagedWidget("keep",
+ xmToggleButtonGadgetClass, form,
+ XmNlabelString, str,
+ XmNnavigationType, XmTAB_GROUP,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(printlog_text),
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_keep, XmNvalueChangedCallback, cb_dvips_keep,
+ NULL);
+
+ str = XmStringCreateLocalized("Close window");
+ printlog_close = XtVaCreateManagedWidget("close",
+ xmPushButtonWidgetClass, form,
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNsensitive, False,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, printlog_keep,
+ XmNtopOffset, DDIST,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_close, XmNactivateCallback, cb_dvips_close,
+ NULL);
+
+ str = XmStringCreateLocalized("Cancel");
+ printlog_cancel = XtVaCreateManagedWidget("cancel",
+ xmPushButtonWidgetClass, form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, printlog_keep,
+ XmNtopOffset, DDIST,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_cancel, XmNactivateCallback, cb_dvips_cancel,
+ NULL);
+
+ { /* straighten the row of widgets */
+ Dimension h1, h2;
+
+ XtVaGetValues(printlog_close, XmNheight, &h1, NULL);
+ XtVaGetValues(printlog_cancel, XmNheight, &h2, NULL);
+ XtVaSetValues(printlog_cancel,
+ XmNtopOffset, DDIST + (h1 - h2) / 2, NULL);
+ XtVaSetValues(printlog_cancel,
+ XmNrightOffset, DDIST + (h1 - h2) / 2, NULL);
+ }
+
+ XtManageChild(form);
+ XmProcessTraversal(printlog_text, XmTRAVERSE_CURRENT);
+ }
+ else {
+ XmTextSetString(printlog_text, "");
+ XtSetSensitive(printlog_close, False);
+ XtSetSensitive(printlog_keep, True);
+ XtSetSensitive(printlog_cancel, True);
+ }
+
+#endif
+
+ /* Compute length of dvips command line */
+ /* dvips [-Pps] -f [-o!command] [-p=n -lm] [xargs] */
+ argc = 3;
+ len = strlen(resource.dvips_path) + 4;
+ /* "dvips -f\0" */
+ if (prn != NULL) argc = 4, len += strlen(prn) + 3;
+ if (pr_save_fileradio == &r1radio1) ++argc, len += strlen(dest) + 4;
+ if (pr_save_pageradio == &r7radio) {
+ argc += 2;
+ len += uintlen(pageno1) + uintlen(pageno2) + 7;
+ }
+ if (pr_save_xargs != NULL) {
+ _Xconst char *q = pr_save_xargs;
+
+ len += strlen(pr_save_xargs);
+ for (;;) {
+ while (*q == ' ' || *q == '\t') ++q, --len;
+ if (*q == '\0') break;
+ ++argc;
+ ++len;
+ while (*q != '\0' && *q != ' ' && *q != '\t') ++q;
+ }
+ }
+
+ /* Compute actual dvips command line */
+ argv = xmalloc(argc * sizeof(char *));
+ p = argv[0] = xmalloc(len + 1);
+ argnext = argv + 1;
+ p += strlen(strcpy(p, resource.dvips_path));
+ *p++ = ' ';
+ *argnext++ = p;
+
+ if (prn != NULL) {
+ sprintf(p, "-P%s ", prn);
+ p += strlen(p);
+ *argnext++ = p;
+ }
+
+ *p++ = '-';
+ *p++ = 'f';
+ *p++ = ' ';
+ *argnext++ = p;
+
+ if (pr_save_fileradio == &r1radio1) {
+ sprintf(p, "-o!%s ", dest);
+ p += strlen(p);
+ *argnext++ = p;
+ }
+
+ if (pr_save_pageradio == &r7radio) {
+ sprintf(p, "-p=%u ", pageno1);
+ p += strlen(p);
+ *argnext++ = p;
+ sprintf(p, "-l%u ", pageno2);
+ p += strlen(p);
+ *argnext++ = p;
+ }
+
+ if (pr_save_xargs != NULL) {
+ _Xconst char *q = pr_save_xargs;
+
+ for (;;) {
+ while (*q == ' ' || *q == '\t') ++q;
+ if (*q == '\0') break;
+ while (*q != '\0' && *q != ' ' && *q != '\t') *p++ = *q++;
+ *p++ = ' ';
+ *argnext++ = p;
+ }
+ }
+
+#if 0
+ if (argnext - argv != argc)
+ oops("dvips command count mismatch: %u != %u", argc,
+ argnext - argv);
+ if (p - argv[0] != len)
+ oops("dvips command length mismatch: %u != %u", len, p - argv[0]);
+#endif
+
+ p[-1] = '\n';
+#if MOTIF
+ *p = '\0';
+#endif
+
+ printlog_length = 0;
+
+ q = rindex(dvi_name, '/');
+ if (q != NULL) {
+ struct dvips_env *dep;
+
+#if PS
+ /* grab copies of environment variables before we change them */
+ ps_init_paths();
+#endif
+
+ if (dvips_envs[0].envname == NULL) {
+ for (dep = dvips_envs; dep < dvips_envs + XtNumber(dvips_envs);
+ ++dep) {
+ _Xconst char *envname;
+ _Xconst char *envval;
+ unsigned int len;
+
+ envval = getenv(envname = dep->en1);
+ if (envval == NULL) {
+ envval = getenv(dep->en2);
+ if (envval != NULL) envname = dep->en2;
+ }
+ dep->envname = envname;
+ len = q - dvi_name + 2;
+ if (envval != NULL)
+ len += strlen(envval);
+ dep->envval = p = xmalloc(len);
+ bcopy(dvi_name, p, q - dvi_name);
+ p += q - dvi_name;
+ *p++ = ':';
+ *p = '\0';
+ if (envval != NULL)
+ Strcpy(p, envval);
+ xputenv(dep->envname, dep->envval);
+ }
+ }
+ for (dep = dvips_envs; dep < dvips_envs + XtNumber(dvips_envs);
+ ++dep) {
+ printlog_append(dep->envname, strlen(dep->envname));
+ printlog_append("=", 1);
+ printlog_append(dep->envval, strlen(dep->envval));
+ printlog_append(" ", 1);
+ }
+ }
+
+ printlog_append(argv[0], len);
+#if XAW
+ do_popup(printlog_shell);
+#else
+ XtPopup(printlog_shell, XtGrabNone);
+#endif
+ printlog_active = True;
+
+ --argnext;
+ for (pp = argv + 1; pp <= argnext; ++pp) (*pp)[-1] = '\0';
+ *argnext = NULL;
+
+ if (xpipe(print_io) != 0) {
+ perror("[xdvi] pipe");
+ return;
+ }
+
+ /* Fork process */
+ Fflush(stderr); /* avoid double buffering */
+ print_child.pid = vfork();
+ if (print_child.pid == 0) { /* if child */
+ int fd;
+
+ (void) close(0);
+ (void) close(fileno(dvi_file));
+ fd = open(dvi_name, O_RDONLY);
+ if (fd < 0) {
+ perror(dvi_name);
+ Fflush(stderr);
+ _exit(1);
+ }
+ if (fd > 0) {
+ dup2(fd, 0);
+ (void) close(fd);
+ }
+
+ (void) close(1);
+ if (pr_save_fileradio == &r1radio1) { /* if printing to printer */
+ (void) dup2(print_io[1], 1);
+ }
+ else { /* printing to file */
+ (void) dup2(fileno(f), 1);
+ (void) close(fileno(f));
+ }
+ (void) close(2);
+ (void) dup2(print_io[1], 2);
+ (void) close(print_io[1]);
+ (void) close(print_io[0]);
+
+ if (setsid() == -1) { /* so we can kill the process group */
+ perror("setsid");
+ Fflush(stderr);
+ _exit(1);
+ }
+ (void) execvp(*argv, argv);
+ Fprintf(stderr, "Execvp of %s failed.\n", *argv);
+ Fflush(stderr);
+ _exit(1);
+ }
+
+ free(argv[0]);
+ free(argv);
+ if (pr_save_fileradio == &r1radio2) {
+ fclose(f);
+ ++n_files_left;
+ }
+
+ if (print_child.pid == -1) { /* error */
+ perror("[xdvi] vfork");
+ return;
+ }
+
+ set_chld(&print_child);
+ dvips_sig = SIGINT;
+
+ (void) close(print_io[1]);
+ ++n_files_left;
+
+ /* Set up file descriptor for non-blocking I/O */
+ prep_fd(print_io[0], True);
+ print_xio.fd = print_io[0];
+ set_io(&print_xio);
+
+ dvips_status = DVIPS_STAT_RUN; /* running */
+}
+
+
+#if XAW
+
+static void
+printlog_append(str, len)
+ _Xconst char *str;
+ int len;
+{
+ static XawTextBlock block = {0, 0, NULL, 0};
+
+ block.ptr = (char *) str;
+ block.length = len;
+ block.format = XawFmt8Bit;
+ while (XawTextReplace(printlog_text, printlog_length, printlog_length,
+ &block) != XawEditDone) {
+ int length;
+
+ XtVaGetValues(printlog_text, XtNlength, &length, NULL);
+ printlog_length = length;
+ }
+ printlog_length += len;
+ XawTextSetInsertionPoint(printlog_text, printlog_length);
+}
+
+#else /* MOTIF */
+
+static void
+printlog_append(str, len)
+ _Xconst char *str;
+ int len;
+{
+ XmTextInsert(printlog_text, printlog_length, (char *) str);
+ printlog_length += len;
+ XtVaSetValues(printlog_text, XmNcursorPosition, printlog_length, NULL);
+ XmTextShowPosition(printlog_text, printlog_length);
+}
+
+#endif
+
+static void
+read_from_dvips()
+{
+ int bytes;
+ char line[80];
+
+ for (;;) {
+#if XAW
+ bytes = read(print_xio.fd, line, sizeof line);
+#else
+ bytes = read(print_xio.fd, line, sizeof line - 1);
+#endif
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi: read_from_dvips");
+ break;
+ }
+
+ if (bytes == 0)
+ break;
+ else {
+#if MOTIF
+ line[bytes] = '\0';
+#endif
+ printlog_append(line, bytes);
+ }
+ }
+}
+
+/* ARGSUSED */
+static void
+cb_dvips_cancel(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (dvips_status != DVIPS_STAT_RUN)
+ return; /* How did we get here? */
+
+ kill(print_child.pid, dvips_sig);
+ dvips_sig = SIGKILL;
+ printlog_append("^C", 2);
+}
+
+static void
+dvips_ended(status)
+{
+ char *str;
+ int ms;
+
+ read_from_dvips();
+ clear_io(&print_xio);
+ (void) close(print_xio.fd);
+ ++n_files_left;
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0) {
+ printlog_append("Done.\n", 6);
+ str = NULL;
+ }
+ else
+ str = mprintf("\nPrint process returned exit code %d.\n",
+ WEXITSTATUS(status));
+ }
+ else if (WIFSIGNALED(status))
+ str = mprintf("\nPrint process terminated by signal %d.\n",
+ WTERMSIG(status));
+ else
+ str = mprintf("\nPrint process returned unknown status 0x%x.\n",
+ status);
+
+ ms = resource.dvips_hang;
+ if (str != NULL) {
+ ms = resource.dvips_fail_hang;
+ printlog_append(str, strlen(str));
+ free(str);
+ }
+
+ if (ms > 0) {
+ set_timer(&dvips_timer, ms);
+ dvips_status = DVIPS_STAT_WAIT;
+ }
+ else {
+ printlog_act_keep(NULL, NULL, NULL, NULL);
+ dvips_status = DVIPS_STAT_NONE;
+ }
+
+ XtSetSensitive(printlog_close, True);
+ XtSetSensitive(printlog_cancel, False);
+}
+
+static void
+dvips_pop_down()
+{
+ XtPopdown(printlog_shell);
+ printlog_active = False;
+}
+
+static void
+dvips_alarm(arg)
+ struct xtimer *arg;
+{
+#if XAW
+ Boolean state;
+#endif
+
+#if XAW
+ XtVaGetValues(printlog_keep, XtNstate, &state, NULL);
+ if (!state)
+ dvips_pop_down();
+#else /* MOTIF */
+ if (!XmToggleButtonGadgetGetState(printlog_keep))
+ dvips_pop_down();
+#endif
+ dvips_status = DVIPS_STAT_NONE;
+}
+
+/* ARGSUSED */
+static void
+cb_dvips_close(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (dvips_status == DVIPS_STAT_RUN)
+ return; /* How did we get here? */
+
+ if (dvips_status == DVIPS_STAT_WAIT) {
+ dvips_status = DVIPS_STAT_NONE;
+ cancel_timer(&dvips_timer);
+ }
+
+ dvips_pop_down();
+}
+
+/* ARGSUSED */
+static void
+cb_dvips_keep(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+#if XAW
+ Boolean state;
+#endif
+
+ if (dvips_status != DVIPS_STAT_NONE)
+ return; /* Nothing to do */
+
+#if XAW
+ XtVaGetValues(printlog_keep, XtNstate, &state, NULL);
+ if (!state)
+ dvips_pop_down();
+#else
+ if (!XmToggleButtonGadgetGetState(printlog_keep))
+ dvips_pop_down();
+#endif
+}
+
+/* ARGSUSED */
+static void
+cb_dvips_delete(w, client_data, call_data)
+ Widget w;
+ XtPointer client_data;
+ XtPointer call_data;
+{
+ if (dvips_status == DVIPS_STAT_RUN)
+ cb_dvips_cancel(w, client_data, call_data);
+ else
+ cb_dvips_close(w, client_data, call_data);
+}
+
+/* ARGSUSED */
+static void
+printlog_act_close P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ cb_dvips_close(NULL, NULL, NULL);
+}
+
+/* ARGSUSED */
+static void
+printlog_act_keep P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+#if XAW
+ XtVaSetValues(printlog_keep, XtNstate, True, NULL);
+#else /* MOTIF */
+ XmToggleButtonGadgetSetState(printlog_keep, True, False);
+#endif
+}
+
+/* ARGSUSED */
+static void
+printlog_act_unkeep P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+#if XAW
+ XtVaSetValues(printlog_keep, XtNstate, False, NULL);
+#else /* MOTIF */
+ XmToggleButtonGadgetSetState(printlog_keep, False, False);
+#endif
+ if (dvips_status == DVIPS_STAT_NONE)
+ dvips_pop_down();
+}
+
+/* ARGSUSED */
+static void
+printlog_act_cancel P4C(Widget, w, XEvent *, event, String *, params,
+ Cardinal *, num_params)
+{
+ cb_dvips_cancel(NULL, NULL, NULL);
+}
diff --git a/psdps.c b/psdps.c
@@ -0,0 +1,832 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2002 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTES:
+ This code was originally written by Ricardo Telichevesky
+ (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
+ (lms@rle-vlsi-mit.edu).
+ It was largely influenced by similar code in the SeeTeX/XTeX
+ package by Dirk Grunwald (grunwald@colorado.edu).
+
+\*========================================================================*/
+
+#include "xdvi.h"
+#include <errno.h>
+#include <signal.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <DPS/XDPSlib.h>
+#include <DPS/dpsXclient.h>
+#include <DPS/dpsexcept.h>
+#include <DPS/dpsclient.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#if defined(sun) || defined(__sun)
+#ifndef SUNHACK
+#define SUNHACK 1
+#endif
+#endif
+
+
+ /*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ */
+#if !SUNHACK
+static char preamble[] = "\
+/xdvi$line 81 string def \
+/xdvi$run {{$error null ne {$error /newerror false put}if \
+ currentfile cvx stopped \
+ $error null eq {false} {$error /newerror get} ifelse and \
+ {handleerror} if} stopped pop} def \
+/xdvi$dslen countdictstack def \
+{currentfile read not {exit} if 72 eq \
+ {xdvi$run} \
+ {/xdvi$sav save def xdvi$run \
+ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
+ ifelse \
+ {(%%xdvimark) currentfile xdvi$line {readline} stopped \
+ {clear} {pop eq {exit} if} ifelse }loop \
+ (xdvi$Ack\n) print flush \
+}loop\nH";
+#else /* SUNHACK */
+static char preamble[] = "\
+/xdvi$line 81 string def \
+/xdvi$run {{$error null ne {$error /newerror false put}if \
+ currentfile cvx stopped \
+ $error null eq {false} {$error /newerror get} ifelse and \
+ {handleerror} if} stopped pop} def \
+/xdvi$dslen countdictstack def \
+/xdvi$ack {{(%%xdvimark) currentfile xdvi$line {readline} stopped \
+ {clear} {pop eq {exit} if} ifelse }loop \
+ (xdvi$Ack\n) print flush} bind def \
+errordict begin /interrupt{(xdvi$Int\n) print flush stop}bind def \
+end \
+{{currentfile read not {exit} if 72 eq \
+ {xdvi$run} \
+ {/xdvi$sav save def xdvi$run \
+ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
+ ifelse \
+ xdvi$ack \
+ }loop \
+xdvi$ack \
+}loop\nH";
+#endif /* SUNHACK */
+
+extern _Xconst char psheader[];
+extern unsigned psheaderlen;
+
+#define postscript resource._postscript
+
+
+/* global procedures (besides initDPS) */
+
+static void toggleDPS ARGS((void));
+static void destroyDPS ARGS((void));
+static void interruptDPS ARGS((void));
+static void endpageDPS ARGS((void));
+static void drawbeginDPS ARGS((int, int, _Xconst char *));
+static void drawrawDPS ARGS((_Xconst char *));
+static void drawfileDPS ARGS((_Xconst char *, FILE *));
+static void drawendDPS ARGS((_Xconst char *));
+static void beginheaderDPS ARGS((void));
+static void endheaderDPS ARGS((void));
+static void newdocDPS ARGS((void));
+
+static struct psprocs dps_procs = {
+ /* toggle */ toggleDPS,
+ /* destroy */ destroyDPS,
+ /* interrupt */ interruptDPS,
+ /* endpage */ endpageDPS,
+ /* drawbegin */ drawbeginDPS,
+ /* drawraw */ drawrawDPS,
+ /* drawfile */ drawfileDPS,
+ /* drawend */ drawendDPS,
+ /* beginheader */ beginheaderDPS,
+ /* endheader */ endheaderDPS,
+ /* newdoc */ newdocDPS};
+
+#define DPS_MASK_NORMAL EV_GE_NEWPAGE
+#define DPS_MASK_HEADER EV_GE_PS_TOGGLE
+#define DPS_MASK_INIT (EV_GE_TERM | EV_PS_TOGGLE)
+
+static DPSContext DPS_ctx = NULL;
+static DPSSpace DPS_space = NULL;
+static int DPS_mag; /* magnification currently in use */
+static int DPS_shrink; /* shrink factor currently in use */
+static Boolean DPS_active; /* if we've started a page */
+static int DPS_pending; /* number of ack's we're expecting */
+static Boolean DPS_in_header; /* if we're sending a header */
+static Boolean DPS_in_doc; /* if we've sent header information */
+static int DPS_ev_mask = DPS_MASK_NORMAL;
+ /* events for which we'll stop */
+
+#if 0
+static void DPSErrorProcHandler();
+#else
+#define DPSErrorProcHandler DPSDefaultErrorProc
+#endif
+
+
+static char ackstr[] = "xdvi$Ack\n";
+#if SUNHACK
+static char intstr[] = "xdvi$Int\n";
+static char intstr2[] = "xdvi$In2\n";
+#endif
+
+#define LINELEN 81
+#define BUFLEN (LINELEN + sizeof(ackstr))
+static char line[BUFLEN + 1];
+static char *linepos = line;
+
+/* ARGSUSED */
+static void
+TextProc(ctxt, buf, count)
+ DPSContext ctxt;
+ char *buf;
+ unsigned long count;
+{
+ int i;
+ char *p;
+ char *p0;
+
+ while (count > 0) {
+ i = line + BUFLEN - linepos;
+ if (i > count) i = count;
+ (void) bcopy(buf, linepos, i);
+ linepos += i;
+ buf += i;
+ count -= i;
+ p0 = line;
+ for (;;) {
+ if (p0 >= linepos) {
+ linepos = line;
+ break;
+ }
+ p = memchr(p0, '\n', linepos - p0);
+ if (p == NULL) {
+ if (p0 != line) {
+ (void) bcopy(p0, line, linepos - p0);
+ linepos -= p0 - line;
+ }
+ else if (linepos == line + BUFLEN) {
+ char c;
+
+ c = line[LINELEN];
+ line[LINELEN] = '\0';
+ Printf("DPS: %s\n", line);
+ line[LINELEN] = c;
+ linepos -= LINELEN;
+ (void) bcopy(line + LINELEN, line, linepos - line);
+ }
+ break;
+ }
+ if (p >= p0 + 8 && memcmp(p - 8, ackstr, 9) == 0) {
+ --DPS_pending;
+ if (DPS_pending == 0)
+ ev_flags |= EV_ACK;
+ if (debug & DBG_PS)
+ Printf("Got DPS ack; %d pending.\n", DPS_pending);
+ ++p;
+ (void) bcopy(p, p - 9, linepos - p);
+ linepos -= 9;
+ continue;
+ }
+#if SUNHACK
+ if (p >= p0 + 8 && memcmp(p - 8, intstr, 9) == 0) {
+ if (debug & DBG_PS)
+ Puts("Got DPS int.");
+ ++p;
+ (void) bcopy(p, p - 9, linepos - p);
+ linepos -= 9;
+ ev_flags |= EV_ACK;
+ continue;
+ }
+ if (p >= p0 + 8 && memcmp(p - 8, intstr2, 9) == 0) {
+ if (debug & DBG_PS)
+ Puts("Got DPS int 2.");
+ ++p;
+ (void) bcopy(p, p - 9, linepos - p);
+ linepos -= 9;
+ DPS_pending = 3;
+ continue;
+ }
+#endif /* SUNHACK */
+ *p = '\0';
+ Printf("DPS: %s\n", p0);
+ p0 = p + 1;
+ }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ waitack()
+
+ Arguments: none.
+
+ Returns: (void)
+
+ Description:
+ Waits until the requisite number of acknowledgements has been received from
+ the context.
+
++----------------------------------------------------------------------------*/
+
+#if SUNHACK
+static void DPS_alarm ARGS((struct xtimer *));
+
+static struct xtimer DPS_timer = TIMER_INIT(DPS_alarm);
+static Boolean DPS_timer_set;
+
+static void
+DPS_alarm(arg)
+ struct xtimer *arg;
+{
+ if (debug & DBG_PS)
+ Puts("Received DPS alarm");
+
+ DPS_timer_set = False;
+ ev_flags |= EV_ACK;
+}
+#endif /* SUNHACK */
+
+static void
+waitack()
+{
+ if (DPS_pending <= 0)
+ return;
+
+ DPSFlushContext(DPS_ctx);
+ if (read_events(DPS_ev_mask | EV_ACK) & EV_ACK) {
+ ev_flags &= ~EV_ACK;
+ return;
+ }
+
+ if (debug & DBG_PS)
+ Printf("Interrupting DPS in waitack(); code is now %d %x\n",
+ XDPSGetContextStatus(DPS_ctx), ev_flags);
+
+ DPS_active = DPS_in_header = DPS_in_doc = False;
+ DPS_ev_mask = DPS_MASK_NORMAL;
+
+ /*
+ * I would really like to use DPSInterruptContext() here, but (at least
+ * on an RS6000) I can't get it to work.
+ */
+
+#if SUNHACK
+
+ /*
+ * On the other hand, under OpenWindows 3.3 (at least), destroying and
+ * re-creating contexts has a nasty habit of crashing the server.
+ */
+
+ DPS_pending = 32767;
+ DPSInterruptContext(DPS_ctx);
+ DPSFlushContext(DPS_ctx);
+ (void) read_events(EV_GE_TERM | EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ XSync(DISP, False);
+ DPSPrintf(DPS_ctx, " stop\n%%%%xdvimark\n stop\n%%%%xdvimark\n");
+ DPSPrintf(DPS_ctx," (xdvi$In2\n) print flush stop\n%%%%xdvimark\n");
+ DPSPrintf(DPS_ctx, " stop\n%%%%xdvimark\n stop\n%%%%xdvimark\n");
+ DPSFlushContext(DPS_ctx);
+
+ if (debug & DBG_PS)
+ Puts("Setting DPS timer");
+ DPS_timer_set = True;
+ set_timer(&DPS_timer, 500);
+ (void) read_events(EV_GE_TERM | EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (DPS_pending <= 0) {
+ if (DPS_timer_set) cancel_timer(&DPS_timer);
+ return;
+ }
+
+ /*
+ * However, under Solaris 2.6 (at least), sometimes interrupting the
+ * context leaves it in an uncommunicative state, so destruction
+ * is the only alternative.
+ */
+
+ if (debug & DBG_PS)
+ Puts("Plan B: Destroying DPS context");
+
+#endif /* SUNHACK */
+
+ DPSDestroyContext(DPS_ctx);
+ DPS_ctx = NULL;
+ DPS_pending = 0;
+}
+
+
+/*---------------------------------------------------------------------------*
+ initDPS()
+
+ Arguments: (none)
+ Returns: (void)
+ Side-Effects: DPS_ctx may be set as well as other static variables.
+
+ Description:
+ Initializes variables from the application main loop. Checks to see if
+ a connection to the DPS server can be opened.
+
++----------------------------------------------------------------------------*/
+
+static int
+get_shift(mask)
+ Pixel mask;
+{
+ int k;
+
+ for (k = 0; (mask & 1) == 0; ++k)
+ mask >>= 1;
+ return k;
+}
+
+Boolean
+initDPS()
+{
+
+ /* Try to create a context */
+
+#if GREY
+
+ if (our_colormap == DefaultColormapOfScreen(SCRN))
+ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, copyGC, 0, 0,
+ TextProc, DPSDefaultErrorProc, NULL);
+ else {
+ static XStandardColormap *ccube = NULL;
+ static XStandardColormap *grayramp = NULL;
+ int shift;
+
+ if (grayramp == NULL) {
+ grayramp = XAllocStandardColormap();
+ if (grayramp == NULL)
+ return False;
+ }
+
+ if (ccube == NULL) {
+ ccube = XAllocStandardColormap();
+ if (ccube == NULL)
+ return False;
+ }
+
+ shift = get_shift(our_visual->red_mask);
+ ccube->red_max = our_visual->red_mask >> shift;
+ ccube->red_mult = 1 << shift;
+
+ shift = get_shift(our_visual->green_mask);
+ ccube->green_max = our_visual->green_mask >> shift;
+ ccube->green_mult = 1 << shift;
+
+ shift = get_shift(our_visual->blue_mask);
+ ccube->blue_max = our_visual->blue_mask >> shift;
+ ccube->blue_mult = 1 << shift;
+
+ grayramp->red_max = ccube->red_max & ccube->green_max
+ & ccube->blue_max;
+ grayramp->red_mult = ccube->red_mult + ccube->green_mult
+ + ccube->blue_mult;
+
+ ccube->colormap = grayramp->colormap = our_colormap;
+ ccube->visualid = grayramp->visualid = our_visual->visualid;
+
+ DPS_ctx = XDPSCreateContext(DISP, mane.win, copyGC, 0, 0,
+ 0, grayramp, ccube,
+ /* actual */ (ccube->red_max + 1) * (ccube->green_max + 1)
+ * (ccube->blue_max + 1),
+ TextProc, DPSDefaultErrorProc, NULL);
+ }
+
+#else /* not GREY */
+
+ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, copyGC, 0, 0,
+ TextProc, DPSDefaultErrorProc, NULL);
+
+#endif /* not GREY */
+
+ if (DPS_ctx == NULL)
+ return False;
+
+ DPS_mag = DPS_shrink = -1;
+ DPS_active = False;
+ DPS_pending = 1;
+
+ DPS_space = DPSSpaceFromContext(DPS_ctx);
+ DPSWritePostScript(DPS_ctx, preamble, sizeof(preamble) - 1);
+ DPSWritePostScript(DPS_ctx, (char *) psheader, psheaderlen);
+ DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n");
+ DPSFlushContext(DPS_ctx);
+
+ psp = dps_procs;
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ toggleDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: psp.drawbegin is changed.
+
+ Description:
+ Used to toggle the rendering of PostScript by the DPS server
+ This routine may be called from within read_events().
+
++----------------------------------------------------------------------------*/
+
+static void
+toggleDPS()
+{
+ if (debug & DBG_PS) Puts("Toggling DPS on or off");
+
+ psp.drawbegin = (postscript ? drawbeginDPS : drawbegin_none);
+}
+
+
+/*---------------------------------------------------------------------------*
+ destroyDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the context is nulled out and destroyed.
+
+ Description:
+ Close the connection to the DPS server; used when rendering is terminated
+ in any way.
+
++----------------------------------------------------------------------------*/
+
+static void
+destroyDPS()
+{
+ if (debug & DBG_PS)
+ Puts("Calling destroyDPS()");
+ if (linepos > line) {
+ *linepos = '\0';
+ Printf("DPS: %s\n", line);
+ }
+ DPSDestroySpace(DPS_space);
+ psp = no_ps_procs;
+ scanned_page = scanned_page_ps = scanned_page_reset;
+}
+
+
+/*---------------------------------------------------------------------------*
+ interruptDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the context may be nulled out and destroyed.
+
+ Description:
+ Close the connection to the DPS server; used when rendering is terminated
+ because of an interruption in the viewing of the current page.
+
++----------------------------------------------------------------------------*/
+
+static void
+interruptDPS()
+{
+
+ if (debug & DBG_PS)
+ Puts("Running interruptDPS()");
+
+ if (DPS_pending <= 0)
+ return; /* nothing to do */
+
+ if (DPS_active) {
+ DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
+ DPS_active = False;
+ }
+
+ waitack();
+}
+
+
+/*---------------------------------------------------------------------------*
+ endpageDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the DPS_active variable is cleared.
+
+ Description:
+ Should be called at the end of a page to end this chunk for the DPS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+endpageDPS()
+{
+ if (DPS_active) {
+ if (debug & DBG_PS)
+ Puts("Endpage sent to context");
+ DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
+ DPS_active = False;
+ waitack();
+ }
+}
+
+
+/*
+ * checkDPS - Check that the DPS interpreter is still running.
+ * Return True for success, False for failure.
+ */
+
+static Boolean
+checkDPS()
+{
+ /* static char faulty_display_vs[]
+ * ="DECWINDOWS DigitalEquipmentCorporation UWS4.2LA"; */
+
+ if (DPS_ctx == NULL) {
+ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, copyGC, 0, 0,
+ TextProc, DPSErrorProcHandler, DPS_space);
+ if (DPS_ctx == NULL) {
+ psp = no_ps_procs;
+ draw_bbox();
+ return False;
+ }
+ DPSWritePostScript(DPS_ctx, preamble, sizeof(preamble) - 1);
+ /* it already has psheader */
+ DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n");
+ DPS_mag = DPS_shrink = -1;
+ DPS_active = False;
+ DPS_pending = 1;
+ }
+
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawbeginDPS ()
+
+ Arguments: xul, yul - coordinates of the upper left corner of the figure
+ cp - string with the bounding box line data
+ Returns: (void)
+ Side-Effects: DPS_ctx is set is set and connection to DPS server is
+ opened.
+
+ Description:
+ Opens a connection to the DPS server and send in the preamble and the
+ bounding box information after correctly computing resolution factors.
+ In case no rendering is to be done, outlines the figure.
+ An outline is also generated whenever the a context cannot be allocated
+
++----------------------------------------------------------------------------*/
+
+static void
+drawbeginDPS(xul, yul, cp)
+ int xul, yul;
+ _Xconst char *cp;
+{
+ if (debug & DBG_PS)
+ Printf("Begin drawing at xul= %d, yul= %d.\n", xul, yul);
+
+ if (!checkDPS()) return;
+
+ if (!DPS_active) {
+ /* send initialization to context */
+ if (magnification != DPS_mag) {
+ DPSPrintf(DPS_ctx, "H TeXDict begin /DVImag %d 1000 div def \
+end stop\n%%%%xdvimark\n",
+ DPS_mag = magnification);
+ ++DPS_pending;
+ }
+ if (mane.shrinkfactor != DPS_shrink) {
+ DPSPrintf(DPS_ctx, "H TeXDict begin %d %d div dup \
+/Resolution X /VResolution X \
+end stop\n%%%%xdvimark\n",
+ pixels_per_inch, DPS_shrink = mane.shrinkfactor);
+ ++DPS_pending;
+ }
+ DPSPrintf(DPS_ctx, " TeXDict begin\n");
+ DPS_active = True;
+ ++DPS_pending;
+ }
+
+ if (ev_flags & DPS_MASK_NORMAL)
+ longjmp(canit_env, 1);
+
+ DPSPrintf(DPS_ctx, "%d %d moveto\n", xul, yul);
+ DPSPrintf(DPS_ctx, "%s\n", cp);
+}
+
+
+/*---------------------------------------------------------------------------*
+
+ drawrawDPS()
+
+ Arguments: cp - the raw string to be sent to the postscript interpreter
+ Returns: (void)
+ Side-Effects: (none)
+
+ Description:
+ If there is a valid postscript context, just send the string to the
+ interpreter, else leave.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawrawDPS(cp)
+ _Xconst char *cp;
+{
+ if (!DPS_active || (ev_flags & DPS_ev_mask))
+ return;
+
+ if (debug & DBG_PS)
+ Printf("Sending raw PS to context: %s\n", cp);
+
+ DPSPrintf(DPS_ctx,"%s\n", cp);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawfileDPS()
+
+ Arguments: cp - string with the postscript file pathname
+ psfile - opened file pointer
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Postscript file containing the figure is opened and sent to the DPS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawfileDPS(cp, psfile)
+ _Xconst char *cp;
+ FILE *psfile;
+{
+ char buffer[1025];
+ int blen;
+
+ if (DPS_active && !(read_events(EV_NOWAIT) & DPS_ev_mask)) {
+ if (debug & DBG_PS)
+ Printf("sending file %s\n", cp);
+ for (;;) {
+ blen = fread(buffer, sizeof(char), 1024, psfile);
+ if (blen == 0) break;
+ DPSWritePostScript(DPS_ctx, buffer, blen);
+ if (read_events(EV_NOWAIT) & DPS_ev_mask) {
+ /* ||| stop at a good place */
+ if (debug & DBG_PS)
+ Puts("Interrupting in drawfileDPS");
+ break;
+ }
+ }
+ }
+
+ Fclose(psfile);
+ ++n_files_left;
+
+ if (ev_flags & DPS_ev_mask)
+ longjmp(canit_env, 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawendDPS()
+
+ Arguments: cp - string with indication of the end of the special
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Sends the indication of end of the figure PostScript code.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawendDPS(cp)
+ _Xconst char *cp;
+{
+ if (!DPS_active || (ev_flags & DPS_MASK_NORMAL))
+ return;
+
+ if (debug & DBG_PS)
+ Printf("End PS: %s\n", cp);
+ DPSPrintf(DPS_ctx,"%s\n", cp);
+}
+
+
+/*---------------------------------------------------------------------------*
+ beginheaderDPS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+beginheaderDPS()
+{
+ if (ev_flags & DPS_MASK_HEADER || !checkDPS())
+ return;
+
+ if (debug & DBG_PS) Puts("Running beginheaderDPS()");
+
+ if (DPS_active) {
+ if (!DPS_in_header)
+ oops("Internal error in beginheaderDPS().\n");
+ return;
+ }
+
+ DPS_in_header = True;
+ DPS_ev_mask = DPS_MASK_HEADER;
+
+ if (DPS_in_doc)
+ DPSPrintf(DPS_ctx, "H");
+ else {
+ DPSPrintf(DPS_ctx, "Hsave /xdvi$doc exch def\n");
+ DPS_in_doc = True;
+ }
+ DPS_active = True;
+ ++DPS_pending;
+}
+
+
+/*---------------------------------------------------------------------------*
+ endheaderDPS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+endheaderDPS()
+{
+ if (debug & DBG_PS) Puts("Running endheaderDPS()");
+
+ if (DPS_active) {
+ DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
+ DPS_active = False;
+ waitack();
+ DPS_in_header = False;
+ DPS_ev_mask = DPS_MASK_NORMAL;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ newdocDPS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Clears out headers stored from the previous document.
+
++----------------------------------------------------------------------------*/
+
+static void
+newdocDPS()
+{
+ if (debug & DBG_PS) Puts("Running newdocDPS()");
+
+ if (DPS_in_doc) {
+ DPSPrintf(DPS_ctx, "H xdvi$doc restore stop\n%%%%xdvimark\n");
+ ++DPS_pending;
+ DPS_mag = DPS_shrink = -1;
+ DPS_in_doc = False;
+ }
+}
diff --git a/psgs.c b/psgs.c
@@ -0,0 +1,916 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2003 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+#include "xdvi.h"
+#include <X11/Xatom.h>
+
+#include <memory.h>
+#include <signal.h>
+
+/* Condition for retrying a write */
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef EWOULDBLOCK
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+#else /* EAGAIN */
+#define AGAIN_CONDITION (errno == EWOULDBLOCK)
+#endif /* EAGAIN */
+#else /* EWOULDBLOCK */
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EAGAIN)
+#endif /* EAGAIN */
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+#if HAVE_VFORK_H
+# include <vfork.h>
+#endif
+
+#ifndef GS_TIMEOUT
+# define GS_TIMEOUT 1000 /* milliseconds */
+#endif
+
+extern _Xconst char psheader[];
+extern unsigned psheaderlen;
+
+#define postscript resource._postscript
+
+/* global procedures (besides initGS) */
+
+static void toggle_gs ARGS((void));
+static void destroy_gs ARGS((void));
+static void interrupt_gs ARGS((void));
+static void endpage_gs ARGS((void));
+static void drawbegin_gs ARGS((int, int, _Xconst char *));
+static void drawraw_gs ARGS((_Xconst char *));
+static void drawfile_gs ARGS((_Xconst char *, FILE *));
+static void drawend_gs ARGS((_Xconst char *));
+static void beginheader_gs ARGS((void));
+static void endheader_gs ARGS((void));
+static void newdoc_gs ARGS((void));
+
+static struct psprocs gs_procs = {
+ /* toggle */ toggle_gs,
+ /* destroy */ destroy_gs,
+ /* interrupt */ interrupt_gs,
+ /* endpage */ endpage_gs,
+ /* drawbegin */ drawbegin_gs,
+ /* drawraw */ drawraw_gs,
+ /* drawfile */ drawfile_gs,
+ /* drawend */ drawend_gs,
+ /* beginheader */ beginheader_gs,
+ /* endheader */ endheader_gs,
+ /* newdoc */ newdoc_gs};
+
+static int std_io[2];
+
+#define GS_fd (std_io[0])
+
+ /* some arguments are filled in later */
+static char arg4[] = "-dDEVICEWIDTH=xxxxxxxxxx";
+static char arg5[] = "-dDEVICEHEIGHT=xxxxxxxxxx";
+
+static _Xconst char *argv[] = {NULL, NULL, "-dNOPAUSE", "-q", arg4, arg5,
+ "-dDEVICEXRESOLUTION=72",
+ "-dDEVICEYRESOLUTION=72",
+ "-dNOSAFER", "-dNOEPS", NULL, NULL, NULL};
+
+static unsigned int GS_page_w; /* how big our current page is */
+static unsigned int GS_page_h;
+static Boolean GS_alpha; /* if we are using the alpha driver */
+static int GS_mag; /* magnification currently in use */
+static int GS_shrink; /* shrink factor currently in use */
+static Boolean GS_active; /* if we've started a page yet */
+static int GS_pending; /* number of ack's we're expecting */
+static char GS_outb[257]; /* circular output buffer */
+static char *GS_outb_in; /* next position in output buffer */
+static char *GS_outb_out; /* next byte to come out of buffer */
+#define GS_outb_limit (GS_outb + sizeof GS_outb) /* last+1 byte */
+static int GS_write_ack; /* flag to set when done writing */
+static Boolean GS_in_header; /* if we're sending a header */
+static Boolean GS_in_doc; /* if we've sent header information */
+static int GS_ev_mask; /* events for which we'll stop */
+static int GS_die_ack = 0; /* flags to set when GS dies */
+static Boolean GS_timer_set; /* if there's a timer set */
+static Boolean GS_old; /* if we're using gs 2.xx */
+
+#define GS_MASK_NORMAL EV_GE_NEWPAGE
+#define GS_MASK_HEADER EV_GE_PS_TOGGLE
+#define GS_MASK_INIT (EV_GE_TERM | EV_PS_TOGGLE)
+
+static Atom gs_atom;
+static Atom gs_colors_atom;
+
+#define Landscape 90
+
+#define LINELEN 81
+static char line[LINELEN + 1];
+static char *linepos = line;
+static char ackstr[] = "\347\310\376";
+static char oldstr[] = "\347\310\375";
+
+static void gs_died ARGS((int));
+
+static struct xchild gs_child = {NULL, 0, True, gs_died};
+#define GS_pid (gs_child.pid)
+
+static void read_from_gs ARGS((void));
+static void write_to_gs ARGS((void));
+
+static struct xio gs_xio = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_gs, write_to_gs};
+
+static void gs_alarm ARGS((struct xtimer *));
+
+static struct xtimer gs_timer = TIMER_INIT(gs_alarm);
+
+static void
+showto(q)
+ char *q;
+{
+ char *p = line;
+ char *p1;
+
+ while (p < q) {
+ p1 = memchr(p, '\n', q - p);
+ if (p1 == NULL) p1 = q;
+ *p1 = '\0';
+ Printf("gs: %s\n", p);
+ p = p1 + 1;
+ }
+}
+
+static void
+read_from_gs()
+{
+ int bytes;
+ char *line_end;
+ char *p;
+
+ for (;;) {
+
+ bytes = read(GS_fd, linepos, line + LINELEN - linepos);
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi: read_from_gs");
+ break;
+ }
+ line_end = linepos + bytes;
+
+ if (bytes == 0) {
+ if (GS_pid != 0)
+ puts("Read_from_gs returned 0 bytes.");
+ break;
+ }
+
+ /* Check for ack strings */
+ for (p = line; p < line_end - 2; ++p) {
+ p = memchr(p, '\347', line_end - p - 2);
+ if (p == NULL) break;
+ if (memcmp(p, ackstr, 3) == 0) {
+ --GS_pending;
+ if (GS_pending == 0)
+ ev_flags |= EV_ACK;
+ if (debug & DBG_PS)
+ Printf("Got GS ack; %d pending.\n", GS_pending);
+ }
+ else if (memcmp(p, oldstr, 3) == 0) {
+ if (debug & DBG_PS)
+ Puts("Using old GS version.");
+ GS_old = True;
+ }
+ else continue;
+
+ showto(p);
+ p += 3;
+ (void) bcopy(p, line, line_end - p);
+ line_end -= p - line;
+ linepos = p = line;
+ --p;
+ }
+ *line_end = '\0';
+ p = rindex(linepos, '\n');
+ if (p != NULL) {
+ ++p;
+ showto(p);
+ (void) bcopy(p, line, line_end - p);
+ line_end -= p - line;
+ }
+ linepos = line_end;
+ /*
+ * Normally we'd hold text until a newline character, but the
+ * buffer is full. So we flush it, being careful not to cut up an
+ * ack string.
+ */
+ if (linepos >= line + LINELEN) {
+ p = line + LINELEN;
+ if ((*--p != '\347' && *--p != '\347' && *--p != '\347')
+ || (memcmp(p, ackstr, line + LINELEN - p) != 0
+ && memcmp(p, oldstr, line + LINELEN - p) != 0))
+ p = line + LINELEN;
+ *p = '\0';
+ Printf("gs: %s\n", line);
+ *p = '\347';
+ linepos = line;
+ while (p < line + LINELEN) *linepos++ = *p++;
+ }
+ }
+}
+
+static void
+write_to_gs()
+{
+ char *send_end;
+ int bytes;
+
+ for (;;) {
+ send_end = GS_outb_in;
+ if (send_end < GS_outb_out) send_end = GS_outb_limit;
+ bytes = write(GS_fd, GS_outb_out, send_end - GS_outb_out);
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi: write_to_gs");
+ break;
+ }
+ GS_outb_out += bytes;
+ if (GS_outb_out == GS_outb_limit) GS_outb_out = GS_outb;
+ if (GS_outb_out == GS_outb_in) { /* if buffer is empty */
+ gs_xio.xio_events = XIO_IN;
+#if HAVE_POLL
+ if (gs_xio.pfd != NULL) /* write_to_gs is called directly */
+ gs_xio.pfd->events = XIO_IN;
+#endif
+ break;
+ }
+ }
+
+ ev_flags |= GS_write_ack;
+ GS_write_ack = 0;
+}
+
+
+/*
+ * Main routine for writing to the GS interpreter.
+ */
+
+static void
+gs_send(cp, len)
+ _Xconst char *cp;
+ size_t len;
+{
+ _Xconst char *cp_end = cp + len;
+ char *send_end;
+ size_t bytes;
+ char *old_out;
+ Boolean interrupting;
+
+ if (GS_pid == 0 || (ev_flags & GS_ev_mask))
+ return;
+
+ /*
+ * Because cp might reside on the stack, don't return until we've
+ * copied all of it to our circular output buffer.
+ * Note that GS_outb_out == GS_outb_in means that the buffer is empty.
+ */
+
+ GS_timer_set = interrupting = False;
+ for (;;) {
+ send_end = GS_outb_out;
+ if (send_end == GS_outb) send_end = GS_outb_limit;
+ --send_end;
+ if (send_end < GS_outb_in) send_end = GS_outb_limit;
+ bytes = send_end - GS_outb_in;
+ if (bytes > 0) {
+ if (bytes >= cp_end - cp) bytes = cp_end - cp;
+ bcopy(cp, GS_outb_in, bytes);
+ cp += bytes;
+ GS_outb_in += bytes;
+ if (GS_outb_in == GS_outb_limit) GS_outb_in = GS_outb;
+ if (cp < cp_end) continue;
+ }
+
+ /* The buffer is now full --or-- we've run out of data */
+ old_out = GS_outb_out;
+ if (!(gs_xio.xio_events & XIO_OUT)) { /* restart output */
+ gs_xio.xio_events = XIO_IN | XIO_OUT;
+#if HAVE_POLL
+ if (gs_xio.pfd != NULL)
+ gs_xio.pfd->events = POLLIN | POLLOUT;
+#endif
+ write_to_gs();
+ if (GS_outb_out != old_out) {
+ if (cp == cp_end)
+ break;
+ else
+ continue;
+ }
+ }
+
+ if (cp == cp_end)
+ break;
+
+ GS_die_ack = GS_write_ack = EV_ACK;
+ for (;;) { /* loop because there may be stray ACKs */
+ if (!interrupting) {
+ (void) read_events(GS_ev_mask | EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (GS_pid == 0) { /* if GS died */
+ GS_die_ack = 0;
+ return;
+ }
+
+ if (GS_outb_out != old_out) /* if more room in buffer */
+ break;
+
+ if (ev_flags & GS_ev_mask) { /* if a serious event */
+ if (debug & DBG_PS)
+ Puts("Setting timeout in gs_send()");
+
+ set_timer(&gs_timer, GS_TIMEOUT);
+ GS_timer_set = interrupting = True;
+ }
+ }
+ else {
+ (void) read_events(EV_GE_TERM | EV_PS_TOGGLE | EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (GS_outb_out != old_out) /* if more room in buffer */
+ break;
+
+ if (GS_timer_set) /* if timer still set */
+ cancel_timer(&gs_timer);
+
+ destroy_gs();
+ GS_die_ack = 0;
+ return;
+ }
+ }
+ }
+
+ if (GS_timer_set) /* if timer still set */
+ cancel_timer(&gs_timer);
+
+ GS_die_ack = GS_write_ack = 0;
+}
+
+/*
+ * Interrupt routine for timer routine.
+ */
+
+static void
+gs_alarm(arg)
+ struct xtimer *arg;
+{
+ if (debug & DBG_PS)
+ puts("GS timeout expired");
+
+ ev_flags |= EV_ACK;
+ GS_timer_set = False;
+}
+
+/*
+ * Wait for acknowledgement from GS.
+ */
+
+static void
+waitack()
+{
+ if (GS_pending == 0) {
+ ev_flags &= ~EV_ACK;
+ return;
+ }
+
+ GS_die_ack = EV_ACK;
+
+ for (;;) { /* loop because there might be stray ACKs. */
+ (void) read_events(EV_GE_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (GS_pending == 0) {
+ GS_die_ack = 0;
+ return;
+ }
+ if (ev_flags & EV_GE_ACK)
+ break;
+ }
+
+ if (debug & DBG_PS)
+ Puts("Setting timeout in waitack()");
+
+ set_timer(&gs_timer, GS_TIMEOUT);
+ GS_timer_set = True;
+
+ (void) read_events(EV_GE_TERM | EV_PS_TOGGLE | EV_ACK);
+ ev_flags &= ~EV_ACK;
+
+ if (GS_timer_set)
+ cancel_timer(&gs_timer);
+
+ GS_die_ack = 0;
+
+ if (GS_pending > 0)
+ destroy_gs();
+}
+
+
+/*
+ * Fork a process to run ghostscript. This is done using the
+ * x11 device (which needs to be compiled in). Normally the x11
+ * device uses ClientMessage events to communicate with the calling
+ * program, but we don't do this. The reason for using the ClientMessage
+ * events is that otherwise ghostview doesn't know when a non-conforming
+ * postscript program calls showpage. That doesn't affect us here,
+ * since in fact we disable showpage.
+ *
+ * SAFER mode is handled as follows. Ghostscript versions 7.02 and earlier
+ * ignore -dNOSAFER and handle -dSAFER if it is supplied; the code in
+ * strsafe is ignored since .locksafe is not present. In versions 7.04 and
+ * higher, -dNOSAFER overrides -dSAFER (if provided); SAFER mode is
+ * optionally turned on by sending the strsafe string. It is possible
+ * in some versions of gs prior to 7.04 to use -dDELAYSAFER instead of
+ * -dNOSAFER, but there's no point in doing that since .locksafe is not
+ * defined in those versions. I don't know where 7.03 fits in on all of
+ * this.
+ */
+
+Boolean
+initGS()
+{
+ char buf[100];
+ static Boolean did_putenv = False;
+ /*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ * `execute' is unique to ghostscript.
+ */
+ static _Xconst char strsafe[] = "\
+{ << /PermitFileReading [ (*) ] /PermitFileWriting [ ] /PermitFileControl [ ] \
+ >> setuserparams .locksafe \
+} stopped pop\n";
+
+ static _Xconst char str1[] = "\
+/xdvi$run {$error /newerror false put {currentfile cvx execute} stopped pop} \
+ def \
+/xdvi$ack (\347\310\376) def \
+/xdvi$dslen countdictstack def \
+{currentfile read pop 72 eq \
+ {xdvi$run} \
+ {/xdvi$sav save def xdvi$run \
+ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
+ ifelse \
+ {(%%xdvimark) currentfile =string {readline} stopped \
+ {clear} {pop eq {exit} if} ifelse }loop \
+ flushpage xdvi$ack print flush \
+}loop\nH";
+ static _Xconst char str2[] = "[0 1 1 0 0 0] concat\n\
+revision 300 lt{(\347\310\375) print flush}if\n\
+stop\n%%xdvimark\n";
+
+ /*
+ * If we're prescanning *before* setting up the widgets (to get the
+ * page size, for example), then postpone starting up ghostscript.
+ */
+
+ if (mane.win == (Window) 0) {
+ if (debug & DBG_PS)
+ Puts("Hit PS header in early prescan; postponing.");
+ psp = no_ps_procs;
+ gs_postpone_prescan = True;
+ return True;
+ }
+
+ if (debug & DBG_PS)
+ Puts("Running initGS ...");
+
+ gs_atom = XInternAtom(DISP, "GHOSTVIEW", False);
+ /* send bpixmap, orientation, bbox (in pixels), and h & v resolution */
+ Sprintf(buf, "%ld %d 0 0 %u %u 72 72",
+ None, /* bpixmap */
+ Landscape, /* orientation */
+ GS_page_h = page_h, GS_page_w = page_w);
+ XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8,
+ PropModeReplace, (unsigned char *) buf, strlen(buf));
+ GS_alpha = resource.gs_alpha;
+
+ gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False);
+ Sprintf(buf, "%s %ld %ld", resource.gs_palette,
+ fore_color_data.pixel, back_color_data.pixel);
+ XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8,
+ PropModeReplace, (unsigned char *) buf, strlen(buf));
+
+ if (!did_putenv) {
+ Sprintf(buf, "%ld", mane.win);
+ xputenv("GHOSTVIEW", buf);
+ did_putenv = True;
+ }
+
+ XSync(DISP, False); /* update the window */
+
+ if (xpipe(std_io) != 0) {
+ perror("[xdvi] pipe");
+ return False;
+ }
+ Fflush(stderr); /* to avoid double flushing */
+ GS_pid = vfork();
+ if (GS_pid == 0) { /* child */
+ _Xconst char **argvp = argv + 10;
+
+ argv[1] = resource.gs_alpha ? "-sDEVICE=x11alpha" : "-sDEVICE=x11";
+ Sprintf(arg4 + 14, "%u", GS_page_w);
+ Sprintf(arg5 + 15, "%u", GS_page_h);
+ if (resource.gs_safer) *argvp++ = "-dSAFER";
+ *argvp = "-";
+ (void) close(std_io[0]);
+ (void) dup2(std_io[1], 0);
+ (void) dup2(std_io[1], 1);
+ (void) dup2(std_io[1], 2);
+ (void) close(std_io[1]);
+ (void) execvp(argv[0] = resource.gs_path, (char * _Xconst *) argv);
+ Fprintf(stderr, "%s: Execvp of %s failed.\n", prog, argv[0]);
+ Fflush(stderr);
+ _exit(1);
+ }
+ (void) close(std_io[1]);
+ ++n_files_left;
+ if (GS_pid == -1) { /* error */
+ GS_pid = 0;
+ perror("[xdvi] vfork");
+ (void) close(GS_fd);
+ ++n_files_left;
+ return False;
+ }
+
+ prep_fd(GS_fd, True); /* Set file descriptor for non-blocking I/O */
+
+ set_chld(&gs_child);
+
+ psp = gs_procs;
+ GS_active = False;
+ GS_in_header = True;
+ GS_pending = 1;
+ GS_mag = GS_shrink = -1;
+ gs_xio.fd = GS_fd;
+ gs_xio.xio_events = XIO_IN;
+ GS_write_ack = 0;
+ GS_outb_in = GS_outb_out = GS_outb;
+ set_io(&gs_xio);
+ GS_ev_mask = GS_MASK_INIT;
+ (void) signal(SIGPIPE, SIG_IGN);
+
+ if (resource.gs_safer)
+ gs_send(strsafe, sizeof(strsafe) - 1);
+ gs_send(str1, sizeof(str1) - 1);
+ gs_send(psheader, psheaderlen);
+ gs_send(str2, sizeof(str2) - 1);
+ waitack();
+ GS_in_header = False;
+ GS_ev_mask = GS_MASK_NORMAL;
+
+ if (GS_pid == 0) { /* if something happened */
+ destroy_gs();
+ return False;
+ }
+ if (!postscript) toggle_gs(); /* if we got a 'v' already */
+ else {
+ scanned_page = scanned_page_ps = scanned_page_reset;
+ ev_flags |= EV_NEWPAGE; /* ||| redraw the page */
+ longjmp(canit_env, 1);
+ }
+ return True;
+}
+
+static void
+toggle_gs() /* this routine is callable from within read_events(). */
+{
+ if (debug & DBG_PS) Puts("Toggling GS on or off");
+
+ psp.drawbegin = (postscript ? drawbegin_gs : drawbegin_none);
+}
+
+void
+gs_resume_prescan()
+{
+ if (debug & DBG_PS)
+ Puts("Resuming prescan");
+
+ gs_postpone_prescan = False;
+ if (!initGS()) /* this may not return */
+ psp = no_ps_procs;
+}
+
+/* ARGSUSED */
+static void
+gs_died(status)
+ int status;
+{
+ if (debug & DBG_PS) Puts("GS process died");
+ GS_pid = 0;
+ read_from_gs();
+ if (linepos > line) {
+ *linepos = '\0';
+ Printf("gs: %s\n", line);
+ linepos = line;
+ }
+ clear_io(&gs_xio);
+ (void) close(GS_fd);
+ ++n_files_left;
+ scanned_page = scanned_page_ps = scanned_page_reset;
+ GS_active = GS_in_doc = False;
+ GS_pending = 0;
+ ev_flags |= GS_die_ack;
+}
+
+static void
+destroy_gs()
+{
+ if (debug & DBG_PS) Puts("Destroying GS process");
+ if (GS_pid != 0) {
+ if (kill(GS_pid, SIGKILL) < 0 && errno != ESRCH)
+ perror("xdvi destroy_gs");
+ GS_pid = 0;
+ clear_chld(&gs_child);
+ read_from_gs();
+ if (linepos > line) {
+ *linepos = '\0';
+ Printf("gs: %s\n", line);
+ linepos = line;
+ }
+ clear_io(&gs_xio);
+ (void) close(GS_fd);
+ ++n_files_left;
+ scanned_page = scanned_page_ps = scanned_page_reset;
+ }
+ GS_active = GS_in_doc = False;
+ GS_pending = 0;
+}
+
+static void
+deactivate()
+{
+ static _Xconst char str[] = " stop\n%%xdvimark\n";
+ int saved_mask;
+
+ saved_mask = GS_ev_mask;
+ GS_ev_mask = 0;
+ gs_send(str, sizeof(str) - 1);
+ GS_ev_mask = saved_mask;
+
+ GS_active = False;
+}
+
+static void
+interrupt_gs()
+{
+ if (debug & DBG_PS) Puts("Running interrupt_gs()");
+ if (GS_pending <= 0) return; /* nothing to do */
+
+ /*
+ * ||| what I'd really like to do here is cause gs to execute
+ * the interrupt routine in errordict. But so far (gs 2.6.1)
+ * that has not been implemented in ghostscript.
+ */
+
+ if (GS_active)
+ deactivate();
+ waitack();
+}
+
+static void
+endpage_gs()
+{
+ if (debug & DBG_PS) Puts("Running endpage_gs()");
+ if (GS_active) {
+ deactivate();
+ waitack();
+ }
+}
+
+/*
+ * Checks that the GS interpreter is running correctly.
+ */
+
+static void
+checkgs(in_header)
+ Boolean in_header;
+{
+ char buf[150];
+
+ /* For gs 2, we pretty much have to start over to enlarge the window. */
+ if ((GS_old && (page_w > GS_page_w || page_h > GS_page_h))
+ || GS_alpha != resource.gs_alpha)
+ destroy_gs();
+
+ if (GS_pid == 0)
+ (void) initGS();
+
+ if (!GS_active) {
+ /* check whether page_w or page_h have increased */
+ if (page_w > GS_page_w || page_h > GS_page_h) {
+ if (ev_flags & GS_ev_mask)
+ longjmp(canit_env, 1);
+ ++GS_pending;
+ Sprintf(buf, "H mark /HWSize [%d %d] /ImagingBBox [0 0 %d %d] \
+currentdevice putdeviceprops pop\n\
+initgraphics [0 1 1 0 0 0] concat stop\n%%%%xdvimark\n",
+ GS_page_w = page_w, GS_page_h = page_h, page_h, page_w);
+ gs_send(buf, strlen(buf));
+ if (!in_header) {
+ ev_flags |= EV_NEWPAGE; /* ||| redraw the page */
+ longjmp(canit_env, 1);
+ }
+ }
+
+ if (magnification != GS_mag) {
+ if (ev_flags & GS_ev_mask)
+ longjmp(canit_env, 1);
+ ++GS_pending;
+ Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \
+end stop\n%%%%xdvimark\n",
+ GS_mag = magnification);
+ gs_send(buf, strlen(buf));
+ }
+
+ if (mane.shrinkfactor != GS_shrink) {
+ if (ev_flags & GS_ev_mask)
+ longjmp(canit_env, 1);
+ ++GS_pending;
+ Sprintf(buf,
+ "H TeXDict begin %d %d div dup \
+/Resolution X /VResolution X \
+end stop\n%%%%xdvimark\n",
+ pixels_per_inch, GS_shrink = mane.shrinkfactor);
+ gs_send(buf, strlen(buf));
+ }
+ }
+}
+
+static void
+drawbegin_gs(xul, yul, cp)
+ int xul, yul;
+ _Xconst char *cp;
+{
+ char buf[32];
+ static _Xconst char str[] = " TeXDict begin\n";
+
+ checkgs(False);
+
+ if (!GS_active) {
+ if (ev_flags & GS_ev_mask)
+ longjmp(canit_env, 1);
+ ++GS_pending;
+ gs_send(str, sizeof(str) - 1);
+ GS_active = True;
+ }
+
+ /* This allows the X side to clear the page */
+ XSync(DISP, False);
+
+ Sprintf(buf, "%d %d moveto\n", xul, yul);
+ gs_send(buf, strlen(buf));
+ if (debug & DBG_PS)
+ Printf("drawbegin at %d,%d: sending `%s'\n", xul, yul, cp);
+ gs_send(cp, strlen(cp));
+}
+
+static void
+drawraw_gs(cp)
+ _Xconst char *cp;
+{
+ if (!GS_active)
+ return;
+ if (debug & DBG_PS) Printf("raw ps sent to context: %s\n", cp);
+ gs_send(cp, strlen(cp));
+ gs_send("\n", 1);
+}
+
+static void
+drawfile_gs(cp, f)
+ _Xconst char *cp;
+ FILE *f;
+{
+ Fclose(f); /* don't need it */
+ ++n_files_left;
+
+ if (!GS_active)
+ return;
+
+ if (debug & DBG_PS) Printf("printing file %s\n", cp);
+
+ gs_send("(", 1);
+ gs_send(cp, strlen(cp));
+ gs_send(")run\n", 5);
+}
+
+static void
+drawend_gs(cp)
+ _Xconst char *cp;
+{
+ if (!GS_active)
+ return;
+ if (debug & DBG_PS) Printf("end ps: %s\n", cp);
+ gs_send(cp, strlen(cp));
+ gs_send("\n", 1);
+}
+
+static void
+beginheader_gs()
+{
+ static _Xconst char str[] = "Hsave /xdvi$doc exch def\n";
+
+ if (debug & DBG_PS) Puts("Running beginheader_gs()");
+
+ checkgs(True);
+
+ if (GS_active) {
+ if (!GS_in_header)
+ oops("Internal error in beginheader_gs().\n");
+ return;
+ }
+
+ if (ev_flags & GS_ev_mask)
+ longjmp(canit_env, 1);
+
+ GS_in_header = True;
+ GS_ev_mask = GS_MASK_HEADER;
+ ++GS_pending;
+ if (GS_in_doc)
+ gs_send("H", 1);
+ else {
+ gs_send(str, sizeof(str) - 1);
+ GS_in_doc = True;
+ }
+ GS_active = True;
+}
+
+static void
+endheader_gs()
+{
+ if (debug & DBG_PS) Puts("Running endheader_gs()");
+
+ if (GS_active) {
+ deactivate();
+ waitack();
+ GS_in_header = False;
+ GS_ev_mask = GS_MASK_NORMAL;
+ }
+}
+
+static void
+newdoc_gs()
+{
+ static _Xconst char str[] =
+ "Hxdvi$doc restore stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) Puts("Running newdoc_gs()");
+
+ if (GS_in_doc) {
+ ++GS_pending;
+ gs_send(str, sizeof(str) - 1);
+ GS_mag = GS_shrink = -1;
+ GS_in_doc = False;
+
+ if (!GS_old) GS_page_w = GS_page_h = 0;
+ }
+}
diff --git a/psheader.txt b/psheader.txt
@@ -0,0 +1,297 @@
+%% These are from tex.lpro
+/TeXDict 250 dict def % define a working dictionary ( IBM: color - 200->250 )
+TeXDict begin % start using it.
+/N {def} def
+/B {bind def} N
+/S {exch} N
+/X { S N } B
+/TR {translate} N
+/vsize 11 72 mul N
+end % TeXDict
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% header for the \special command
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% The structure of the PostScript produced by dvips for \special is:
+% @beginspecial
+% - any number of @hsize, @hoffset, @hscale, etc., commands
+% @setspecial
+% - the user's file of PostScript commands
+% @endspecial
+
+TeXDict begin
+/SDict 200 dict N
+SDict begin
+
+/@SpecialDefaults
+ { /hs 612 N
+ /vs 792 N
+ /ho 0 N
+ /vo 0 N
+ /hsc 1 N
+ /vsc 1 N
+ /ang 0 N
+ /CLIP 0 N
+ /rwiSeen false N
+ /rhiSeen false N
+ /letter {} N /note {} N /a4 {} N /legal {} N
+ } B
+
+%
+% The following definition sets up the units that hscale/vscale are in.
+% For certain sites this might require change, but it is
+% recommended instead that any macro packages that require
+% hscale/vscale set the units appropriately via
+%
+% \special{! /@scaleunit 1 def }
+%
+% if global, or
+%
+% \special{" /@scaleunit 1 def }
+%
+% before each instance if multiple macro packages with
+% different requirements are being used.
+%
+/@scaleunit 100 N
+% s @hscale - set scale factor
+/@hscale {@scaleunit div /hsc X} B
+/@vscale {@scaleunit div /vsc X} B
+
+% d @hsize - specify a horizontal clipping dimension
+/@hsize {/hs X /CLIP 1 N} B
+/@vsize {/vs X /CLIP 1 N} B
+
+/@clip {/CLIP 2 N} B
+
+% d @hoffset - specify a shift for the figure
+/@hoffset {/ho X} B
+/@voffset {/vo X} B
+
+% a @angle - set rotation angle
+/@angle {/ang X} B
+
+%
+% Here we handle bounding box calculations, if necessary.
+%
+/@rwi { 10 div /rwi X /rwiSeen true N } B % rwi will be real width after scaling
+/@rhi { 10 div /rhi X /rhiSeen true N } B % rhi will be real height after scaling
+/@llx { /llx X } B
+/@lly { /lly X } B
+/@urx { /urx X } B
+/@ury { /ury X } B
+
+/magscale true def
+
+end % of SDict
+
+/@MacSetUp
+ { userdict /md known % if md is defined
+ { userdict /md get type /dicttype eq % and if it is a dictionary
+ {
+ userdict begin % expand it if necessary
+ md length 10 add md maxlength ge
+ {/md md dup length 20 add dict copy def}if
+ end
+ md begin % then redefine some stuff
+ /letter {} N
+ /note {} N
+ /legal {} N
+ /od{txpose
+ 1 0 mtx defaultmatrix dtransform S atan/pa X
+ newpath clippath mark
+ {transform{itransform moveto}}
+ {transform{itransform lineto}}
+ { 6 -2 roll transform
+ 6 -2 roll transform
+ 6 -2 roll transform
+ { itransform 6 2 roll
+ itransform 6 2 roll
+ itransform 6 2 roll
+ curveto
+ }
+ }
+ {{closepath}}
+ pathforall newpath counttomark array astore /gc xdf
+ pop ct 39 0 put
+ 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if
+ }N
+ /txpose{
+ pxs pys scale ppr aload pop
+ por {
+ noflips {
+ pop S neg S TR pop 1 -1 scale
+ }if
+ xflip yflip and {
+ pop S neg S TR 180 rotate 1 -1 scale
+ ppr 3 get ppr 1 get neg sub neg ppr 2 get
+ ppr 0 get neg sub neg TR
+ }if
+ xflip yflip not and {
+ pop S neg S TR pop 180 rotate
+ ppr 3 get ppr 1 get neg sub neg 0 TR
+ }if
+ yflip xflip not and {
+ ppr 1 get neg ppr 0 get neg TR
+ }if
+ }
+ {
+ noflips {
+ TR pop pop 270 rotate 1 -1 scale
+ }if
+ xflip yflip and {
+ TR pop pop 90 rotate 1 -1 scale
+ ppr 3 get ppr 1 get neg sub neg ppr 2 get
+ ppr 0 get neg sub neg TR
+ }if
+ xflip yflip not and {
+ TR pop pop 90 rotate ppr 3 get
+ ppr 1 get neg sub neg 0 TR
+ }if
+ yflip xflip not and {
+ TR pop pop 270 rotate ppr 2 get
+ ppr 0 get neg sub neg 0 S TR
+ }if
+ }ifelse
+ scaleby96 {
+ ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy
+ TR .96 dup scale neg S neg S TR
+ }if
+ }N
+ /cp {pop pop showpage pm restore}N
+ end
+ }if
+ } if
+ } N
+
+%
+% The following procedure brings us back to PostScript size. It takes
+% into account the current global dvi magnification, so graphics
+% scale with the document.
+%
+/normalscale {
+ Resolution 72 div VResolution 72 div neg scale
+ magscale { DVImag dup scale } if
+ 0 setgray
+} N
+%
+% We need the psfig macros.
+%
+% All software, documentation, and related files in this distribution of
+% psfig/tex are Copyright (c) 1987 Trevor J. Darrell
+%
+% Permission is granted for use and non-profit distribution of psfig/tex
+% providing that this notice be clearly maintained, but the right to
+% distribute any portion of psfig/tex for profit or as part of any commercial
+% product is specifically reserved for the author.
+%
+%
+% psfigTeX PostScript Prolog
+% $Header: /cvsroot/xdvi/xdvi/psheader.txt,v 1.80 2008/04/02 18:56:15 vojta Exp $
+%
+/psfts { S 65781.76 div N } N
+
+% x y bb-llx bb-lly bb-urx bb-ury startTexFig -
+/startTexFig {
+ /psf$SavedState save N
+ userdict maxlength dict begin
+
+ /magscale true def
+ normalscale
+ currentpoint TR %set the current point as the user's origin
+
+ /psf$ury psfts
+ /psf$urx psfts
+ /psf$lly psfts
+ /psf$llx psfts
+ /psf$y psfts
+ /psf$x psfts
+
+ /psf$sx psf$x psf$urx psf$llx sub div N % scaling for x
+ /psf$sy psf$y psf$ury psf$lly sub div N % scaling for y
+
+ psf$sx psf$sy scale % scale by (sx,sy)
+
+ psf$llx neg psf$ury neg TR
+
+ /showpage {
+ } N
+ /erasepage {
+ } N
+ /copypage {
+ } N
+ /p 3 def % necessary to get around a bug in Adobe Illustrator
+ @MacSetUp
+} N
+
+% llx lly urx ury doclip - (args in figure coordinates)
+/doclip {
+ psf$llx psf$lly psf$urx psf$ury
+ currentpoint 6 2 roll
+ newpath 4 copy
+ 4 2 roll moveto
+ 6 -1 roll S lineto
+ S lineto
+ S lineto
+ closepath clip
+ newpath
+ moveto
+} N
+% - endTexFig -
+/endTexFig { end psf$SavedState restore } N
+
+% this will be invoked as the result of a \special command (for the
+% inclusion of PostScript graphics). The basic idea is to change all
+% scaling and graphics back to defaults, but to shift the origin
+% to the current position on the page.
+
+/@beginspecial % - @beginspecial - -- enter special mode
+ { SDict begin
+ /SpecialSave save N
+ gsave
+ normalscale
+ currentpoint TR %set the current point as the user's origin
+ @SpecialDefaults % setup default offsets, scales, sizes, and angle
+ count /ocount X /dcount countdictstack N
+ } N
+
+/@setspecial % to setup user specified offsets, scales, sizes (for clipping)
+ {
+ CLIP 1 eq
+ { newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
+ closepath clip }
+ if
+ ho vo TR
+ hsc vsc scale
+ ang rotate
+ rwiSeen {
+ rwi urx llx sub div
+ rhiSeen { rhi ury lly sub div } { dup } ifelse
+ scale llx neg lly neg TR
+ } {
+ rhiSeen { rhi ury lly sub div dup scale llx neg lly neg TR } if
+ } ifelse
+ CLIP 2 eq
+ { newpath llx lly moveto urx lly lineto urx ury lineto llx ury lineto
+ closepath clip }
+ if
+ /showpage {} N
+ /erasepage {} N
+ /copypage {} N
+ newpath
+ } N
+
+/@endspecial % - @endspecial - -- leave special mode
+ { count ocount sub {pop} repeat
+ countdictstack dcount sub {end} repeat
+ grestore SpecialSave restore
+ end
+ } N
+/@defspecial
+ {
+ SDict begin
+ } N
+/@fedspecial
+ {
+ end
+ } B
+end % revert to previous dictionary
diff --git a/psnews.c b/psnews.c
@@ -0,0 +1,923 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2002 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTES:
+ This code was originally written by Ricardo Telichevesky
+ (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
+ (lms@rle-vlsi-mit.edu).
+ It was largely influenced by similar code in the SeeTeX/XTeX
+ package by Dirk Grunwald (grunwald@colorado.edu).
+
+\*========================================================================*/
+
+/* ||| To do:
+ * ALWAYS_CLOSE_SERVER_CONNECTION?
+ * Is there some way of interrupting a process?
+ * fork
+ * extra bytes on input
+ */
+
+#include "xdvi.h"
+#include <memory.h>
+#include <signal.h>
+#include <sys/file.h> /* this defines FASYNC */
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <NeWS/psio.h>
+#include <xvps/pscanvas.h>
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#endif
+
+/* Condition for retrying a write */
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef EWOULDBLOCK
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+#else /* EAGAIN */
+#define AGAIN_CONDITION (errno == EWOULDBLOCK)
+#endif /* EAGAIN */
+#else /* EWOULDBLOCK */
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EAGAIN)
+#endif /* EAGAIN */
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+/* Linux prefers O_ASYNC over FASYNC; SGI IRIX does the opposite. */
+#if !defined(FASYNC) && defined(O_ASYNC)
+#define FASYNC O_ASYNC
+#endif
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+#define FLAKY_SIGPOLL 1
+#endif
+
+char *strtok ARGS((char *, _Xconst char *));
+
+#define Fprintf (void) fprintf
+
+
+/* define ALWAYS_CLOSE_SERVER_CONNECTION if you want to close the server
+ connection all the time */
+#undef ALWAYS_CLOSE_SERVER_CONNECTION
+
+
+ /*
+ * Some setup code.
+ */
+static _Xconst char str0[] = "\
+/OW2? version cvi 2 eq def \
+OW2? \
+{ /setlinewidth { pop } def} \
+{ /NeWS 3 0 findpackage beginpackage \
+ /X11 3 0 findpackage beginpackage} \
+ifelse \
+currentcanvas /Color get \
+currentcanvas /Colormap get getcubedescription null eq and \
+ {8 {{currentcanvas /Colormap get 1 index dup dup dup newcube} stopped \
+ {pop pop pop pop pop} {exit} ifelse \
+ 2 div cvi dup 1 eq {exit} if} loop pop} \
+if\n";
+ /*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ */
+static _Xconst char preamble[] = "\
+/xdvi$line 81 string def \
+/xdvi$run {$error null ne {$error /newerror false put} if \
+ {currentfile cvx stopped \
+ $error null eq {false} {$error /newerror get} ifelse and \
+ {handleerror} if} stopped pop} def \
+/xdvi$dslen countdictstack def \
+{currentfile read not {exit} if 72 eq \
+ {xdvi$run} \
+ {/xdvi$sav save def xdvi$run \
+ clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} \
+ ifelse \
+ {(%%xdvimark) currentfile xdvi$line {readline} stopped \
+ {clear} {{eq {false exit} if} {true exit} ifelse} ifelse }loop {exit} if \
+ 58 tagprint flush \
+}loop\nH";
+
+extern _Xconst char psheader[];
+extern unsigned psheaderlen;
+
+static _Xconst char preamble2[] = " stop\n%%xdvimark\n";
+#define stopstring preamble2
+
+#define postscript resource._postscript
+
+
+/* global procedures (besides initNeWS) */
+
+static void toggleNeWS ARGS((void));
+static void destroyNeWS ARGS((void));
+static void interruptNeWS ARGS((void));
+static void endpageNeWS ARGS((void));
+static void drawbeginNeWS ARGS((int, int, _Xconst char *));
+static void drawrawNeWS ARGS((_Xconst char *));
+static void drawfileNeWS ARGS((_Xconst char *, FILE *));
+static void drawendNeWS ARGS((_Xconst char *));
+static void beginheaderNeWS ARGS((void));
+static void endheaderNeWS ARGS((void));
+static void newdocNeWS ARGS((void));
+
+static struct psprocs news_procs = {
+ /* toggle */ toggleNeWS,
+ /* destroy */ destroyNeWS,
+ /* interrupt */ interruptNeWS,
+ /* endpage */ endpageNeWS,
+ /* drawbegin */ drawbeginNeWS,
+ /* drawraw */ drawrawNeWS,
+ /* drawfile */ drawfileNeWS,
+ /* drawend */ drawendNeWS,
+ /* beginheader */ beginheaderNeWS,
+ /* endheader */ endheaderNeWS,
+ /* newdoc */ newdocNeWS};
+
+/* define local static variables */
+static int NeWS_mag; /* magnification currently in use */
+static int NeWS_shrink; /* shrink factor currently in use */
+static unsigned int NeWS_page_w; /* how big our current page is */
+static unsigned int NeWS_page_h;
+static Boolean NeWS_active; /* if we've started a page yet */
+static int NeWS_pending; /* number of ack's we're expecting */
+static _Xconst char *NeWS_send_byte; /* next byte to send to NeWS */
+static _Xconst char *NeWS_send_end; /* last + 1 byte to send */
+static Boolean NeWS_in_header; /* if we're sending a header */
+static Boolean NeWS_in_doc; /* if we've sent header information */
+static int NeWS_ev_mask; /* events for which we'll stop */
+static Boolean NeWS_destroyed = False;
+
+#define NEWS_MASK_NORMAL EV_GE_NEWPAGE
+#define NEWS_MASK_HEADER EV_GE_PS_TOGGLE
+#define NEWS_MASK_INIT (EV_GE_TERM | EV_PS_TOGGLE)
+
+
+/*
+ * NeWS I/O code. This should send PS code to NeWS,
+ * receive acknowledgements, and receive X events in the meantime.
+ * It also checks for SIGPIPE errors.
+ */
+
+static void read_from_NeWS ARGS((void));
+static void write_to_NeWS ARGS((void));
+
+static struct xio NeWS_xout = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_NeWS, write_to_NeWS};
+
+static struct xio NeWS_xin = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_NeWS, NULL};
+
+
+/*---------------------------------------------------------------------------*
+ psio_sigpipe_handler ()
+
+ Arguments: sig, code, scp, addr (see man page for signal)
+ Returns: (void)
+ Side-Effects: SIGPIPE signal is flagged as sigpipe_error variable is set.
+
+ Description:
+ Handler for SIGPIPE error generated by a broken pipe in the connection
+ to the NeWS server; this may be duer to some abnormal condition, or some
+ hairy PostScript code containing commands not implemented by the server.
+
++----------------------------------------------------------------------------*/
+
+static Boolean sigpipe_error = False;
+
+static struct sigaction psio_sigpipe_handler_struct;
+ /* initialized to {psio_sigpipe_handler, (sigset_t) 0, 0} in initNeWS */
+
+/* ARGSUSED */
+static RETSIGTYPE
+psio_sigpipe_handler(sig, code, scp, addr)
+ int sig;
+ int code;
+ struct sigcontext *scp;
+ char *addr;
+{
+ sigpipe_error = True;
+}
+
+
+/*
+ * read_from_NeWS - This does the actual retrieving of acknowledgements.
+ * If other bytes appear on the file - tough.
+ */
+
+static void
+read_from_NeWS()
+{
+ for (;;) {
+ int retval;
+
+ retval = ps_checkfor(PostScriptInput, PSIO_FIND_TAG, 58);
+ if (retval == 0) break;
+ if (retval < 0) {
+ WARN1(XmDIALOG_WARNING,
+ "xdvi internal error\nps_checkfor returned negative value %d",
+ retval);
+ return;
+ }
+ (void) ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 58);
+ --NeWS_pending;
+ if (NeWS_pending == 0)
+ ev_flags |= EV_ACK;
+ if (debug & DBG_PS)
+ Printf("Got NeWS ack; %d pending.\n", NeWS_pending);
+ }
+}
+
+
+/*
+ * write_to_NeWS - Write to the PostScript interpreter.
+ */
+
+static void
+write_to_NeWS()
+{
+ int old_flags;
+ int bytes;
+
+ old_flags = fcntl(PostScript->file, F_GETFL, 0);
+ if (old_flags < 0) return;
+ /* set to be non-blocking */
+ if (fcntl(PostScript->file, F_SETFL, old_flags | O_NONBLOCK) < 0)
+ return;
+
+ for (;;) {
+ bytes = write(PostScript->file, NeWS_send_byte,
+ NeWS_send_end - NeWS_send_byte);
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi NeWS_send");
+ break;
+ }
+ NeWS_send_byte += bytes;
+ if (NeWS_send_byte == NeWS_send_end) {
+ NeWS_send_byte = NULL;
+ NeWS_xout.xio_events &= ~XIO_OUT;
+#if HAVE_POLL
+ /* This check is necessary, since write_to_NeWS can be called
+ directly. */
+ if (NeWS_xout.pfd != NULL)
+ NeWS_xout.pfd->events &= ~POLLOUT;
+ ev_flags |= EV_ACK;
+ break;
+#endif
+ }
+ }
+
+ fcntl(PostScript->file, F_SETFL, old_flags);
+}
+
+
+/*
+ * Clean up after NeWS_send()
+ */
+
+static void
+post_send()
+{
+ if (sigpipe_error) {
+ WARN(XmDIALOG_WARNING, "NeWS died unexpectedly");
+ destroyNeWS();
+ draw_bbox();
+ }
+}
+
+
+/*
+ * Main routine for writing to the NeWS interpreter.
+ */
+
+static void
+NeWS_send(cp, len)
+ _Xconst char *cp;
+ size_t len;
+{
+ struct sigaction orig;
+
+ if (PostScript == (PSFILE *) NULL || (ev_flags & NeWS_ev_mask))
+ return;
+
+ (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
+ sigpipe_error = False;
+
+ NeWS_send_byte = cp;
+ NeWS_send_end = cp + len;
+ NeWS_xout.xio_events |= XIO_OUT;
+#if HAVE_POLL
+ if (NeWS_xout.pfd != NULL)
+ NeWS_xout.pfd->events |= POLLOUT;
+#endif
+
+ write_to_NeWS();
+ (void) read_events(NeWS_ev_mask | EV_ACK);
+
+ if (!(ev_flags & EV_ACK)) { /* if interrupted */
+ /* ||| Do somthing more severe here */
+ }
+
+ ev_flags &= ~EV_ACK;
+
+ /* put back generic handler for SIGPIPE */
+ (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
+
+ if (!NeWS_in_header) post_send();
+}
+
+/*
+ * Wait for acknowledgement from NeWS. With NeWS we have no choice but
+ * to wait (||| I think).
+ */
+
+static void
+waitack()
+{
+ if (PostScript == (PSFILE *) NULL) return;
+
+ if (NeWS_pending > 0)
+ (void) read_events(EV_GE_ACK);
+
+ if (ev_flags & EV_ACK) {
+ ev_flags &= ~EV_ACK;
+ return;
+ }
+
+ /* ||| Do something more serious here */
+}
+
+
+/*---------------------------------------------------------------------------*
+ initNeWS()
+
+ Arguments: None.
+ Returns: True if and only if initialization succeeded
+ Side-Effects: Static variables may be set.
+
+ Description:
+ Initializes variables for the application main loop.
+
++----------------------------------------------------------------------------*/
+
+Boolean
+initNeWS()
+{
+ static NeWStoken newstoken;
+
+ /* now try to open the connection to the NeWS server */
+ if (ps_open_PostScript() == (PSFILE *) NULL)
+ return False;
+
+ psio_sigpipe_handler_struct.sa_handler = psio_sigpipe_handler;
+ sigemptyset(&psio_sigpipe_handler_struct.sa_mask);
+
+#if !FLAKY_SIGPOLL
+ if (fcntl(PostScript->file, F_SETOWN, getpid()) == -1)
+ perror("xdvi: fcntl F_SETOWN");
+ if (fcntl(PostScript->file, F_SETFL,
+ fcntl(PostScript->file, F_GETFL, 0) | FASYNC) == -1)
+ perror("xdvi: fcntl F_SETFL");
+#endif /* not FLAKY_SIGPOLL */
+ if (PostScriptInput->file != PostScript->file) {
+#if !FLAKY_SIGPOLL
+ if (fcntl(PostScriptInput->file, F_SETOWN, getpid()) == -1)
+ perror("xdvi: fcntl F_SETOWN");
+ if (fcntl(PostScriptInput->file, F_SETFL,
+ fcntl(PostScriptInput->file, F_GETFL, 0) | FASYNC) == -1)
+ perror("xdvi: fcntl F_SETFL");
+#endif /* not FLAKY_SIGPOLL */
+ NeWS_xout.xio_events &= ~XIO_IN;
+ NeWS_xin.fd = PostScriptInput->file;
+ set_io(&NeWS_xin);
+ }
+ NeWS_xout.fd = PostScript->file;
+ set_io(&NeWS_xout);
+
+ NeWS_active = False;
+ NeWS_in_header = True;
+ NeWS_ev_mask = NEWS_MASK_INIT;
+ NeWS_pending = 1;
+
+ ps_flush_PostScript();
+ NeWS_send(str0, sizeof(str0) - 1);
+ /* get xid of window, then make this window the NeWS canvas */
+ (void) ps_token_from_xid(mane.win, &newstoken);
+ if (newstoken != -1) {
+ ps_setcanvas(newstoken);
+ ps_flush_PostScript();
+
+ NeWS_send(preamble, sizeof(preamble) - 1);
+ NeWS_send(psheader, psheaderlen);
+ NeWS_send(preamble2, sizeof(preamble2) - 1);
+ NeWS_in_header = False;
+ post_send();
+ waitack();
+ }
+
+ if (NeWS_destroyed) return False;
+
+ /* success */
+
+ NeWS_mag = NeWS_shrink = -1;
+ NeWS_page_w = page_w;
+ NeWS_page_h = page_h;
+
+ psp = news_procs;
+ if (!postscript) toggleNeWS(); /* if we got a 'v' already */
+
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ toggleNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: psp.drawbegin is changed
+
+ Description:
+ Used to toggle the rendering of PostScript by the NeWS server
+ Callable from within read_events().
+
++----------------------------------------------------------------------------*/
+
+static void
+toggleNeWS()
+{
+ if (debug & DBG_PS) Puts("Toggling NeWS on or off");
+
+ psp.drawbegin = (postscript ? drawbeginNeWS : drawbegin_none);
+}
+
+
+/*---------------------------------------------------------------------------*
+ destroyNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the pointer to the NeWS file is nulled
+
+ Description:
+ Close the connection to the NeWS server; used when rendering is terminated
+ in any way.
+
++----------------------------------------------------------------------------*/
+
+static void
+destroyNeWS()
+{
+ psp = no_ps_procs;
+ NeWS_destroyed = True;
+ scanned_page = scanned_page_ps = scanned_page_reset;
+}
+
+
+/*---------------------------------------------------------------------------*
+ interruptNeWS()
+
+ Arguments: none
+ Returns: void
+
+ Description:
+ Close the connection to the NeWS server; used when rendering is terminated
+ because of an interruption in the viewing of the current page.
+ ||| It would be nice if we could asynchronously ``wake up'' a NeWS process
+ (preferably by sending something along the X socket); then we could do
+ better than just to wait.
+
++----------------------------------------------------------------------------*/
+
+static void
+interruptNeWS()
+{
+ if (debug & DBG_PS) Puts("Running interruptNeWS()");
+ if (NeWS_pending <= 0) return; /* if nothing to do */
+
+ if (NeWS_active) {
+ NeWS_send(stopstring, sizeof(stopstring) - 1);
+ NeWS_active = False;
+ }
+
+ for (;;) {
+ ps_flush_PostScript();
+ if (NeWS_pending <= 0) break;
+ waitack();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ endpageNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the NeWS_active variable is cleared.
+
+ Description:
+ Should be called at the end of a page to end this chunk for the NeWS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+endpageNeWS()
+{
+ if (debug & DBG_PS)
+ Puts("endpage sent to NeWS Server");
+ if (NeWS_active) {
+ NeWS_send(stopstring, sizeof(stopstring) - 1);
+ NeWS_active = False;
+ waitack();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawbeginNeWS ()
+
+ Arguments: xul, yul - coordinates of the upper left corner of the figure
+ cp - string with the bounding box line data
+ Returns: (void)
+
+ Description:
+ Opens a connection to the NeWS server and send in the preamble and the
+ bounding box information after correctly computing resolution factors.
+ In case no rendering is to be done, outlines the figure. An outline is
+ also generated whenever the PostScript code is too hairy and generates
+ a SIGPIPE signal.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawbeginNeWS(xul, yul, cp)
+ int xul, yul;
+ _Xconst char *cp;
+{
+ char buf[100];
+ static _Xconst char str[] = " TeXDict begin\n";
+ static _Xconst char str2[] = "Hinitgraphics stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) {
+ Printf("xul= %d yul= %d\n", xul, yul);
+ Printf("String = < %s >\n", cp);
+ }
+
+ /* catch up on the X side */
+ XSync(DISP, False);
+
+ if (!NeWS_active) {
+ /* send initialization to NeWS server */
+ if (NeWS_page_w < page_w || NeWS_page_h < page_h) {
+ if (ev_flags & NEWS_MASK_NORMAL)
+ longjmp(canit_env, 1);
+ ++NeWS_pending;
+ NeWS_page_w = page_w;
+ NeWS_page_h = page_h;
+ NeWS_send(str2, sizeof(str2) - 1);
+ }
+ if (magnification != NeWS_mag) {
+ if (ev_flags & NEWS_MASK_NORMAL)
+ longjmp(canit_env, 1);
+ ++NeWS_pending;
+ Sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def \
+end stop\n%%%%xdvimark\n",
+ NeWS_mag = magnification);
+ NeWS_send(buf, strlen(buf));
+ }
+ if (mane.shrinkfactor != NeWS_shrink) {
+ if (ev_flags & NEWS_MASK_NORMAL)
+ longjmp(canit_env, 1);
+ ++NeWS_pending;
+ Sprintf(buf, "H TeXDict begin %d %d div dup \
+/Resolution X /VResolution X \
+end stop\n%%%%xdvimark\n",
+ pixels_per_inch, NeWS_shrink = mane.shrinkfactor);
+ NeWS_send(buf, strlen(buf));
+ }
+ if (ev_flags & NEWS_MASK_NORMAL)
+ longjmp(canit_env, 1);
+ ++NeWS_pending;
+ NeWS_send(str, sizeof(str) - 1);
+ NeWS_active = True;
+ }
+
+ Sprintf(buf, "%d %d moveto\n", xul, yul);
+ NeWS_send(buf, strlen(buf));
+ NeWS_send(cp, strlen(cp));
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawrawNeWS()
+
+ Arguments: origcp - the raw string to be sent to the postscript interpreter
+ Returns: (void)
+ Side-Effects: (none)
+
+ Description:
+ If there is a valid connection to the NeWS server, just send the string to
+ the interpreter, else leave.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawrawNeWS(origcp)
+ _Xconst char *origcp;
+{
+ _Xconst char *pt, *ptm1, *ocp1;
+ static char *cp;
+ char *cp1;
+ static unsigned int cplen = 0;
+ unsigned int len;
+ double angle;
+ Boolean found = False;
+
+ if (!NeWS_active)
+ return;
+
+ if (debug & DBG_PS)
+ Printf("Raw PS sent to context: <%s>\n", origcp);
+
+ /* take a look at the string: NeWS bums on certain rotations */
+ len = strlen(origcp) + 4;
+ if (cplen < len) {
+ if (cplen != 0) free(cp);
+ cplen = len;
+ cp = xmalloc(cplen);
+ }
+ ocp1 = origcp;
+ pt = origcp;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ cp1 = cp;
+ for (;;) {
+ ptm1 = pt;
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ if (*pt == '\0') break;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ if (strncmp(pt, "rotate", 6) == 0
+ && (pt[6] == '\0' || pt[6] == ' ' || pt[6] == '\t')) {
+ /* found rotate; check angle */
+ if (sscanf(ptm1, "%lf", &angle) >= 1) {
+ found = True;
+ while (angle > 360.0)
+ angle -= 360;
+ while (angle < -360.0)
+ angle += 360;
+ if (angle == 90.0) {
+ angle = 89.999;
+ (void) memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ Strcpy(cp1, "89.999 rotate ");
+ cp1 += strlen(cp1);
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ ocp1 = pt;
+ } else if (angle == -90.0) {
+ angle = -89.999;
+ (void) memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ Strcpy(cp1, "-89.999 rotate ");
+ cp1 += strlen(cp1);
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ ocp1 = pt;
+ } else if (angle == 0.0) {
+ (void) memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t') ++pt;
+ while (*pt == ' ' || *pt == '\t') ++pt;
+ ocp1 = pt;
+ }
+ }
+ }
+ }
+ Strcpy(cp1, ocp1);
+ if ((debug & DBG_PS) && found) {
+ Printf("String is now <%s>\n", cp);
+ Printf("Found rotate string. Angle is %g degrees.\n", angle);
+ }
+
+ len = strlen(cp);
+ cp[len] = '\n';
+ NeWS_send(cp, len + 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawfileNeWS()
+
+ Arguments: cp - string with the postscript file pathname
+ psfile - file, already opened
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Postscript file containing the figure is opened and sent to the NeWS server.
+ Figure is outlined in case hairy code produces a SIGPIPE signal.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawfileNeWS(cp, psfile)
+ _Xconst char *cp;
+ FILE *psfile;
+{
+ char buffer[1025];
+ int blen;
+ struct sigaction orig;
+
+ if (!NeWS_active) {
+ Fclose(psfile);
+ ++n_files_left;
+ return;
+ }
+
+ if (debug & DBG_PS)
+ Printf("printing file %s\n", cp);
+
+ sigpipe_error = False;
+ for (;;) {
+ blen = fread(buffer, sizeof(char), 1024, psfile);
+ if (blen == 0) break;
+ NeWS_send(buffer, blen);
+ if (sigpipe_error || (ev_flags & NeWS_ev_mask))
+ break;
+ }
+ Fclose(psfile);
+ ++n_files_left;
+
+ if (sigpipe_error) {
+ WARN(XmDIALOG_WARNING, "NeWS died unexpectedly");
+ destroyNeWS();
+ draw_bbox();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawendNeWS()
+
+ Arguments: cp - string with indication of the end of the special
+ Returns: (void)
+
+ Description:
+ Sends the indication of end of the figure PostScript code.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawendNeWS(cp)
+ _Xconst char *cp;
+{
+ if (!NeWS_active)
+ return;
+
+ if (debug & DBG_PS)
+ Puts("drawend sent to NeWS Server");
+ NeWS_send(cp, strlen(cp));
+ NeWS_send("\n", 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ beginheaderNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+beginheaderNeWS()
+{
+ static _Xconst char str[] = "Hsave /xdvi$doc exch def\n";
+
+ if (debug & DBG_PS) Puts("Running beginheaderNeWS()");
+
+ if (NeWS_active) {
+ if (!NeWS_in_header)
+ oops("Internal error in beginheaderNeWS().\n");
+ return;
+ }
+
+ if (ev_flags & NEWS_MASK_HEADER)
+ longjmp(canit_env, 1);
+
+ NeWS_in_header = True;
+ NeWS_ev_mask = NEWS_MASK_HEADER;
+ ++NeWS_pending;
+ if (NeWS_in_doc)
+ NeWS_send("H", 1);
+ else {
+ NeWS_send(str, sizeof(str) - 1);
+ NeWS_in_doc = True;
+ }
+ NeWS_active = True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ endheaderNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+endheaderNeWS()
+{
+ static _Xconst char str[] = "stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) Puts("Running endheaderNeWS()");
+
+ if (NeWS_active) {
+ NeWS_send(str, sizeof(str) - 1);
+ NeWS_active = False;
+ post_send();
+ waitack();
+ NeWS_in_header = False;
+ NeWS_ev_mask = NEWS_MASK_NORMAL;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ newdocNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Clears out headers stored from the previous document.
+
++----------------------------------------------------------------------------*/
+
+static void
+newdocNeWS()
+{
+ static _Xconst char str[] =
+ "H xdvi$doc restore stop\n%%xdvimark\n";
+
+ if (debug & DBG_PS) Puts("Running newdocNeWS()");
+
+ if (NeWS_in_doc) {
+ ++NeWS_pending;
+ NeWS_send(str, sizeof(str) - 1);
+ NeWS_mag = NeWS_shrink = -1;
+ NeWS_in_doc = False;
+ }
+}
diff --git a/special.c b/special.c
@@ -0,0 +1,2284 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2002 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTE:
+ This module is based on prior work as noted below.
+
+\*========================================================================*/
+
+/*
+ * Support drawing routines for TeXsun and TeX
+ *
+ * Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine
+ * Adapted for xdvi by Jeffrey Lee, U. of Toronto
+ *
+ * At the time these routines are called, the values of hh and vv should
+ * have been updated to the upper left corner of the graph (the position
+ * the \special appears at in the dvi file). Then the coordinates in the
+ * graphics commands are in terms of a virtual page with axes oriented the
+ * same as the Imagen and the SUN normally have:
+ *
+ * 0,0
+ * +-----------> +x
+ * |
+ * |
+ * |
+ * \ /
+ * +y
+ *
+ * Angles are measured in the conventional way, from +x towards +y.
+ * Unfortunately, that reverses the meaning of "counterclockwise"
+ * from what it's normally thought of.
+ *
+ * A lot of floating point arithmetic has been converted to integer
+ * arithmetic for speed. In some places, this is kind-of kludgy, but
+ * it's worth it.
+ */
+
+#include "xdvi.h"
+
+#include <math.h>
+#include <ctype.h>
+
+extern char *strtok ARGS((char *, _Xconst char *));
+extern double floor ARGS((double));
+#define rint(x) floor((x) + 0.5)
+
+#ifdef X_NOT_STDC_ENV
+#ifndef atof
+extern double atof ARGS((_Xconst char *));
+#endif
+
+extern char *getenv ARGS((_Xconst char *));
+#endif /* X_NOT_STDC_ENV */
+
+#if PS
+# if HAVE_VFORK_H
+# include <vfork.h>
+# endif
+
+# include <errno.h>
+
+# if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+# endif
+# ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+# endif
+# ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+# endif
+
+# ifdef X_NOT_STDC_ENV
+extern int errno;
+# endif
+#endif /* PS */
+
+#define MAXPOINTS 300 /* Max points in a path */
+#define MAX_PEN_SIZE 7 /* Max pixels of pen width */
+#define TWOPI (3.14159265359 * 2.0)
+
+
+static int xx[MAXPOINTS], yy[MAXPOINTS]; /* Path in milli-inches */
+static int path_len = 0; /* # points in current path */
+static int pen_size = 1; /* Pixel width of lines drawn */
+
+static Boolean whiten = False;
+static Boolean shade = False;
+static Boolean blacken = False;
+
+/* Unfortunately, these values also appear in dvisun.c */
+#define xRESOLUTION (pixels_per_inch/shrink_factor)
+#define yRESOLUTION (pixels_per_inch/shrink_factor)
+
+
+/*
+ * Issue warning messages
+ */
+
+static void
+Warning(fmt, msg)
+ char *fmt, *msg;
+{
+ Fprintf(stderr, "%s: ", prog);
+ Fprintf(stderr, fmt, msg);
+ (void) fputc('\n', stderr);
+}
+
+
+/*
+ * X drawing routines
+ */
+
+#define toint(x) ((int) ((x) + 0.5))
+#define xconv(x) (toint(tpic_conv*(x))/shrink_factor + PXL_H)
+#define yconv(y) (toint(tpic_conv*(y))/shrink_factor + PXL_V)
+
+/*
+ * Draw a line from (fx,fy) to (tx,ty).
+ * Right now, we ignore pen_size.
+ */
+static void
+line_btw(fx, fy, tx, ty)
+int fx, fy, tx, ty;
+{
+ int fcx = xconv(fx);
+ int tcx = xconv(tx);
+ int fcy = yconv(fy);
+ int tcy = yconv(ty);
+
+ if ((fcx < max_x || tcx < max_x) && (fcx >= min_x || tcx >= min_x) &&
+ (fcy < max_y || tcy < max_y) && (fcy >= min_y || tcy >= min_y)) {
+#if COLOR
+ if (fg_active != fg_current) do_color_change();
+#endif
+ XDrawLine(DISP, currwin.win, ruleGC,
+ fcx - currwin.base_x, fcy - currwin.base_y,
+ tcx - currwin.base_x, tcy - currwin.base_y);
+ }
+}
+
+/*
+ * Draw a dot at (x,y)
+ */
+static void
+dot_at(x, y)
+ int x, y;
+{
+ int cx = xconv(x);
+ int cy = yconv(y);
+
+ if (cx < max_x && cx >= min_x && cy < max_y && cy >= min_y) {
+#if COLOR
+ if (fg_active != fg_current) do_color_change();
+#endif
+ XDrawPoint(DISP, currwin.win, ruleGC,
+ cx - currwin.base_x, cy - currwin.base_y);
+ }
+}
+
+/*
+ * Apply the requested attributes to the last path (box) drawn.
+ * Attributes are reset.
+ * (Not currently implemented.)
+ */
+ /* ARGSUSED */
+static void
+do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y)
+int last_min_x, last_max_x, last_min_y, last_max_y;
+{
+}
+
+/*
+ * Set the size of the virtual pen used to draw in milli-inches
+ */
+
+/* ARGSUSED */
+static void
+set_pen_size(cp)
+ char *cp;
+{
+ int ps;
+
+ if (sscanf(cp, " %d ", &ps) != 1) {
+ Warning("invalid .ps command format: %s", cp);
+ return;
+ }
+ pen_size = (ps * (xRESOLUTION + yRESOLUTION) + 1000) / 2000;
+ if (pen_size < 1) pen_size = 1;
+ else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE;
+}
+
+
+/*
+ * Print the line defined by previous path commands
+ */
+
+static void
+flush_path()
+{
+ int i;
+ int last_min_x, last_max_x, last_min_y, last_max_y;
+
+ last_min_x = 30000;
+ last_min_y = 30000;
+ last_max_x = -30000;
+ last_max_y = -30000;
+ for (i = 1; i < path_len; i++) {
+ if (xx[i] > last_max_x) last_max_x = xx[i];
+ if (xx[i] < last_min_x) last_min_x = xx[i];
+ if (yy[i] > last_max_y) last_max_y = yy[i];
+ if (yy[i] < last_min_y) last_min_y = yy[i];
+ line_btw(xx[i], yy[i], xx[i+1], yy[i+1]);
+ }
+ if (xx[path_len] > last_max_x) last_max_x = xx[path_len];
+ if (xx[path_len] < last_min_x) last_min_x = xx[path_len];
+ if (yy[path_len] > last_max_y) last_max_y = yy[path_len];
+ if (yy[path_len] < last_min_y) last_min_y = yy[path_len];
+ path_len = 0;
+ do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y);
+}
+
+
+/*
+ * Print a dashed line along the previously defined path, with
+ * the dashes/inch defined.
+ */
+
+static void
+flush_dashed(cp, dotted)
+ char *cp;
+ Boolean dotted;
+{
+ int i;
+ int numdots;
+ int lx0, ly0, lx1, ly1;
+ int cx0, cy0, cx1, cy1;
+ float inchesperdash;
+ double d, spacesize, a, b, dx, dy, milliperdash;
+
+ if (sscanf(cp, " %f ", &inchesperdash) != 1) {
+ Warning("invalid format for dotted/dashed line: %s", cp);
+ return;
+ }
+ if (path_len <= 1 || inchesperdash <= 0.0) {
+ Warning("invalid conditions for dotted/dashed line", "");
+ return;
+ }
+ milliperdash = inchesperdash * 1000.0;
+ lx0 = xx[1]; ly0 = yy[1];
+ lx1 = xx[2]; ly1 = yy[2];
+ dx = lx1 - lx0;
+ dy = ly1 - ly0;
+ if (dotted) {
+ numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5;
+ if (numdots == 0) numdots = 1;
+ for (i = 0; i <= numdots; i++) {
+ a = (float) i / (float) numdots;
+ cx0 = lx0 + a * dx + 0.5;
+ cy0 = ly0 + a * dy + 0.5;
+ dot_at(cx0, cy0);
+ }
+ }
+ else {
+ d = sqrt(dx*dx + dy*dy);
+ numdots = d / (2.0 * milliperdash) + 1.0;
+ if (numdots <= 1)
+ line_btw(lx0, ly0, lx1, ly1);
+ else {
+ spacesize = (d - numdots * milliperdash) / (numdots - 1);
+ for (i = 0; i < numdots - 1; i++) {
+ a = i * (milliperdash + spacesize) / d;
+ b = a + milliperdash / d;
+ cx0 = lx0 + a * dx + 0.5;
+ cy0 = ly0 + a * dy + 0.5;
+ cx1 = lx0 + b * dx + 0.5;
+ cy1 = ly0 + b * dy + 0.5;
+ line_btw(cx0, cy0, cx1, cy1);
+ b += spacesize / d;
+ }
+ cx0 = lx0 + b * dx + 0.5;
+ cy0 = ly0 + b * dy + 0.5;
+ line_btw(cx0, cy0, lx1, ly1);
+ }
+ }
+ path_len = 0;
+}
+
+
+/*
+ * Add a point to the current path
+ */
+
+static void
+add_path(cp)
+ char *cp;
+{
+ int pathx, pathy;
+
+ if (++path_len >= MAXPOINTS) oops("Too many points");
+ if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2)
+ oops("Malformed path command");
+ xx[path_len] = pathx;
+ yy[path_len] = pathy;
+}
+
+
+/*
+ * Draw to a floating point position
+ */
+
+static void
+im_fdraw(x, y)
+ double x,y;
+{
+ if (++path_len >= MAXPOINTS) oops("Too many arc points");
+ xx[path_len] = x + 0.5;
+ yy[path_len] = y + 0.5;
+}
+
+
+/*
+ * Draw an ellipse with the indicated center and radices.
+ */
+
+static void
+draw_ellipse(xc, yc, xr, yr)
+ int xc, yc, xr, yr;
+{
+ double angle, theta;
+ int n;
+ int px0, py0, px1, py1;
+
+ angle = (xr + yr) / 2.0;
+ theta = sqrt(1.0 / angle);
+ n = TWOPI / theta + 0.5;
+ if (n < 12) n = 12;
+ else if (n > 80) n = 80;
+ n /= 2;
+ theta = TWOPI / n;
+
+ angle = 0.0;
+ px0 = xc + xr; /* cos(0) = 1 */
+ py0 = yc; /* sin(0) = 0 */
+ while ((angle += theta) <= TWOPI) {
+ px1 = xc + xr*cos(angle) + 0.5;
+ py1 = yc + yr*sin(angle) + 0.5;
+ line_btw(px0, py0, px1, py1);
+ px0 = px1;
+ py0 = py1;
+ }
+ line_btw(px0, py0, xc + xr, yc);
+}
+
+/*
+ * Draw an arc
+ */
+
+static void
+arc(cp, invis)
+ char *cp;
+ Boolean invis;
+{
+ int xc, yc, xrad, yrad, n;
+ float start_angle, end_angle, angle, theta, r;
+ double xradius, yradius, xcenter, ycenter;
+
+ if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad,
+ &start_angle, &end_angle) != 6) {
+ Warning("invalid arc specification: %s", cp);
+ return;
+ }
+
+ if (invis) return;
+
+ /* We have a specialized fast way to draw closed circles/ellipses */
+ if (start_angle <= 0.0 && end_angle >= 6.282) {
+ draw_ellipse(xc, yc, xrad, yrad);
+ return;
+ }
+ xcenter = xc;
+ ycenter = yc;
+ xradius = xrad;
+ yradius = yrad;
+ r = (xradius + yradius) / 2.0;
+ theta = sqrt(1.0 / r);
+ n = 0.3 * TWOPI / theta + 0.5;
+ if (n < 12) n = 12;
+ else if (n > 80) n = 80;
+ n /= 2;
+ theta = TWOPI / n;
+ flush_path();
+ im_fdraw(xcenter + xradius * cos(start_angle),
+ ycenter + yradius * sin(start_angle));
+ angle = start_angle + theta;
+ if (end_angle < start_angle) end_angle += TWOPI;
+ while (angle < end_angle) {
+ im_fdraw(xcenter + xradius * cos(angle),
+ ycenter + yradius * sin(angle));
+ angle += theta;
+ }
+ im_fdraw(xcenter + xradius * cos(end_angle),
+ ycenter + yradius * sin(end_angle));
+ flush_path();
+}
+
+
+/*
+ * APPROXIMATE integer distance between two points
+ */
+
+#define dist(x0, y0, x1, y1) (abs(x0 - x1) + abs(y0 - y1))
+
+
+/*
+ * Draw a spline along the previously defined path
+ */
+
+static void
+flush_spline()
+{
+ int xp, yp;
+ int N;
+ int lastx, lasty;
+ Boolean lastvalid = False;
+ int t1, t2, t3;
+ int steps;
+ int j;
+ int i, w;
+
+#ifdef lint
+ lastx = lasty = -1;
+#endif
+ N = path_len + 1;
+ xx[0] = xx[1];
+ yy[0] = yy[1];
+ xx[N] = xx[N-1];
+ yy[N] = yy[N-1];
+ for (i = 0; i < N - 1; i++) { /* interval */
+ steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) +
+ dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80;
+ for (j = 0; j < steps; j++) { /* points within */
+ w = (j * 1000 + 500) / steps;
+ t1 = w * w / 20;
+ w -= 500;
+ t2 = (750000 - w * w) / 10;
+ w -= 500;
+ t3 = w * w / 20;
+ xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000;
+ yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000;
+ if (lastvalid) line_btw(lastx, lasty, xp, yp);
+ lastx = xp;
+ lasty = yp;
+ lastvalid = True;
+ }
+ }
+ path_len = 0;
+}
+
+
+/*
+ * Shade the last box, circle, or ellipse
+ */
+
+static void
+shade_last()
+{
+ blacken = whiten = False;
+ shade = True;
+}
+
+
+/*
+ * Make the last box, circle, or ellipse, white inside (shade with white)
+ */
+
+static void
+whiten_last()
+{
+ whiten = True;
+ blacken = shade = False;
+}
+
+
+/*
+ * Make last box, etc, black inside
+ */
+
+static void
+blacken_last()
+{
+ blacken = True;
+ whiten = shade = False;
+}
+
+
+/*
+ * Code for PostScript<tm> specials begins here.
+ */
+
+#if PS
+
+/*
+ * Information on how to search for PS header and figure files.
+ */
+
+#include "filf-app.h" /* application-related defs, etc. */
+#include "filefind.h"
+
+static _Xconst char no_f_str_ps[] = "/%f";
+
+static struct findrec search_header = {
+ /* path1 */ NULL,
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ DEFAULT_HEADER_PATH,
+ /* type */ "PS header",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f',
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_ps,
+ /* no_f_str_end */ no_f_str_ps + sizeof(no_f_str_ps) - 1,
+ /* abs_str */ "%f",
+#if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f',
+ /* pk_gf_addr */ NULL,
+#endif
+ /* pct_s_str */ "%qdvips//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+static struct findrec search_fig = {
+ /* path1 */ NULL,
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ DEFAULT_FIG_PATH,
+ /* type */ "PS",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f',
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_ps,
+ /* no_f_str_end */ no_f_str_ps + sizeof(no_f_str_ps) - 1,
+ /* abs_str */ "%f",
+#if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f',
+ /* pk_gf_addr */ NULL,
+#endif
+ /* pct_s_str */ "%qdvips//:%qtex//",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+static void ps_startup ARGS((int, int, _Xconst char *));
+static void ps_startup2 ARGS((void));
+void NullProc ARGS((void)) {}
+static void NullProc2 ARGS((_Xconst char *));
+
+struct psprocs psp = { /* used for lazy startup of the ps machinery */
+ /* toggle */ NullProc,
+ /* destroy */ NullProc,
+ /* interrupt */ NullProc,
+ /* endpage */ NullProc,
+ /* drawbegin */ ps_startup,
+ /* drawraw */ NullProc2,
+ /* drawfile */ NULL,
+ /* drawend */ NullProc2,
+ /* beginheader */ ps_startup2,
+ /* endheader */ NullProc,
+ /* newdoc */ NullProc};
+
+struct psprocs no_ps_procs = { /* used if postscript is unavailable */
+ /* toggle */ NullProc,
+ /* destroy */ NullProc,
+ /* interrupt */ NullProc,
+ /* endpage */ NullProc,
+ /* drawbegin */ drawbegin_none,
+ /* drawraw */ NullProc2,
+ /* drawfile */ NULL,
+ /* drawend */ NullProc2,
+ /* beginheader */ NullProc,
+ /* endheader */ NullProc,
+ /* newdoc */ NullProc};
+
+#endif /* PS */
+
+static Boolean bbox_valid;
+static unsigned int bbox_width;
+static unsigned int bbox_height;
+static int bbox_angle;
+static int bbox_voffset;
+
+void
+draw_bbox()
+{
+ int xcorner, ycorner;
+
+ if (bbox_valid) {
+
+#if COLOR
+ if (fg_active != fg_current) do_color_change();
+#endif
+
+ xcorner = PXL_H - currwin.base_x;
+ ycorner = PXL_V - currwin.base_y;
+
+ if (bbox_angle == 0) {
+ ycorner -= bbox_voffset;
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner, ycorner,
+ xcorner + bbox_width, ycorner);
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner + bbox_width, ycorner,
+ xcorner + bbox_width, ycorner + bbox_height);
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner + bbox_width, ycorner + bbox_height,
+ xcorner, ycorner + bbox_height);
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner, ycorner + bbox_height,
+ xcorner, ycorner);
+ }
+ else {
+ float sin_a = sin(bbox_angle * (TWOPI / 360));
+ float cos_a = cos(bbox_angle * (TWOPI / 360));
+ float a, b, c, d;
+
+ a = cos_a * bbox_width;
+ b = -sin_a * bbox_width;
+ c = -sin_a * bbox_height;
+ d = -cos_a * bbox_height;
+
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner, ycorner,
+ xcorner + (int) rint(a), ycorner + (int) rint(b));
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner + (int) rint(a), ycorner + (int) rint(b),
+ xcorner + (int) rint(a + c), ycorner + (int) rint(b + d));
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner + (int) rint(a + c), ycorner + (int) rint(b + d),
+ xcorner + (int) rint(c), ycorner + (int) rint(d));
+ XDrawLine(DISP, currwin.win, ruleGC,
+ xcorner + (int) rint(c), ycorner + (int) rint(d),
+ xcorner, ycorner);
+ }
+ bbox_valid = False;
+ }
+}
+
+#if PS
+
+static XIOErrorHandler oldhandler;
+
+static int XDviIOErrorHandler P1C(Display *, disp)
+{
+ ps_destroy();
+ return oldhandler(disp);
+}
+
+/*
+ * Initialize paths for file searching
+ */
+
+void
+ps_init_paths()
+{
+#if TOOLKIT
+ static Boolean done_already = False;
+
+ if (done_already)
+ return;
+ done_already = True;
+#endif
+
+#if CFGFILE
+
+ if ((search_header.path1 = getenv("XDVIHEADERS")) == NULL
+ && (search_header.path1 = getenv("TEXPSHEADERS")) == NULL)
+ search_header.path1 = getenv("PSHEADERS");
+ search_header.envptr = ffgetenv("PSHEADERS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_header.envptr != NULL && search_header.envptr->value == NULL)
+ search_header.envptr = NULL;
+
+ if ((search_fig.path1 = getenv("XDVIPICTS")) == NULL
+ && (search_fig.path1 = getenv("TEXPICTS")) == NULL)
+ search_fig.path1 = getenv("TEXINPUTS");
+ search_fig.envptr = ffgetenv("TEXPICTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_fig.envptr != NULL && search_fig.envptr->value == NULL)
+ search_fig.envptr = NULL;
+
+#else /* not CFGFILE */
+
+ if ((search_header.path1 = getenv("XDVIHEADERS")) == NULL
+ && (search_header.path1 = getenv("TEXPSHEADERS")) == NULL
+ && (search_header.path1 = getenv("PSHEADERS")) == NULL
+ ) {
+ search_header.path1 = search_header.path2;
+ search_header.path2 = NULL;
+ }
+
+ if ((search_fig.path1 = getenv("XDVIPICTS")) == NULL
+ && (search_fig.path1 = getenv("TEXPICTS")) == NULL
+ && (search_fig.path1 = getenv("TEXINPUTS")) == NULL
+ ) {
+ search_fig.path1 = search_fig.path2;
+ search_fig.path2 = NULL;
+ }
+
+#endif /* not CFGFILE */
+
+}
+
+
+static void
+actual_startup()
+{
+ ps_init_paths();
+
+ /* This allows us to clean up after server shutdowns, etc. */
+ oldhandler = XSetIOErrorHandler(XDviIOErrorHandler);
+
+ /*
+ * Figure out what we want to use to display postscript figures
+ * and set at most one of the following to True:
+ * resource.useGS, resource.useDPS, resource.useNeWS
+ *
+ * Choose DPS then NEWS then Ghostscript if they are available
+ */
+ if (!(
+#ifdef PS_DPS
+ (resource.useDPS && initDPS())
+#if defined(PS_NEWS) || defined(PS_GS)
+ ||
+#endif
+#endif /* PS_DPS */
+
+#ifdef PS_NEWS
+ (resource.useNeWS && initNeWS())
+#ifdef PS_GS
+ ||
+#endif
+#endif /* PS_NEWS */
+
+#ifdef PS_GS
+ (resource.useGS && initGS())
+#endif
+
+ ))
+ psp = no_ps_procs;
+}
+
+static void
+ps_startup(xul, yul, cp)
+ int xul, yul;
+ _Xconst char *cp;
+{
+ if (!resource._postscript) {
+ draw_bbox();
+ return;
+ }
+ actual_startup();
+ psp.drawbegin(xul, yul, cp);
+}
+
+static void
+ps_startup2()
+{
+ actual_startup();
+ psp.beginheader();
+}
+
+/* ARGSUSED */
+static void
+NullProc2(cp)
+ _Xconst char *cp;
+{}
+
+static void
+ps_parseraw(PostScript_cmd)
+ _Xconst char *PostScript_cmd;
+{
+ _Xconst char *p;
+
+ /* dumb parsing of PostScript - search for rotation H. Zeller 1/97 */
+ bbox_angle = 0;
+ p = strstr(PostScript_cmd, "rotate");
+ if (p != NULL) {
+ while (*p != '\0' && !isdigit(*p)) --p;
+ while (*p != '\0' && isdigit(*p)) --p;
+ if (*p != '+' && *p != '-') ++p;
+ sscanf(p, "%d neg rotate", &bbox_angle);
+ }
+}
+
+/* ARGSUSED */
+void
+#if NeedFunctionPrototypes
+drawbegin_none(int xul, int yul, _Xconst char *cp)
+#else /* !NeedFunctionPrototypes */
+drawbegin_none(xul, yul, cp)
+ int xul, yul;
+ _Xconst char *cp;
+#endif /* NeedFunctionPrototypes */
+{
+ draw_bbox();
+}
+
+
+/*
+ * Mechanism to cache results of ``tick'' specials.
+ */
+
+struct tickrec {
+ struct tickrec *next;
+ int pageno;
+ char *command;
+ char *tempname;
+};
+
+static struct tickrec *tickhead = NULL; /* head of linked list of */
+ /* cached information */
+static int nticks = 0; /* number of records total */
+
+#ifndef TICKCACHESIZE
+#define TICKCACHESIZE 3
+#endif
+
+#ifndef TICKTMP
+#define TICKTMP "/tmp"
+#endif
+
+/*
+ * cachetick() - returns:
+ * NULL error;
+ * fp == NULL string was not in cache, fd = file
+ * fp != NULL string was in cache, fp = cached file
+ */
+
+static struct tickrec *
+cachetick(filename, pathinfo, fp, fdp)
+ _Xconst char *filename;
+ struct findrec *pathinfo;
+ FILE **fp;
+ int *fdp;
+{
+ struct tickrec **linkp;
+ struct tickrec *tikp;
+ struct tickrec **freerecp;
+
+ linkp = &tickhead;
+ freerecp = NULL;
+ for (;;) { /* see if we have it already */
+ tikp = *linkp;
+ if (tikp == NULL) { /* if end of list */
+ int fd;
+
+ if (nticks >= TICKCACHESIZE && freerecp != NULL) {
+ tikp = *freerecp;
+ *freerecp = tikp->next;
+ free(tikp->command);
+ unlink(tikp->tempname);
+ /* reuse tikp and tikp->tempname */
+ }
+ else {
+ tikp = xmalloc(sizeof(struct tickrec));
+ tikp->tempname = NULL;
+ ++nticks;
+ }
+ fd = xdvi_temp_fd(&tikp->tempname);
+ if (fd == -1) {
+ perror("Cannot create temporary file");
+ free(tikp->tempname);
+ free(tikp);
+ return NULL;
+ }
+ tikp->command = xstrdup(filename);
+ *fp = NULL;
+ *fdp = fd;
+ break;
+ }
+ if (strcmp(filename, tikp->command) == 0) { /* found it */
+ *linkp = tikp->next; /* unlink it */
+ *fp = xfopen(tikp->tempname, OPEN_MODE);
+ if (*fp == NULL) {
+ perror(tikp->tempname);
+ free(tikp->tempname);
+ free(tikp->command);
+ free(tikp);
+ return NULL;
+ }
+ break;
+ }
+ if (tikp->pageno != current_page) freerecp = linkp;
+ linkp = &tikp->next;
+ }
+ tikp->next = tickhead; /* link it in */
+ tickhead = tikp;
+ tikp->pageno = pathinfo != &search_header ? current_page : -1;
+ return tikp;
+}
+
+void
+ps_clear_cache()
+{
+ struct tickrec *tikp;
+
+ while (tickhead != NULL) {
+ tikp = tickhead;
+ tickhead = tickhead->next;
+ free(tikp->command);
+ unlink(tikp->tempname);
+ free((char *) tikp->tempname);
+ free(tikp);
+ }
+ nticks = 0;
+}
+
+#ifndef UNCOMPRESS
+#define UNCOMPRESS "uncompress"
+#endif
+
+#ifndef GUNZIP
+#define GUNZIP "gunzip"
+#endif
+
+#ifndef BUNZIP2
+#define BUNZIP2 "bunzip2"
+#endif
+
+static void
+send_ps_file(filename, pathinfo)
+ _Xconst char *filename;
+ struct findrec *pathinfo;
+{
+ FILE *f;
+ int fd;
+ static _Xconst char *argv[] = {NULL, "-c", NULL, NULL};
+ _Xconst char *bufp;
+ struct tickrec *tikp;
+ char *p;
+ unsigned len;
+ char magic1, magic2, magic3;
+
+ if (psp.drawfile == NULL || !resource._postscript) return;
+
+ if (filename[0] == '`') {
+ if (!resource.allow_shell) {
+ if (warn_spec_now)
+ WARN1(XmDIALOG_ERROR,
+ "Shell escape disallowed for special\n\"%s\"", filename);
+ return;
+ }
+
+ tikp = cachetick(filename, pathinfo, &f, &fd);
+ if (tikp == NULL) /* if error */
+ return;
+ if (f == NULL) { /* if not cached, need to create */
+ close(fd);
+ ++n_files_left;
+ len = strlen(filename) + strlen(tikp->tempname) + (4 - 1);
+ if (len > ffline_len)
+ expandline(len);
+ Sprintf(ffline, "%s > %s", filename + 1, tikp->tempname);
+ (void) system(ffline);
+ f = xfopen(tikp->tempname, OPEN_MODE);
+ if (f == NULL) {
+ perror(tikp->tempname);
+ return;
+ }
+ }
+ bufp = tikp->tempname;
+ }
+ else {
+ f = NULL;
+ /* first try the same path as the dvi file */
+ if (filename[0] != '/') {
+ p = rindex(dvi_name, '/');
+ if (p == NULL) bufp = filename;
+ else {
+ unsigned len1, len2;
+
+ len1 = ++p - dvi_name;
+ len2 = strlen(filename) + 1;
+ if (len1 + len2 > ffline_len)
+ expandline(len1 + len2);
+ bcopy(dvi_name, ffline, len1);
+ bcopy(filename, ffline + len1, len2);
+ bufp = ffline;
+ }
+ if (debug & DBG_OPEN) Printf("Trying PS file %s\n", bufp);
+ f = xfopen(bufp, OPEN_MODE);
+ }
+ if (f == NULL) {
+ f = filefind(filename, pathinfo, (_Xconst char **) NULL);
+ bufp = ffline;
+ }
+
+ /* if still no luck, complain */
+ if (f == NULL) {
+ WARN1(XmDIALOG_ERROR,
+ "Cannot find PostScript file for inclusion in document:\n%s",
+ filename);
+ draw_bbox();
+ return;
+ }
+
+ /* check for compressed files */
+ len = strlen(filename);
+ magic1 = '\037';
+ magic3 = '\0';
+ if ((len > 2 && strcmp(filename + len - 2, ".Z") == 0
+ && (argv[0] = UNCOMPRESS, magic2 = '\235', True))
+ || (len > 3 && strcmp(filename + len - 3, ".gz") == 0
+ && (argv[0] = GUNZIP, magic2 = '\213', True))
+ || (len > 4 && strcmp(filename + len - 4, ".bz2") == 0
+ && (argv[0] = BUNZIP2, magic1 = 'B', magic2 = 'Z',
+ magic3 = 'h', True))) {
+ if (getc(f) != magic1 || (char) getc(f) != magic2
+ || (magic3 != '\0' && getc(f) != magic3))
+ rewind(f);
+ else {
+ Fclose(f);
+ ++n_files_left;
+ tikp = cachetick(filename, pathinfo, &f, &fd);
+ if (tikp == NULL) /* if error */
+ return;
+ if (f == NULL) { /* if not cached, need to create */
+ pid_t pid;
+ int status;
+
+ argv[2] = bufp;
+ Fflush(stderr); /* avoid double flushing */
+ pid = vfork();
+ if (pid == 0) { /* if child */
+ (void) dup2(fd, 1);
+ (void) execvp(argv[0], (char **) argv);
+ Fprintf(stderr, "Execvp of %s failed.\n", argv[0]);
+ Fflush(stderr);
+ _exit(1);
+ }
+ (void) close(fd);
+ ++n_files_left;
+ for (;;) {
+#if HAVE_WAITPID
+ if (waitpid(pid, &status, 0) != -1) break;
+#else
+# if HAVE_WAIT4
+ if (wait4(pid, &status, 0, (struct rusage *) NULL)
+ != -1)
+ break;
+# else
+ int retval;
+
+ retval = wait(&status);
+ if (retval == pid) break;
+ if (retval != -1) continue;
+# endif
+#endif
+ if (errno == EINTR) continue;
+ perror("[xdvi] waitpid");
+ return;
+ }
+ f = xfopen(tikp->tempname, OPEN_MODE);
+ if (f == NULL) {
+ perror(tikp->tempname);
+ return;
+ }
+ }
+ bufp = tikp->tempname;
+ }
+ }
+ }
+
+ /* Success! */
+ psp.drawfile(bufp, f); /* this is supposed to close the file */
+}
+
+
+void
+ps_destroy()
+{
+ struct tickrec *tikp;
+
+ /* Note: old NeXT systems (at least) lack atexit/on_exit. */
+ psp.destroy();
+ for (tikp = tickhead; tikp != NULL; tikp = tikp->next)
+ if (unlink(tikp->tempname) < 0)
+ perror(tikp->tempname);
+}
+
+#endif /* PS */
+
+
+void
+init_prescan()
+{
+#if PS
+ struct tickrec *tikp;
+#endif
+
+ scanned_page =
+#if PS
+ scanned_page_ps = scanned_page_ps_bak =
+#endif
+#if COLOR
+ scanned_page_color =
+#endif
+ scanned_page_reset = resource.prescan ? -1 : total_pages + 1;
+
+#if PS
+ if (!resource._postscript)
+ scanned_page_ps = total_pages + 1;
+
+ for (tikp = tickhead; tikp != NULL; tikp = tikp->next)
+ tikp->pageno = -1;
+ psp.newdoc();
+#endif
+
+#if COLOR
+ if (!use_color)
+ scanned_page_color = total_pages + 1;
+#endif
+
+ if (ignore_papersize_specials)
+ scanned_page =
+#if PS && COLOR
+ scanned_page_ps < scanned_page_color
+ ? scanned_page_ps : scanned_page_color;
+#elif PS
+ scanned_page_ps;
+#elif COLOR
+ scanned_page_color;
+#else
+ total_pages + 1;
+#endif
+}
+
+
+static void
+psfig_special(cp)
+ char *cp;
+{
+ char *filename;
+ int raww, rawh;
+
+ if (strncmp(cp, ":[begin]", 8) == 0) {
+ cp += 8;
+ bbox_valid = False;
+ bbox_angle = 0;
+ if (sscanf(cp, "%d %d\n", &raww, &rawh) >= 2) {
+ bbox_valid = True;
+ bbox_width = pixel_conv(spell_conv(raww));
+ bbox_height = pixel_conv(spell_conv(rawh));
+ bbox_voffset = 0;
+ }
+ if (currwin.win == mane.win)
+#if PS
+ psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
+ cp);
+#else
+ draw_bbox();
+#endif
+ psfig_begun = True;
+ } else if (strncmp(cp, " plotfile ", 10) == 0) {
+ cp += 10;
+ while (isspace(*cp)) cp++;
+ for (filename = cp; !isspace(*cp); ++cp);
+ *cp = '\0';
+#if PS
+ if (currwin.win == mane.win) send_ps_file(filename, &search_fig);
+#endif
+ } else if (strncmp(cp, ":[end]", 6) == 0) {
+ cp += 6;
+#if PS
+ if (currwin.win == mane.win) psp.drawend(cp);
+#endif
+ bbox_valid = False;
+ psfig_begun = False;
+ } else if (*cp == ':') {
+ /* I am going to send some raw postscript stuff */
+ ++cp; /* skip the colon */
+#if PS
+ ps_parseraw(cp);
+ if (currwin.win == mane.win) psp.drawraw(cp);
+#endif
+ } else {
+ /* also raw PostScript, but no extra colon to skip */
+#if PS
+ if (currwin.win == mane.win) {
+ ps_parseraw(cp);
+ if (psfig_begun) psp.drawraw(cp);
+ else {
+ psp.drawbegin(PXL_H - currwin.base_x,
+ PXL_V - currwin.base_y, cp);
+ psp.drawend("");
+ }
+ }
+#endif
+ }
+}
+
+
+/* Keys for epsf specials */
+
+static _Xconst char *keytab[] = {"clip",
+ "llx",
+ "lly",
+ "urx",
+ "ury",
+ "rwi",
+ "rhi",
+ "hsize",
+ "vsize",
+ "hoffset",
+ "voffset",
+ "hscale",
+ "vscale",
+ "angle"};
+
+#define KEY_LLX keyval[0]
+#define KEY_LLY keyval[1]
+#define KEY_URX keyval[2]
+#define KEY_URY keyval[3]
+#define KEY_RWI keyval[4]
+#define KEY_RHI keyval[5]
+
+#define NKEYS (sizeof(keytab)/sizeof(*keytab))
+#define N_ARGLESS_KEYS 1
+
+static void
+epsf_special(cp)
+ char *cp;
+{
+ char *filename;
+ static char *buffer;
+ static unsigned int buflen = 0;
+ unsigned int len;
+ char *q;
+ int flags = 0;
+ double keyval[6];
+
+ filename = cp;
+ if (*cp == '\'' || *cp == '"') {
+ do ++cp;
+ while (*cp != '\0' && *cp != *filename);
+ ++filename;
+ }
+ else
+ while (*cp != '\0' && !isspace(*cp)) ++cp;
+ if (*cp != '\0') *cp++ = '\0';
+ while (isspace(*cp)) ++cp;
+ len = strlen(cp) + NKEYS + 30;
+ if (buflen < len) {
+ if (buflen != 0) free(buffer);
+ buflen = len;
+ buffer = xmalloc(buflen);
+ }
+ Strcpy(buffer, "@beginspecial");
+ q = buffer + strlen(buffer);
+ while (*cp != '\0') {
+ char *p1 = cp;
+ int keyno;
+
+ while (*p1 != '=' && !isspace(*p1) && *p1 != '\0') ++p1;
+ for (keyno = 0;; ++keyno) {
+ if (keyno >= NKEYS) {
+ if (warn_spec_now)
+ Fprintf(stderr,
+ "%s: unknown keyword (%.*s) in \\special will be ignored\n",
+ prog, (int) (p1 - cp), cp);
+ break;
+ }
+ if (memcmp(cp, keytab[keyno], p1 - cp) == 0) {
+ if (keyno >= N_ARGLESS_KEYS) {
+ while (isspace(*p1)) ++p1;
+ if (*p1 == '=') {
+ ++p1;
+ while (isspace(*p1)) ++p1;
+ }
+ if (keyno < N_ARGLESS_KEYS + 6) {
+ keyval[keyno - N_ARGLESS_KEYS] = atof(p1);
+ flags |= (1 << (keyno - N_ARGLESS_KEYS));
+ }
+ *q++ = ' ';
+ while (!isspace(*p1) && *p1 != '\0') *q++ = *p1++;
+ }
+ *q++ = ' ';
+ *q++ = '@';
+ Strcpy(q, keytab[keyno]);
+ q += strlen(q);
+ break;
+ }
+ }
+ cp = p1;
+ while (!isspace(*cp) && *cp != '\0') ++cp;
+ while (isspace(*cp)) ++cp;
+ }
+ Strcpy(q, " @setspecial\n");
+
+ bbox_valid = False;
+ if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf)){
+ bbox_valid = True;
+ bbox_width = 0.1 * ((flags & 0x10) ? KEY_RWI
+ : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY - KEY_LLY))
+ * dimconv / shrink_factor + 0.5;
+ bbox_voffset = bbox_height = 0.1 * ((flags & 0x20) ? KEY_RHI
+ : KEY_RWI * (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX))
+ * dimconv / shrink_factor + 0.5;
+ }
+
+ if (currwin.win == mane.win) {
+#if PS
+ psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
+ buffer);
+ /* talk directly with the DPSHandler here */
+ send_ps_file(filename, &search_fig);
+ psp.drawend(" @endspecial");
+#else
+ draw_bbox();
+#endif
+ }
+ bbox_valid = False;
+}
+
+
+static void
+quote_special(cp)
+ char *cp;
+{
+ bbox_valid = False;
+
+#if PS
+ if (currwin.win == mane.win) {
+ psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
+ "@beginspecial @setspecial ");
+ /* talk directly with the DPSHandler here */
+ psp.drawraw(cp + 1);
+ psp.drawend(" @endspecial");
+ }
+#endif
+
+ /* nothing else to do--there's no bbox here */
+}
+
+#if PS
+
+static void
+scan_header(cp)
+ char *cp;
+{
+ char *filename;
+
+#if PS_GS
+ if (gs_postpone_prescan)
+ return;
+#endif
+ filename = cp;
+ if (*cp == '\'' || *cp == '"') {
+ do ++cp;
+ while (*cp != '\0' && *cp != *filename);
+ *cp = '\0';
+ ++filename;
+ }
+
+ psp.beginheader();
+ send_ps_file(filename, &search_header);
+}
+
+static void
+scan_bang(cp)
+ char *cp;
+{
+ psp.beginheader();
+ psp.drawraw(cp + 1);
+}
+
+#endif /* PS */
+
+#if COLOR
+
+/*
+ * Table of dvips color names. Produced by passing the table in
+ * dvipsk/color.lpro through the following perl script, and then
+ * through sort.
+ *
+ * #! /usr/bin/perl -w
+ *
+ * sub cvpart {
+ * return $_[0] < 1.0 ? 1.0 - $_[0] : 0.0;
+ * }
+ *
+ * $pat = "^\\/(\\w+)\\s*\\{\\s*([0-9.]+)\\s*([0-9.]+)\\s*([0-9.]+)"
+ * . "\\s*([0-9.]+)\\s*setcmykcolor\\s*\\}\\s*DC\\s*\$";
+ * while (<STDIN>) {
+ * chop;
+ * if (/^%%/) {next;}
+ * if (/$pat/o) {
+ * printf "\t\tDVIPSCOLORDESC(%2d, \"%s\", %g, %g, %g),\n",
+ * length($1), $1,
+ * cvpart($2 + $5), cvpart($3 + $5), cvpart($4 + $5);
+ * }
+ * else {
+ * print "Bad line: ", $_, "\n";
+ * }
+ * }
+ */
+
+struct dvipscolor {
+ int len;
+ _Xconst char *name;
+ struct rgb color;
+};
+
+#define CVPART(x) ((int)((x) * 65535 + 0.5))
+#define DVIPSCOLORDESC(n, name, r, g, b) \
+ {n, name, {CVPART(r), CVPART(g), CVPART(b)}}
+
+static struct dvipscolor colornames[] = {
+ DVIPSCOLORDESC( 3, "Red", 1, 0, 0),
+ DVIPSCOLORDESC( 3, "Tan", 0.86, 0.58, 0.44),
+ DVIPSCOLORDESC( 4, "Blue", 0, 0, 1),
+ DVIPSCOLORDESC( 4, "Cyan", 0, 1, 1),
+ DVIPSCOLORDESC( 4, "Gray", 0.5, 0.5, 0.5),
+ DVIPSCOLORDESC( 4, "Plum", 0.5, 0, 1),
+ DVIPSCOLORDESC( 5, "Black", 0, 0, 0),
+ DVIPSCOLORDESC( 5, "Brown", 0.4, 0, 0),
+ DVIPSCOLORDESC( 5, "Green", 0, 1, 0),
+ DVIPSCOLORDESC( 5, "Melon", 1, 0.54, 0.5),
+ DVIPSCOLORDESC( 5, "Peach", 1, 0.5, 0.3),
+ DVIPSCOLORDESC( 5, "Sepia", 0.3, 0, 0),
+ DVIPSCOLORDESC( 5, "White", 1, 1, 1),
+ DVIPSCOLORDESC( 6, "Maroon", 0.68, 0, 0),
+ DVIPSCOLORDESC( 6, "Orange", 1, 0.39, 0.13),
+ DVIPSCOLORDESC( 6, "Orchid", 0.68, 0.36, 1),
+ DVIPSCOLORDESC( 6, "Purple", 0.55, 0.14, 1),
+ DVIPSCOLORDESC( 6, "Salmon", 1, 0.47, 0.62),
+ DVIPSCOLORDESC( 6, "Violet", 0.21, 0.12, 1),
+ DVIPSCOLORDESC( 6, "Yellow", 1, 1, 0),
+ DVIPSCOLORDESC( 7, "Apricot", 1, 0.68, 0.48),
+ DVIPSCOLORDESC( 7, "Emerald", 0, 1, 0.5),
+ DVIPSCOLORDESC( 7, "Fuchsia", 0.45, 0.01, 0.92),
+ DVIPSCOLORDESC( 7, "Magenta", 1, 0, 1),
+ DVIPSCOLORDESC( 7, "SkyBlue", 0.38, 1, 0.88),
+ DVIPSCOLORDESC( 7, "Thistle", 0.88, 0.41, 1),
+ DVIPSCOLORDESC( 8, "BrickRed", 0.72, 0, 0),
+ DVIPSCOLORDESC( 8, "Cerulean", 0.06, 0.89, 1),
+ DVIPSCOLORDESC( 8, "Lavender", 1, 0.52, 1),
+ DVIPSCOLORDESC( 8, "Mahogany", 0.65, 0, 0),
+ DVIPSCOLORDESC( 8, "Mulberry", 0.64, 0.08, 0.98),
+ DVIPSCOLORDESC( 8, "NavyBlue", 0.06, 0.46, 1),
+ DVIPSCOLORDESC( 8, "SeaGreen", 0.31, 1, 0.5),
+ DVIPSCOLORDESC( 8, "TealBlue", 0.12, 0.98, 0.64),
+ DVIPSCOLORDESC( 9, "BlueGreen", 0.15, 1, 0.67),
+ DVIPSCOLORDESC( 9, "CadetBlue", 0.38, 0.43, 0.77),
+ DVIPSCOLORDESC( 9, "Dandelion", 1, 0.71, 0.16),
+ DVIPSCOLORDESC( 9, "Goldenrod", 1, 0.9, 0.16),
+ DVIPSCOLORDESC( 9, "LimeGreen", 0.5, 1, 0),
+ DVIPSCOLORDESC( 9, "OrangeRed", 1, 0, 0.5),
+ DVIPSCOLORDESC( 9, "PineGreen", 0, 0.75, 0.16),
+ DVIPSCOLORDESC( 9, "RawSienna", 0.55, 0, 0),
+ DVIPSCOLORDESC( 9, "RedOrange", 1, 0.23, 0.13),
+ DVIPSCOLORDESC( 9, "RedViolet", 0.59, 0, 0.66),
+ DVIPSCOLORDESC( 9, "Rhodamine", 1, 0.18, 1),
+ DVIPSCOLORDESC( 9, "RoyalBlue", 0, 0.5, 1),
+ DVIPSCOLORDESC( 9, "RubineRed", 1, 0, 0.87),
+ DVIPSCOLORDESC( 9, "Turquoise", 0.15, 1, 0.8),
+ DVIPSCOLORDESC( 9, "VioletRed", 1, 0.19, 1),
+ DVIPSCOLORDESC(10, "Aquamarine", 0.18, 1, 0.7),
+ DVIPSCOLORDESC(10, "BlueViolet", 0.1, 0.05, 0.96),
+ DVIPSCOLORDESC(10, "DarkOrchid", 0.6, 0.2, 0.8),
+ DVIPSCOLORDESC(10, "OliveGreen", 0, 0.6, 0),
+ DVIPSCOLORDESC(10, "Periwinkle", 0.43, 0.45, 1),
+ DVIPSCOLORDESC(11, "Bittersweet", 0.76, 0.01, 0),
+ DVIPSCOLORDESC(11, "BurntOrange", 1, 0.49, 0),
+ DVIPSCOLORDESC(11, "ForestGreen", 0, 0.88, 0),
+ DVIPSCOLORDESC(11, "GreenYellow", 0.85, 1, 0.31),
+ DVIPSCOLORDESC(11, "JungleGreen", 0.01, 1, 0.48),
+ DVIPSCOLORDESC(11, "ProcessBlue", 0.04, 1, 1),
+ DVIPSCOLORDESC(11, "RoyalPurple", 0.25, 0.1, 1),
+ DVIPSCOLORDESC(11, "SpringGreen", 0.74, 1, 0.24),
+ DVIPSCOLORDESC(11, "YellowGreen", 0.56, 1, 0.26),
+ DVIPSCOLORDESC(12, "MidnightBlue", 0, 0.44, 0.57),
+ DVIPSCOLORDESC(12, "YellowOrange", 1, 0.58, 0),
+ DVIPSCOLORDESC(13, "CarnationPink", 1, 0.37, 1),
+ DVIPSCOLORDESC(14, "CornflowerBlue", 0.35, 0.87, 1),
+ DVIPSCOLORDESC(14, "WildStrawberry", 1, 0.04, 0.61),
+};
+
+#undef CVPART
+#undef DVIPSCOLORDESC
+
+static Boolean
+parse_color(cp0, cp, rgbp)
+ _Xconst char *cp0, *cp;
+ struct rgb *rgbp;
+{
+ double r, g, b;
+
+ while (*cp == ' ') ++cp;
+
+ if (memicmp(cp, "rgb ", 4) == 0) {
+ if (sscanf(cp + 3, "%lf %lf %lf", &r, &g, &b) == 3
+ && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) {
+ rgbp->r = r * 65535 + 0.5;
+ rgbp->g = g * 65535 + 0.5;
+ rgbp->b = b * 65535 + 0.5;
+ return True;
+ }
+ }
+ else if (memicmp(cp, "gray ", 5) == 0) {
+ if (sscanf(cp + 4, "%lf", &r) == 1 && r >= 0 && r <= 1) {
+ rgbp->r = rgbp->g = rgbp->b = r * 65535 + 0.5;
+ return True;
+ }
+ }
+ else if (memicmp(cp, "cmyk ", 5) == 0) {
+ double k;
+
+ if (sscanf(cp + 4, "%lf %lf %lf %lf", &r, &g, &b, &k) == 4
+ && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1
+ && k >= 0 && k <= 1) {
+ r = 1.0 - r - k; /* cyan --> red */
+ rgbp->r = (r < 0 ? 0 : r * 65535 + 0.5);
+ g = 1.0 - g - k; /* magenta --> green */
+ rgbp->g = (g < 0 ? 0 : g * 65535 + 0.5);
+ b = 1.0 - b - k; /* yellow --> blue */
+ rgbp->b = (b < 0 ? 0 : b * 65535 + 0.5);
+ return True;
+ }
+ }
+ else if (memicmp(cp, "hsb ", 4) == 0) {
+ double hue, sat, bri;
+
+ if (sscanf(cp + 3, "%lf %lf %lf", &hue, &sat, &bri) == 3 && hue >= 0
+ && hue <= 1 && sat >= 0 && sat <= 1 && bri >= 0 && bri <= 1) {
+ int h = (int) (6 * hue);
+ double p = bri * (1 - sat);
+ double q = bri * (1 - sat * (6 * hue - h));
+ double t = p - q + bri;
+
+ switch (h) {
+ case 0: r = bri; g = t; b = p; break; /* Red - Yel */
+ case 1: r = q; g = bri; b = p; break; /* Yel - Grn */
+ case 2: r = p; g = bri; b = t; break; /* Grn - Cyn */
+ case 3: r = p; g = q; b = bri; break; /* Cyn - Blu */
+ case 4: r = t; g = p; b = bri; break; /* Blu - Mag */
+ case 5: r = bri; g = p; b = q; break; /* Mag - Red */
+ case 6: r = bri; g = b = p; break; /* Red */
+ }
+ rgbp->r = r * 65535 + 0.5;
+ rgbp->g = g * 65535 + 0.5;
+ rgbp->b = b * 65535 + 0.5;
+ return True;
+ }
+ }
+ else { /* check table of dvips color names */
+ int i1 = -1; /* ends of range for bisection search */
+ int i2 = XtNumber(colornames);
+ int i;
+ int len;
+
+ len = 0;
+ while (isalpha(cp[len]))
+ ++len; /* get length of color name */
+ do {
+ struct dvipscolor *dp;
+ int j;
+
+ i = (i1 + i2) / 2;
+ dp = &colornames[i];
+ j = len - dp->len;
+ if (j == 0) {
+ j = memcmp(cp, dp->name, len);
+ if (j == 0) {
+ *rgbp = dp->color;
+ return True;
+ }
+ }
+ if (j > 0) i1 = i;
+ else i2 = i;
+ }
+ while (i2 - i1 > 1);
+ }
+
+ if (cp0 != NULL)
+ Fprintf(stderr, "Invalid color name in special `%s'\n", cp0);
+
+ return False;
+}
+
+
+/*
+ * Color stack used when scanning. These records stay around, to ease
+ * the burden on xmalloc(). The first entry is a dummy entry, giving
+ * the default foreground color (as modified).
+ */
+
+struct colorframe {
+ struct colorframe *next, *prev;
+ struct rgb color;
+};
+
+static struct colorframe scanstack_head;
+static int scanstack_len;
+static struct colorframe *scanstack_current;
+
+static void
+init_page_colors()
+{
+ int i;
+
+ page_colors = xmalloc(total_pages * sizeof *page_colors);
+
+ for (i = 0; i <= scanned_page + 1; ++i) {
+ page_colors[i].bg = bg_initial; /* from command line */
+ page_colors[i].colorstack = &fg_initial;
+ page_colors[i].stacksize = 1;
+ }
+ while (i < total_pages)
+ page_colors[i++].colorstack = NULL;
+
+ scanstack_head.color = fg_initial;
+ scanstack_len = 1; /* nothing yet */
+ scanstack_current = &scanstack_head; /* stack position */
+}
+
+
+static void
+scan_bg_color(cp)
+ _Xconst char *cp;
+{
+ if (!use_color)
+ return;
+
+ if (page_colors == NULL)
+ init_page_colors();
+
+ (void) parse_color(cp, cp + 11, &page_colors[scanned_page + 1].bg);
+}
+
+static void
+scan_color(cp)
+ _Xconst char *cp;
+{
+ _Xconst char *cp1 = cp + 6;
+
+ if (!use_color)
+ return;
+
+ while (*cp1 == ' ') ++cp1;
+
+ if (page_colors == NULL)
+ init_page_colors();
+
+ if (memicmp(cp1, "push ", 5) == 0) {
+ if (scanstack_current->next == NULL) { /* if at end */
+ scanstack_current->next = xmalloc(sizeof *scanstack_current);
+ scanstack_current->next->prev = scanstack_current;
+ scanstack_current->next->next = NULL;
+ }
+ scanstack_current = scanstack_current->next;
+ ++scanstack_len;
+ if (!parse_color(cp, cp1 + 5, &scanstack_current->color))
+ scanstack_current->color = scanstack_current->prev->color;
+ }
+ else if (memicmp(cp1, "pop", 3) == 0) {
+ if (scanstack_len <= 1) {
+ fprintf(stderr,
+ "Warning: Color pop occurred with empty color stack.\n");
+ }
+ else {
+ scanstack_current = scanstack_current->prev;
+ --scanstack_len;
+ }
+ }
+ else {
+ (void) parse_color(cp, cp1, &scanstack_head.color);
+ if (scanstack_len > 1) {
+ struct colorframe *cfp;
+
+ Fprintf(stderr, "Warning: Global color change occurred with non-empty color stack;\n\
+coping by setting all stack entries to that color.\n");
+ for (cfp = scanstack_head.next;; cfp = cfp->next) {
+ cfp->color = scanstack_head.color;
+ if (cfp == scanstack_current) break;
+ }
+ }
+ }
+}
+
+void
+scan_color_eop()
+{
+ int i;
+ _Xconst struct rgb *prev;
+ struct colorframe *cf;
+ _Xconst struct rgb *p1;
+ struct rgb *rgbp;
+
+ if (page_colors == NULL)
+ return;
+
+ /* set background color for next page */
+ if (scanned_page + 1 < total_pages)
+ page_colors[scanned_page + 1].bg = page_colors[scanned_page].bg;
+
+ /* save the stack contents */
+ page_colors[scanned_page].stacksize = scanstack_len;
+
+ prev = &fg_initial;
+ i = 1;
+ if (scanned_page > 0) {
+ prev = page_colors[scanned_page - 1].colorstack;
+ i = page_colors[scanned_page - 1].stacksize;
+ }
+ if (scanstack_len <= i) {
+ /* try to reuse the previous array */
+ p1 = prev;
+ cf = &scanstack_head;
+ for (i = 0;;) {
+ if (p1->r != cf->color.r || p1->g != cf->color.g
+ || p1->b != cf->color.b)
+ break;
+ if (++i >= scanstack_len) { /* end loop; reuse memory */
+ page_colors[scanned_page].colorstack = prev;
+ return; /* done */
+ }
+ ++p1;
+ cf = cf->next;
+ }
+ }
+ page_colors[scanned_page].colorstack = rgbp
+ = xmalloc(scanstack_len * sizeof *rgbp);
+ cf = &scanstack_head;
+ for (i = 0; i < scanstack_len; ++i) {
+ *rgbp++ = cf->color;
+ cf = cf->next;
+ }
+}
+
+
+/*
+ * Page stack when displaying. Again, the records stay around once
+ * allocated. Bottom entries in the stack (inherited from previous
+ * pages) are stored in an array instead (see comments in xdvi.h).
+ */
+
+static struct colorframe *rcs_head;
+
+
+/*
+ * We don't actually do any X calls yet to change colors; that can wait
+ * until a character or rule needs to be drawn.
+ */
+
+void
+set_fg_color(_Xconst struct rgb *color)
+{
+ struct fgrec **fgpp;
+
+ if (fg_current != NULL
+ && color->r == fg_current->color.r
+ && color->g == fg_current->color.g
+ && color->b == fg_current->color.b)
+ return;
+
+ for (fgpp = &bg_current->fg_head;;) {
+ fg_current = *fgpp;
+ if (fg_current == NULL) { /* if color is not in list */
+ fg_current = *fgpp = xmalloc(sizeof *fg_current);
+ fg_current->next = NULL;
+ fg_current->color = *color;
+ fg_current->pixel_good = False;
+#if GREY
+ fg_current->palette_good = False;
+#endif
+ break;
+ }
+ if (fg_current->color.r == color->r
+ && fg_current->color.g == color->g
+ && fg_current->color.b == color->b)
+ break;
+ fgpp = &fg_current->next;
+ }
+ if (debug & DBG_DVI)
+ printf("Changing fg color to %5d %5d %5d\n",
+ color->r, color->g, color->b);
+}
+
+static void
+color_special(cp)
+ _Xconst char *cp;
+{
+ if (!use_color)
+ return;
+
+ while (*cp == ' ') ++cp;
+
+ if (memicmp(cp, "push ", 5) == 0) {
+ if (rcs_top == NULL) {
+ if (rcs_head == NULL) {
+ rcs_head = xmalloc(sizeof *rcs_head);
+ rcs_head->prev = rcs_head->next = NULL;
+ }
+ rcs_top = rcs_head;
+ }
+ else {
+ struct colorframe *rcs_next;
+
+ rcs_next = rcs_top->next;
+ if (rcs_next == NULL) {
+ rcs_next = rcs_top->next = xmalloc(sizeof *rcs_next);
+ rcs_next->prev = rcs_top;
+ rcs_next->next = NULL;
+ }
+ rcs_top = rcs_next;
+ }
+ if (!parse_color(NULL, cp + 5, &rcs_top->color)) {
+ if (rcs_top->prev != NULL)
+ rcs_top->color = rcs_top->prev->color;
+ else
+ rcs_top->color = color_bottom[color_bot_size - 1];
+ }
+ set_fg_color(&rcs_top->color);
+ }
+ else if (memicmp(cp, "pop", 3) == 0) {
+ /* Pop stack */
+ if (rcs_top != NULL) {
+ if (color_bot_size > 0)
+ rcs_top = rcs_top->prev;
+ else return;
+ }
+ else if (color_bot_size > 1)
+ --color_bot_size;
+ else {
+ if (scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page =
+#if PS
+ scanned_page_ps =
+#endif
+ scanned_page_color = scanned_page_reset = -1;
+ ev_flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(canit_env, 1);
+ }
+ return;
+ }
+
+ set_fg_color(rcs_top != NULL ? &rcs_top->color
+ : &color_bottom[color_bot_size - 1]);
+ }
+ else {
+ struct rgb color;
+
+ if (!parse_color(NULL, cp, &color)) return;
+
+ /* clear stack */
+ if (rcs_head == NULL) {
+ rcs_head = xmalloc(sizeof *rcs_head);
+ rcs_head->prev = rcs_head->next = NULL;
+ }
+ rcs_top = rcs_head;
+ color_bot_size = 0;
+
+ /* Change top of stack */
+ rcs_top->color = color;
+
+ set_fg_color(&color);
+ }
+}
+
+#endif /* COLOR */
+
+
+static unsigned int
+myatopix(pp)
+ _Xconst char **pp;
+{
+ unsigned int value;
+ _Xconst char *cp = *pp;
+ char scr[16];
+ _Xconst char *p0, *p1;
+
+ p0 = cp;
+ while ((*cp >= '0' && *cp <= '9') || *cp == '.') ++cp;
+ p1 = cp;
+ while (isspace(*cp)) ++cp;
+ if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z') {
+ /* if units are present */
+ if (p1 - p0 <= XtNumber(scr) - 3) {
+ Sprintf(scr, "%.*s%c%c", (int) (p1 - p0), p0, *cp, cp[1]);
+ value = atopix(scr, False);
+ }
+ else value = 0;
+ cp += 2;
+ }
+ else
+ value = atopix(p0, False);
+
+ *pp = cp;
+ return value;
+}
+
+static void
+scan_papersize(cp0)
+ _Xconst char *cp0;
+{
+ _Xconst char *cp = cp0;
+ unsigned int w, h;
+ double mag = 1.;
+
+ if (ignore_papersize_specials)
+ return;
+
+ if (*cp == '*') {
+ do ++cp; while (isspace(*cp));
+ mag = magnification * .001;
+ }
+
+ w = myatopix(&cp) * mag + 0.5;
+
+ while (isspace(*cp)) ++cp;
+ if (*cp == ',')
+ do ++cp; while (isspace(*cp));
+
+ h = myatopix(&cp) * mag + 0.5;
+
+ if (w == 0 || h == 0)
+ Fprintf(stderr, "%s: invalid papersize special \"%s\"\n", prog,
+ cp0);
+ else {
+ page_info[scanned_page + 1].pw = page_info[scanned_page + 1].ww = w;
+ page_info[scanned_page + 1].ph = page_info[scanned_page + 1].wh = h;
+ }
+}
+
+
+/*
+ * The following copyright message applies to the rest of this file. --PV
+ */
+
+/*
+ * This program is Copyright (C) 1987 by the Board of Trustees of the
+ * University of Illinois, and by the author Dirk Grunwald.
+ *
+ * This program may be freely copied, as long as this copyright
+ * message remaines affixed. It may not be sold, although it may
+ * be distributed with other software which is sold. If the
+ * software is distributed, the source code must be made available.
+ *
+ * No warranty, expressed or implied, is given with this software.
+ * It is presented in the hope that it will prove useful.
+ *
+ * Hacked in ignorance and desperation by jonah@db.toronto.edu
+ */
+
+/*
+ * The code to handle the \specials generated by tpic was modified
+ * by Dirk Grunwald using the code Tim Morgan at Univ. of Calif, Irvine
+ * wrote for TeXsun.
+ */
+
+static char *
+endofcommand(cp)
+ char *cp;
+{
+ while (isspace(*cp)) ++cp;
+ if (*cp != '=') return NULL;
+ do ++cp; while (isspace(*cp));
+ return cp;
+}
+
+#define CMD(x, y) ((x) << 8 | (y))
+
+void
+applicationDoSpecial(cp)
+ char *cp;
+{
+ char *p;
+
+ if (debug & DBG_DVI)
+ Printf(" `%s'\n", cp);
+
+ /* Skip white space */
+ while (isspace(*cp)) ++cp;
+
+ /* Ignore initial "xdvi:" */
+ if (memcmp(cp, "xdvi:", 5) == 0) {
+ cp += 5;
+ while (isspace(*cp)) ++cp;
+ }
+
+ /* PostScript specials */
+
+ if (*cp == '"') {
+ quote_special(cp);
+ return;
+ }
+ if (memicmp(cp, "ps:", 3) == 0) {
+ psfig_special(cp + 3);
+ return;
+ }
+ if (memicmp(cp, "psfile", 6) == 0
+ && (p = endofcommand(cp + 6)) != NULL) {
+ epsf_special(p);
+ return;
+ }
+#if COLOR
+ if (memicmp(cp, "color ", 6) == 0) {
+ color_special(cp + 6);
+ return;
+ }
+#endif
+
+ /* these should have been scanned */
+
+ if (*cp == '!'
+ || (memicmp(cp, "header", 6) == 0 && endofcommand(cp + 6) != NULL)) {
+#if PS
+ if (resource._postscript && scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page =
+# if COLOR
+ scanned_page_color =
+# endif
+ scanned_page_ps = scanned_page_reset = -1;
+ ev_flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(canit_env, 1);
+ }
+#endif /* PS */
+ return;
+ }
+
+ if (memicmp(cp, "background ", 11) == 0) {
+#if COLOR
+ if (use_color && scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page =
+# if PS
+ scanned_page_ps =
+# endif
+ scanned_page_color = scanned_page_reset = -1;
+ ev_flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(canit_env, 1);
+ }
+#endif /* COLOR */
+ return;
+ }
+
+ if (memcmp(cp, "papersize", 9) == 0 && endofcommand(cp + 9) != NULL) {
+ if (scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page =
+#if PS
+ scanned_page_ps =
+#endif
+#if COLOR
+ scanned_page_color =
+#endif
+ scanned_page_reset = -1;
+ ev_flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(canit_env, 1);
+ }
+ return;
+ }
+
+ /* tpic specials */
+
+ if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z' &&
+ (isspace(cp[2]) || cp[2] == '\0')) {
+ switch (CMD(*cp, cp[1])) {
+ case CMD('p','n'): set_pen_size(cp + 2); return;
+ case CMD('f','p'): flush_path(); return;
+ case CMD('d','a'): flush_dashed(cp + 2, False); return;
+ case CMD('d','t'): flush_dashed(cp + 2, True); return;
+ case CMD('p','a'): add_path(cp + 2); return;
+ case CMD('a','r'): arc(cp + 2, False); return;
+ case CMD('i','a'): arc(cp + 2, True); return;
+ case CMD('s','p'): flush_spline(); return;
+ case CMD('s','h'): shade_last(); return;
+ case CMD('w','h'): whiten_last(); return;
+ case CMD('b','k'): blacken_last(); return;
+ case CMD('i','p'): /* throw away the path -- jansteen */
+ path_len = 0; return;
+ }
+ }
+
+ if (warn_spec_now && memcmp(cp, "src:", 4) != 0)
+ Fprintf(stderr, "%s: special \"%s\" not implemented\n", prog, cp);
+}
+
+#undef CMD
+
+
+void
+scan_special(cp)
+ char *cp;
+{
+ char *p;
+
+ if (debug & DBG_PS)
+ Printf("Scanning special `%s'.\n", cp);
+
+ /* Skip white space */
+ while (isspace(*cp)) ++cp;
+
+ /* Ignore initial "xdvi:" */
+ if (memcmp(cp, "xdvi:", 5) == 0) {
+ cp += 5;
+ while (isspace(*cp)) ++cp;
+ }
+
+#if PS
+# if COLOR
+ if (scanned_page_ps <= scanned_page)
+# endif
+ {
+ if (*cp == '!') {
+ scan_bang(cp);
+ return;
+ }
+ else if (memicmp(cp, "header", 6) == 0
+ && (p = endofcommand(cp + 6)) != NULL) {
+ scan_header(p);
+ return;
+ }
+ }
+#endif /* PS */
+
+#if COLOR
+# if PS
+ if (scanned_page_color <= scanned_page)
+# endif
+ {
+ if (memicmp(cp, "background ", 11) == 0) {
+ scan_bg_color(cp);
+ return;
+ }
+ else if (memicmp(cp, "color ", 6) == 0) {
+ scan_color(cp);
+ return;
+ }
+ }
+#endif /* COLOR */
+
+ if (memcmp(cp, "papersize", 9) == 0
+ && (p = endofcommand(cp + 9)) != NULL) {
+ scan_papersize(p);
+ return;
+ }
+}
+
+
+#define xspell_conv(n) spell_conv0(n, current_dimconv)
+#define xpixel_conv(x) ((int) ((x) >> 16))
+#define G_PXL_H xpixel_conv(currinf.data.dvi_h)
+
+/* ARGSUSED */
+void
+geom_do_special(g_info, cp, current_dimconv)
+ struct geom_info *g_info;
+ /* cp is not _Xconst, because of endofcommand(). */
+ char *cp;
+ double current_dimconv;
+{
+ _Xconst char *p;
+
+ /* Skip white space */
+ while (isspace(*cp)) ++cp;
+
+ /* Ignore initial "xdvi:" */
+ if (memcmp(cp, "xdvi:", 5) == 0) {
+ cp += 5;
+ while (isspace(*cp)) ++cp;
+ }
+
+ if (memicmp(cp, "psfile", 6) == 0
+ && (p = endofcommand(cp + 6)) != NULL) {
+ /* compute epsf bounding box */
+ char c;
+ int flags = 0;
+ double keyval[6];
+
+ c = *p;
+ if (c == '\'' || c == '"') {
+ do ++p;
+ while (*p != '\0' && *p != c);
+ }
+ else
+ while (*p != '\0' && !isspace(*p)) ++p;
+ while (isspace(*p)) ++p;
+ while (*p != '\0') {
+ _Xconst char *p1 = p;
+ int keyno;
+
+ while (*p1 != '=' && !isspace(*p1) && *p1 != '\0') ++p1;
+ for (keyno = 0; keyno < NKEYS; ++keyno) {
+ if (memcmp(p, keytab[keyno], p1 - p) == 0) {
+ if (keyno >= N_ARGLESS_KEYS) {
+ while (isspace(*p1)) ++p1;
+ if (*p1 == '=') {
+ ++p1;
+ while (isspace(*p1)) ++p1;
+ }
+ if (keyno < N_ARGLESS_KEYS + 6) {
+ keyval[keyno - N_ARGLESS_KEYS] = atof(p1);
+ flags |= (1 << (keyno - N_ARGLESS_KEYS));
+ }
+ while (!isspace(*p1) && *p1 != '\0') ++p1;
+ }
+ break;
+ }
+ }
+ p = p1;
+ while (!isspace(*p) && *p != '\0') ++p;
+ while (isspace(*p)) ++p;
+ }
+
+ if ((flags & 0x30) == 0x30
+ || ((flags & 0x30) && (flags & 0xf) == 0xf)){
+ long x = G_PXL_H;
+ long y = PXL_V;
+ long bbox_w;
+ long bbox_h;
+
+ bbox_w = 0.1 * ((flags & 0x10) ? KEY_RWI
+ : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY - KEY_LLY))
+ * dimconv + 0.5;
+ bbox_h = 0.1 * ((flags & 0x20) ? KEY_RHI
+ : KEY_RWI * (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX))
+ * dimconv + 0.5;
+
+ g_info->geom_box(g_info, x, y - bbox_h, x + bbox_w, y);
+ }
+ }
+ else if (memicmp(cp, "ps::[begin]", 11) == 0) {
+ /* compute psfig bounding box */
+ long bbox_w, bbox_h;
+
+ if (sscanf(cp + 11, "%ld %ld\n", &bbox_w, &bbox_h) >= 2) {
+ long x = G_PXL_H;
+ long y = PXL_V;
+
+ bbox_w = xpixel_conv(spell_conv(bbox_w));
+ bbox_h = xpixel_conv(spell_conv(bbox_h));
+
+ g_info->geom_box(g_info, x, y, x + bbox_w, y + bbox_h);
+ }
+ }
+}
diff --git a/squeeze.c b/squeeze.c
@@ -0,0 +1,192 @@
+/*========================================================================*\
+
+Copyright (c) 1994-1999 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTE:
+ This routine is adapted from the squeeze.c that comes with dvips;
+ it bears the message:
+ This software is Copyright 1988 by Radical Eye Software.
+ Used with permission.
+
+\*========================================================================*/
+
+/*
+ * This routine squeezes a PostScript file down to its
+ * minimum. We parse and then output it.
+ * Adapted for xdvi 1/94. Writes a C program that contains the PS file
+ * as a constant string.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "config.h"
+
+#define LINELENGTH (72)
+#define BUFLENGTH (1000)
+#undef putchar
+#define putchar(a) (void)putc(a, out) ;
+FILE *in, *out ;
+static int linepos = 0 ;
+static int lastspecial = 1 ;
+static int stringlen = 0;
+extern size_t strlen() ;
+/*
+ * This next routine writes out a `special' character. In this case,
+ * we simply put it out, since any special character terminates the
+ * preceding token.
+ */
+void specialout(c)
+char c ;
+{
+ if (linepos + 1 > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0 ;
+ }
+ putchar(c) ;
+ linepos++ ;
+ lastspecial = 1 ;
+}
+void strout(s)
+char *s ;
+{
+ if (linepos + strlen(s) > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0 ;
+ }
+ linepos += strlen(s) ;
+ while (*s != 0)
+ putchar(*s++) ;
+ lastspecial = 1 ;
+}
+void cmdout(s)
+char *s ;
+{
+ int l ;
+
+ l = strlen(s) ;
+ if (linepos + l + 1 > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0 ;
+ lastspecial = 1 ;
+ }
+ if (! lastspecial) {
+ putchar(' ') ;
+ linepos++ ;
+ }
+ while (*s != 0) {
+ putchar(*s++) ;
+ }
+ linepos += l ;
+ lastspecial = 0 ;
+}
+char buf[BUFLENGTH] ;
+#ifndef VMS
+int
+#endif
+main(argc, argv)
+int argc ;
+char *argv[] ;
+{
+ int c ;
+ char *b ;
+ char seeking ;
+ extern void exit() ;
+
+ if (argc > 3 || (in=(argc < 2 ? stdin : fopen(argv[1], "r")))==NULL ||
+ (out=(argc < 3 ? stdout : fopen(argv[2], "w")))==NULL) {
+ (void)fprintf(stderr, "Usage: squeeze [infile [outfile]]\n") ;
+ exit(1) ;
+ }
+ (void)fputs("/*\n\
+ * DO NOT EDIT THIS FILE!\n\
+ * It was created by squeeze.c from another file (see the Makefile).\n\
+ */\n\n\
+#ifndef _Xconst\n\
+#if __STDC__\n\
+#define _Xconst const\n\
+#else\n\
+#define _Xconst\n\
+#endif\n\
+#endif\n\n\
+_Xconst char psheader[] = \"\\\n", out);
+ while (1) {
+ c = getc(in) ;
+ if (c==EOF)
+ break ;
+ if (c=='%') {
+ while ((c=getc(in))!='\n') ;
+ }
+ if (c <= ' ')
+ continue ;
+ switch (c) {
+case '{' :
+case '}' :
+case '[' :
+case ']' :
+ specialout(c) ;
+ break ;
+case '<' :
+case '(' :
+ if (c=='(')
+ seeking = ')' ;
+ else
+ seeking = '>' ;
+ b = buf ;
+ *b++ = c ;
+ do {
+ c = getc(in) ;
+ if (b > buf + BUFLENGTH-2) {
+ (void)fprintf(stderr, "Overran buffer seeking %c", seeking) ;
+ exit(1) ;
+ }
+ *b++ = c ;
+ if (c=='\\')
+ *b++ = getc(in) ;
+ } while (c != seeking) ;
+ *b++ = 0 ;
+ strout(buf) ;
+ break ;
+default:
+ b = buf ;
+ while ((c>='A'&&c<='Z')||(c>='a'&&c<='z')||
+ (c>='0'&&c<='9')||(c=='/')||(c=='@')||
+ (c=='!')||(c=='"')||(c=='&')||(c=='*')||(c==':')||
+ (c==',')||(c==';')||(c=='?')||(c=='^')||(c=='~')||
+ (c=='-')||(c=='.')||(c=='#')||(c=='|')||(c=='_')||
+ (c=='=')||(c=='$')||(c=='+')) {
+ *b++ = c ;
+ c = getc(in) ;
+ }
+ if (b == buf) {
+ (void)fprintf(stderr, "Oops! Missed a case: %c.\n", c) ;
+ exit(1) ;
+ }
+ *b++ = 0 ;
+ (void)ungetc(c, in) ;
+ cmdout(buf) ;
+ }
+ }
+ (void)fprintf(out, "\\n\";\n\n\
+unsigned\tpsheaderlen\t= %d;\n", stringlen + linepos + 1);
+ return 0;
+}
diff --git a/util.c b/util.c
@@ -0,0 +1,1058 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi.h"
+
+#include <errno.h>
+#include <ctype.h> /* needed for memicmp() */
+#include <pwd.h>
+#include <sys/socket.h>
+#include <sys/file.h> /* this defines FASYNC */
+#include <sys/ioctl.h> /* this defines SIOCSPGRP and FIOASYNC */
+
+#include <X11/Xmd.h> /* get WORD64 and LONG64 */
+
+#if PS
+# include <sys/stat.h>
+#endif
+
+#ifdef VMS
+#include <rmsdef.h>
+#endif /* VMS */
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+extern void *malloc();
+extern void *realloc();
+#endif
+
+#if defined(macII) && !__STDC__ /* stdlib.h doesn't define these */
+extern void *malloc();
+extern void *realloc();
+#endif
+
+#if NeedVarargsPrototypes /* this is for oops */
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef DOPRNT /* define this if vfprintf gives you trouble */
+#define vfprintf(stream, message, args) _doprnt(message, args, stream)
+#endif
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined O_NONBLOCK && defined O_NDELAY
+# define O_NONBLOCK O_NDELAY
+#endif
+
+/* Linux prefers O_ASYNC over FASYNC; SGI IRIX does the opposite. */
+#if !defined(FASYNC) && defined(O_ASYNC)
+# define FASYNC O_ASYNC
+#endif
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+# if !defined(SIOCSPGRP) || !defined(FIOASYNC)
+# define FLAKY_SIGPOLL 1
+# endif
+#endif
+
+#if !FLAKY_SIGPOLL && HAVE_STREAMS
+# include <stropts.h>
+
+# ifndef S_RDNORM
+# define S_RDNORM S_INPUT
+# endif
+
+# ifndef S_RDBAND
+# define S_RDBAND 0
+# endif
+
+# ifndef S_HANGUP
+# define S_HANGUP 0
+# endif
+
+# ifndef S_WRNORM
+# define S_WRNORM S_OUTPUT
+# endif
+
+#endif /* not FLAKY_SIGPOLL && HAVE_STREAMS */
+
+
+/*
+ * General utility routines.
+ */
+
+static void
+exit_clean_windows()
+{
+ long *window_list;
+ size_t window_list_len;
+ long *window_list_end;
+ long *wp;
+
+ window_list_len = property_get_data(DefaultRootWindow(DISP),
+ ATOM_XDVI_WINDOWS, (unsigned char **) &window_list,
+ XGetWindowProperty);
+
+ if (window_list_len == 0)
+ return;
+
+ if (window_list_len % sizeof(long) != 0) {
+ XDeleteProperty(DISP, DefaultRootWindow(DISP), ATOM_XDVI_WINDOWS);
+ return;
+ }
+
+ window_list_len /= sizeof(long);
+
+ /* Loop over list of windows. */
+
+ window_list_end = window_list + window_list_len;
+
+ for (wp = window_list; wp < window_list_end; ++wp)
+ if (*wp == XtWindow(top_level)) {
+
+ --window_list_len;
+ --window_list_end;
+ memcpy(wp, wp + 1, (window_list_end - wp) * sizeof(long));
+
+ if (window_list_len == 0)
+ XDeleteProperty(DISP, DefaultRootWindow(DISP),
+ ATOM_XDVI_WINDOWS);
+ else
+ XChangeProperty(DISP, DefaultRootWindow(DISP),
+ ATOM_XDVI_WINDOWS, ATOM_XDVI_WINDOWS, 32, PropModeReplace,
+ (unsigned char *) window_list, window_list_len);
+
+ XFlush(DISP);
+ return;
+ }
+
+ if (debug & DBG_CLIENT)
+ printf("Cannot find window %08lx in list when exiting.\n",
+ XtWindow(top_level));
+
+ return;
+}
+
+
+/*
+ * This routine should be used for all exits, except for really early ones.
+ */
+
+void
+xdvi_exit(status)
+ int status;
+{
+ /* Clean up the "xdvi windows" property in the root window. */
+ if (top_level)
+ exit_clean_windows();
+#if PS
+ ps_destroy();
+#endif
+ exit(status);
+}
+
+/*
+ * Print error message and quit.
+ */
+
+#if NeedVarargsPrototypes
+void
+oops(_Xconst char *message, ...)
+#else
+/* VARARGS */
+void
+oops(va_alist)
+ va_dcl
+#endif
+{
+#if !NeedVarargsPrototypes
+ _Xconst char *message;
+#endif
+ va_list args;
+
+ Fprintf(stderr, "%s: ", prog);
+#if NeedVarargsPrototypes
+ va_start(args, message);
+#else
+ va_start(args);
+ message = va_arg(args, _Xconst char *);
+#endif
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ Putc('\n', stderr);
+ xdvi_exit(1);
+}
+
+
+#ifndef KPATHSEA
+
+/*
+ * Either (re)allocate storage or fail with explanation.
+ */
+
+void *
+xmalloc(size)
+ unsigned size;
+{
+ void *mem = malloc(size);
+
+ if (mem == NULL)
+ oops("! Out of memory (allocating %u bytes).\n", size);
+ return mem;
+}
+
+
+void *
+xrealloc(where, size)
+ void *where;
+ unsigned size;
+{
+ void *mem = realloc(where, size);
+
+ if (mem == NULL)
+ oops("! Out of memory (reallocating %u bytes).\n", size);
+ return mem;
+}
+
+
+/*
+ * Allocate a new string.
+ */
+
+char *
+xstrdup(str)
+ _Xconst char *str;
+{
+ size_t len;
+ char *new;
+
+ len = strlen(str) + 1;
+ new = xmalloc(len);
+ bcopy(str, new, len);
+ return new;
+}
+
+
+/*
+ * Allocate a new string. The second argument is the length.
+ */
+
+char *
+xmemdup(str, len)
+ _Xconst char *str;
+ size_t len;
+{
+ char *new;
+
+ new = xmalloc(len);
+ bcopy(str, new, len);
+ return new;
+}
+
+#endif /* not KPATHSEA */
+
+
+#if TOOLKIT && !HAVE_STRERROR && !defined strerror
+
+/*
+ * Replacement of system routine.
+ */
+
+extern char *sys_errlist[];
+extern int sys_nerr;
+
+char *
+strerror(n)
+ int n;
+{
+ return (unsigned) n <= (unsigned) sys_nerr
+ ? sys_errlist[n]
+ : "Unknown error";
+}
+
+#endif
+
+
+/*
+ * Expand the matrix *ffline to at least the given size.
+ */
+
+void
+expandline(n)
+ size_t n;
+{
+ size_t newlen = n + 128;
+
+ ffline = (ffline == NULL) ? xmalloc(newlen) : xrealloc(ffline, newlen);
+ ffline_len = newlen;
+}
+
+
+/*
+ * Allocate bitmap for given font and character
+ */
+
+void
+alloc_bitmap(bitmap)
+ struct bitmap *bitmap;
+{
+ unsigned int size;
+
+ /* width must be multiple of 16 bits for raster_op */
+ bitmap->bytes_wide = ROUNDUP((int) bitmap->w, BMBITS) * BMBYTES;
+ size = bitmap->bytes_wide * bitmap->h;
+ bitmap->bits = xmalloc(size != 0 ? size : 1);
+}
+
+
+#ifndef KPATHSEA
+
+/*
+ * Put a variable in the environment or abort on error.
+ */
+
+extern char **environ;
+
+void
+xputenv(var, value)
+ _Xconst char *var;
+ _Xconst char *value;
+{
+
+#if HAVE_PUTENV
+
+ char *buf;
+ int len1, len2;
+
+ len1 = strlen(var);
+ len2 = strlen(value) + 1;
+ buf = xmalloc((unsigned int) len1 + len2 + 1);
+ bcopy(var, buf, len1);
+ buf[len1++] = '=';
+ bcopy(value, buf + len1, len2);
+ if (putenv(buf) != 0)
+ oops("! Failure in setting environment variable.");
+ return;
+
+#elif HAVE_SETENV
+
+ if (setenv(var, value, True) != 0)
+ oops("! Failure in setting environment variable.");
+ return;
+
+#else /* not HAVE_{PUTENV,SETENV} */
+
+ int len1;
+ int len2;
+ char *buf;
+ char **linep;
+ static Boolean did_malloc = False;
+
+ len1 = strlen(var);
+ len2 = strlen(value) + 1;
+ buf = xmalloc((unsigned int) len1 + len2 + 1);
+ bcopy(var, buf, len1);
+ buf[len1++] = '=';
+ bcopy(value, buf + len1, len2);
+ for (linep = environ; *linep != NULL; ++linep)
+ if (memcmp(*linep, buf, len1) == 0) {
+ *linep = buf;
+ return;
+ }
+ len1 = linep - environ;
+ if (did_malloc)
+ environ = xrealloc(environ,
+ (unsigned int) (len1 + 2) * sizeof(char *));
+ else {
+ linep = xmalloc((unsigned int)(len1 + 2) * sizeof(char *));
+ bcopy((char *) environ, (char *) linep, len1 * sizeof(char *));
+ environ = linep;
+ did_malloc = True;
+ }
+ environ[len1++] = buf;
+ environ[len1] = NULL;
+
+#endif /* not HAVE_{PUTENV,SETENV} */
+
+}
+
+#endif /* not KPATHSEA */
+
+
+/*
+ * Hopefully a self-explanatory name. This code assumes the second
+ * argument is lower case.
+ */
+
+int
+memicmp(s1, s2, n)
+ _Xconst char *s1;
+ _Xconst char *s2;
+ size_t n;
+{
+ while (n > 0) {
+ int i = tolower(*s1) - *s2;
+ if (i != 0) return i;
+ ++s1;
+ ++s2;
+ --n;
+ }
+ return 0;
+}
+
+
+/*
+ * Close the pixel file for the least recently used font.
+ */
+
+static void
+close_a_file()
+{
+ struct font *fontp;
+ unsigned short oldest = ~0;
+ struct font *f = NULL;
+
+ if (debug & DBG_OPEN)
+ Puts("Calling close_a_file()");
+
+ for (fontp = font_head; fontp != NULL; fontp = fontp->next)
+ if (fontp->file != NULL && fontp->timestamp <= oldest) {
+ f = fontp;
+ oldest = fontp->timestamp;
+ }
+ if (f == NULL)
+ oops("Can't find an open pixel file to close");
+ Fclose(f->file);
+ f->file = NULL;
+ ++n_files_left;
+}
+
+/*
+ * This is necessary on some systems to work around a bug.
+ */
+
+#if SUNOS4
+static void
+close_small_file()
+{
+ struct font *fontp;
+ unsigned short oldest = ~0;
+ struct font *f = NULL;
+
+ if (debug & DBG_OPEN)
+ Puts("Calling close_small_file()");
+
+ for (fontp = font_head; fontp != NULL; fontp = fontp->next)
+ if (fontp->file != NULL && fontp->timestamp <= oldest
+ && (unsigned char) fileno(fontp->file) < 128) {
+ f = fontp;
+ oldest = fontp->timestamp;
+ }
+ if (f == NULL)
+ oops("Can't find an open pixel file to close");
+ Fclose(f->file);
+ f->file = NULL;
+ ++n_files_left;
+}
+#else
+#define close_small_file close_a_file
+#endif
+
+/*
+ * Open a file in the given mode.
+ */
+
+FILE *
+#ifndef VMS
+xfopen(filename, type)
+ _Xconst char *filename;
+ _Xconst char *type;
+#define TYPE type
+#else
+xfopen(filename, type, type2)
+ _Xconst char *filename;
+ _Xconst char *type;
+ _Xconst char *type2;
+#define TYPE type, type2
+#endif /* VMS */
+{
+ FILE *f;
+
+ if (n_files_left == 0) close_a_file();
+ f = fopen(filename, TYPE);
+#ifndef VMS
+ if (f == NULL && (errno == EMFILE || errno == ENFILE))
+#else /* VMS */
+ if (f == NULL && errno == EVMSERR && vaxc$errno == RMS$_ACC)
+#endif /* VMS */
+ {
+ n_files_left = 0;
+ close_a_file();
+ f = fopen(filename, TYPE);
+ }
+ if (f != NULL) {
+ --n_files_left;
+#ifdef F_SETFD
+ (void) fcntl(fileno(f), F_SETFD, 1);
+#endif
+ }
+ return f;
+}
+#undef TYPE
+
+
+#if XAW
+
+/*
+ * Plain ordinary open() system call. Don't adjust n_files_left.
+ */
+
+int
+xopen(path, flags)
+ _Xconst char *path;
+ int flags;
+{
+ int fd;
+
+ if (n_files_left == 0)
+ close_a_file();
+
+ fd = open(path, flags);
+ if (fd == -1 && (errno == EMFILE || errno == ENFILE)) {
+ n_files_left = 0;
+ close_a_file();
+ fd = open(path, flags);
+ }
+
+ return fd;
+}
+
+#endif /* XAW */
+
+
+/*
+ * Create a pipe, closing a file if necessary.
+ * We use socketpair() instead of pipe() because several operating
+ * systems don't support SIGPOLL/SIGIO on pipes:
+ * SGI IRIX 6.5 F_SETOWN not implemented
+ * Linux 2.4.2 Not supported
+ */
+
+int
+xpipe(fd)
+ int *fd;
+{
+ int retval;
+
+ while (n_files_left < 2) close_a_file();
+ for (;;) {
+ retval = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+ if (retval == 0) {
+ n_files_left -= 2;
+ break;
+ }
+ if ((errno != EMFILE && errno != ENFILE))
+ break;
+ n_files_left = 0;
+ close_a_file();
+ }
+ return retval;
+}
+
+
+/*
+ * Open a directory for reading, opening a file if necessary.
+ */
+
+DIR *
+xopendir(name)
+ _Xconst char *name;
+{
+ DIR *retval;
+
+ if (n_files_left == 0) close_a_file();
+ for (;;) {
+ retval = opendir(name);
+ if (retval == NULL || (errno != EMFILE && errno != ENFILE)) break;
+ n_files_left = 0;
+ close_a_file();
+ }
+ if (retval != NULL) --n_files_left;
+ return retval;
+}
+
+
+/*
+ * Perform tilde expansion, updating the character pointer unless the
+ * user was not found.
+ */
+
+_Xconst struct passwd *
+ff_getpw(pp, p_end)
+ _Xconst char **pp;
+ _Xconst char *p_end;
+{
+ _Xconst char *p = *pp;
+ _Xconst char *p1;
+ unsigned len;
+ _Xconst struct passwd *pw;
+ int count;
+
+ ++p; /* skip the tilde */
+ p1 = p;
+ while (p1 < p_end && *p1 != '/') ++p1;
+ len = p1 - p;
+
+ if (len != 0) {
+ if (len >= ffline_len)
+ expandline(len);
+ bcopy(p, ffline, len);
+ ffline[len] = '\0';
+ }
+
+ for (count = 0;; ++count) {
+ if (len == 0) /* if no user name */
+ pw = getpwuid(getuid());
+ else
+ pw = getpwnam(ffline);
+
+ if (pw != NULL) {
+ *pp = p1;
+ return pw;
+ }
+
+ /* On some systems, getpw{uid,nam} return without setting errno,
+ * even if the call failed because of too many open files.
+ * Therefore, we play it safe here.
+ */
+ if (count >= 2 && len != 0 && getpwuid(getuid()) != NULL)
+ return NULL;
+
+ close_small_file();
+ }
+}
+
+
+/*
+ *
+ * Read size bytes from the FILE fp, constructing them into a
+ * signed/unsigned integer.
+ *
+ */
+
+unsigned long
+num(fp, size)
+ FILE *fp;
+ int size;
+{
+ long x = 0;
+
+ while (size--) x = (x << 8) | one(fp);
+ return x;
+}
+
+long
+snum(fp, size)
+ FILE *fp;
+ int size;
+{
+ long x;
+
+#if __STDC__
+ x = (signed char) getc(fp);
+#else
+ x = (unsigned char) getc(fp);
+ if (x & 0x80) x -= 0x100;
+#endif
+ while (--size) x = (x << 8) | one(fp);
+ return x;
+}
+
+
+#if FREETYPE || PS
+
+/*
+ * General AVL tree mechanism. Search for a node, and return it if found.
+ * Otherwise insert a node.
+ * This uses the AVL algorithm from Knuth Vol. 3.
+ */
+
+struct avl *
+avladd(key, key_len, headp, size)
+ _Xconst char *key;
+ size_t key_len;
+ struct avl **headp;
+ size_t size;
+{
+ struct avl *ap;
+ struct avl **app;
+ struct avl *sp; /* place where rebalancing may be necessary */
+ struct avl **spp; /* points to sp */
+ int i;
+
+ /* Search */
+ spp = app = headp;
+ for (;;) {
+ ap = *app;
+ if (ap == NULL) /* bottom of tree */
+ break;
+ if (ap->bal != 0)
+ spp = app;
+ i = key_len - ap->key_len;
+ if (i == 0)
+ i = memcmp(key, ap->key, key_len);
+ if (i == 0) /* found record already */
+ return ap;
+ if (i < 0) /* move left */
+ app = &ap->left;
+ else
+ app = &ap->right;
+ }
+
+ /* Insert */
+ ap = xmalloc(size);
+ ap->key = key;
+ ap->key_len = key_len;
+ ap->bal = 0;
+ ap->left = ap->right = NULL;
+ *app = ap;
+
+ /* Adjust balance factors */
+ sp = *spp;
+ if (sp == ap)
+ return ap;
+ i = key_len - sp->key_len;
+ if (i == 0)
+ i = memcmp(key, sp->key, key_len);
+ sp = (i < 0 ? sp->left : sp->right);
+ while (sp != ap) {
+ i = key_len - sp->key_len;
+ if (i == 0)
+ i = memcmp(key, sp->key, key_len);
+ if (i < 0) {
+ sp->bal = -1;
+ sp = sp->left;
+ }
+ else {
+ sp->bal = 1;
+ sp = sp->right;
+ }
+ }
+
+ /* Balancing act */
+ sp = *spp;
+ i = key_len - sp->key_len;
+ if (i == 0)
+ i = memcmp(key, sp->key, key_len);
+ if (i < 0) {
+ if (sp->bal >= 0)
+ --sp->bal;
+ else { /* need to rebalance */
+ struct avl *left;
+
+ left = sp->left;
+ if (left->bal < 0) { /* single rotation */
+ sp->left = left->right;
+ left->right = sp;
+ sp->bal = left->bal = 0;
+ *spp = left;
+ }
+ else { /* double rotation */
+ struct avl *newtop;
+
+ newtop = left->right;
+ sp->left = newtop->right;
+ newtop->right = sp;
+ left->right = newtop->left;
+ newtop->left = left;
+ sp->bal = left->bal = 0;
+ if (newtop->bal < 0) ++sp->bal;
+ else if (newtop->bal > 0) --left->bal;
+ newtop->bal = 0;
+ *spp = newtop;
+ }
+ }
+ }
+ else {
+ if (sp->bal <= 0)
+ ++sp->bal;
+ else { /* need to rebalance */
+ struct avl *right;
+
+ right = sp->right;
+ if (right->bal > 0) { /* single rotation */
+ sp->right = right->left;
+ right->left = sp;
+ sp->bal = right->bal = 0;
+ *spp = right;
+ }
+ else { /* double rotation */
+ struct avl *newtop;
+
+ newtop = right->left;
+ sp->right = newtop->left;
+ newtop->left = sp;
+ right->left = newtop->right;
+ newtop->right = right;
+ sp->bal = right->bal = 0;
+ if (newtop->bal > 0) --sp->bal;
+ else if (newtop->bal < 0) ++right->bal;
+ newtop->bal = 0;
+ *spp = newtop;
+ }
+ }
+ }
+
+ return ap;
+}
+
+#endif /* FREETYPE || PS */
+
+
+/*
+ * On 64-bit platforms, XGetWindowProperty and related functions convert
+ * properties with format=32 to arrays of longs. This function keeps that
+ * convention.
+ * The return value is the total number of bytes in the buffer.
+ */
+
+#if defined(WORD64) || defined(LONG64)
+# define LONG_CONV_64(bytes, format) ((bytes) << ((format) >> 5))
+#else
+# define LONG_CONV_64(bytes, format) (bytes)
+#endif
+
+size_t
+property_get_data(w, a, ret_buf, x_get_property)
+ Window w;
+ Atom a;
+ unsigned char **ret_buf;
+ int (*x_get_property) ARGS((Display *, Window, Atom, long,
+ long, Bool, Atom, Atom *, int *, unsigned long *,
+ unsigned long *, unsigned char **));
+{
+ /* all of these are in 8-bit units */
+ unsigned long byte_offset = 0;
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems_ret;
+ unsigned long bytes_after_ret = 0;
+ unsigned char *prop_ret = NULL;
+
+ /*
+ * buffer for collecting returned data; this is static to
+ * avoid expensive malloc()s at every call (which is often!)
+ */
+ static unsigned char *buffer = NULL;
+ static size_t buffer_len = 0;
+
+ while (x_get_property(DISP, w,
+ a, byte_offset / 4, (bytes_after_ret + 3) / 4, False, a,
+ &type_ret, &format_ret, &nitems_ret, &bytes_after_ret, &prop_ret)
+ == Success) {
+
+ if (type_ret != a || format_ret == 0) break;
+
+ nitems_ret *= (format_ret / 8); /* convert to bytes */
+
+ if (LONG_CONV_64(byte_offset + nitems_ret, format_ret)
+ >= buffer_len) {
+ buffer_len += 256
+ * ((LONG_CONV_64(byte_offset + nitems_ret, format_ret)
+ - buffer_len) / 256 + 1);
+ buffer = (buffer == NULL ? xmalloc(buffer_len)
+ : xrealloc(buffer, buffer_len));
+ }
+
+ /* the +1 captures the extra '\0' that Xlib puts after the end. */
+ memcpy(buffer + LONG_CONV_64(byte_offset, format_ret), prop_ret,
+ LONG_CONV_64(nitems_ret, format_ret) + 1);
+ byte_offset += nitems_ret;
+
+ XFree(prop_ret);
+ prop_ret = NULL;
+
+ if (bytes_after_ret == 0) /* got all data */
+ break;
+ }
+
+ if (prop_ret != NULL)
+ XFree(prop_ret);
+
+ *ret_buf = buffer;
+ return LONG_CONV_64(byte_offset, format_ret);
+}
+
+
+#if PS
+
+/*
+ * Create a temporary file and return its fd. Also put its filename
+ * in str. Create str if it's NULL.
+ */
+
+#ifndef P_tmpdir
+#define P_tmpdir "/tmp"
+#endif
+
+static _Xconst char tmp_suffix[] = "/xdvi-XXXXXX";
+
+int
+xdvi_temp_fd(str)
+ char **str;
+{
+ int fd;
+ char *p;
+ size_t len;
+ static _Xconst char *template = NULL;
+#if !HAVE_MKSTEMP
+ static unsigned long seed;
+ static char letters[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._";
+ char *p1;
+#endif
+
+ if (*str != NULL) {
+ p = *str;
+ if (n_files_left == 0) close_a_file();
+ /* O_EXCL is there for security (if root runs xdvi) */
+ fd = open(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ if (fd == -1 && (errno == EMFILE || errno == ENFILE)) {
+ n_files_left = 0;
+ close_a_file();
+ fd = open(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ }
+ if (!(fd == -1 && errno == EEXIST))
+ return fd;
+#if HAVE_MKSTEMP
+ memcpy(p + strlen(p) - 6, "XXXXXX", 6);
+#endif
+ }
+ else {
+ if (template == NULL) {
+ _Xconst char *ourdir;
+
+ ourdir = getenv("TMPDIR");
+ if (ourdir == NULL || access(ourdir, W_OK) < 0) {
+ ourdir = P_tmpdir;
+ if (access(ourdir, W_OK) < 0)
+ ourdir = ".";
+ }
+ len = strlen(ourdir);
+ if (len > 0 && ourdir[len - 1] == '/') --len;
+ template = p = xmalloc(len + sizeof tmp_suffix);
+ memcpy(p, ourdir, len);
+ memcpy(p + len, tmp_suffix, sizeof tmp_suffix);
+#if !HAVE_MKSTEMP
+ seed = 123456789 * time(NULL) + 987654321 * getpid();
+#endif
+ }
+ *str = p = xstrdup(template);
+ }
+
+ if (n_files_left == 0) close_a_file();
+
+#if HAVE_MKSTEMP
+ fd = mkstemp(p);
+ if (fd == -1 && (errno == EMFILE || errno == ENFILE)) {
+ n_files_left = 0;
+ close_a_file();
+ memcpy(p + strlen(p) - 6, "XXXXXX", 6);
+ fd = mkstemp(p);
+ }
+#else
+ p1 = p + strlen(p) - 6;
+ for (;;) {
+ unsigned long s = ++seed;
+ char *p2;
+
+ for (p2 = p1 + 5; p2 >= p1; --p2) {
+ *p2 = letters[s & 63];
+ s >>= 6;
+ }
+ fd = open(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ if (fd == -1 && (errno == EMFILE || errno == ENFILE)) {
+ n_files_left = 0;
+ close_a_file();
+ fd = open(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ }
+ if (!(fd == -1 && errno == EEXIST))
+ break;
+ }
+#endif
+
+ return fd;
+}
+
+#endif /* PS */
+
+
+/*
+ * Prepare the file descriptor to generate SIGPOLL/SIGIO events.
+ * If called with a True argument, set it up for non-blocking I/O.
+ */
+
+void
+prep_fd(fd, noblock)
+ int fd;
+ wide_bool noblock;
+{
+ /* Set file descriptor for non-blocking I/O */
+ if (noblock)
+ (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+#if !FLAKY_SIGPOLL
+# if HAVE_STREAMS
+ if (isastream(fd) > 0) {
+ if (ioctl(fd, I_SETSIG,
+ S_RDNORM | S_RDBAND | S_HANGUP | S_WRNORM) == -1)
+ perror("xdvi: ioctl I_SETSIG");
+ }
+ else
+# endif
+ {
+# ifdef FASYNC
+ if (fcntl(fd, F_SETOWN, getpid()) == -1)
+ perror("xdvi: fcntl F_SETOWN");
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | FASYNC) == -1)
+ perror("xdvi: fcntl F_SETFL");
+# elif defined SIOCSPGRP && defined FIOASYNC
+ /* For HP-UX B.10.10 and maybe others. See "man 7 socket". */
+ int arg;
+
+ arg = getpid();
+ if (ioctl(fd, SIOCSPGRP, &arg) == -1)
+ perror("xdvi: ioctl SIOCSPGRP");
+ arg = 1;
+ if (ioctl(fd, FIOASYNC, &arg) == -1)
+ perror("xdvi: ioctl FIOASYNC");
+# endif
+ }
+#endif /* not FLAKY_SIGPOLL */
+}
diff --git a/version.h b/version.h
@@ -0,0 +1 @@
+#define VERSION "22.86"
diff --git a/vf.c b/vf.c
@@ -0,0 +1,152 @@
+/*========================================================================*\
+
+Copyright (c) 1992-1999 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * VF font reading routines.
+ * Public routine is read_index---because virtual characters are presumed
+ * to be short, we read the whole virtual font in at once, instead of
+ * faulting in characters as needed.
+ */
+
+#include "xdvi.h"
+#include "dvi.h"
+
+#define LONG_CHAR 242
+
+/*
+ * These are parameters which determine whether macros are combined for
+ * storage allocation purposes. Small macros ( <= VF_PARM_1 bytes) are
+ * combined into chunks of size VF_PARM_2.
+ */
+
+#ifndef VF_PARM_1
+#define VF_PARM_1 20
+#endif
+#ifndef VF_PARM_2
+#define VF_PARM_2 256
+#endif
+
+/*
+ * The main routine
+ */
+
+void
+read_VF_index(fontp, hushcs)
+ struct font *fontp;
+ wide_bool hushcs;
+{
+ FILE *VF_file = fontp->file;
+ ubyte cmnd;
+ ubyte *avail, *availend; /* available space for macros */
+ long checksum;
+
+ fontp->read_char = NULL;
+ fontp->flags |= FONT_VIRTUAL;
+ fontp->set_char_p = set_vf_char;
+ if (debug & DBG_PK)
+ Printf("Reading VF pixel file %s\n", fontp->filename);
+/*
+ * Read preamble.
+ */
+ Fseek(VF_file, (long) one(VF_file), 1); /* skip comment */
+ checksum = four(VF_file);
+ if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
+ && !hushcs)
+ Fprintf(stderr,
+ "Checksum mismatch (dvi = %lu, vf = %lu) in font file %s\n",
+ fontp->checksum, checksum, fontp->filename);
+ (void) four(VF_file); /* skip design size */
+/*
+ * Read the fonts.
+ */
+ fontp->vf_table = xmalloc(VFTABLELEN * sizeof(struct font *));
+ bzero((char *) fontp->vf_table, VFTABLELEN * sizeof(struct font *));
+ fontp->vf_chain = NULL;
+ fontp->first_font = NULL;
+ while ((cmnd = one(VF_file)) >= FNTDEF1 && cmnd <= FNTDEF4) {
+ struct font *newfontp = define_font(VF_file, cmnd, fontp,
+ fontp->vf_table, VFTABLELEN, &fontp->vf_chain);
+ if (fontp->first_font == NULL) fontp->first_font = newfontp;
+ }
+/*
+ * Prepare macro array.
+ */
+ fontp->macro = xmalloc(256 * sizeof(struct macro));
+ bzero((char *) fontp->macro, 256 * sizeof(struct macro));
+/*
+ * Read macros.
+ */
+ avail = availend = NULL;
+ for (; cmnd <= LONG_CHAR; cmnd = one(VF_file)) {
+ struct macro *m;
+ int len;
+ unsigned long cc;
+ long width;
+
+ if (cmnd == LONG_CHAR) { /* long form packet */
+ len = four(VF_file);
+ cc = four(VF_file);
+ width = four(VF_file);
+ if (cc >= 256) {
+ Fprintf(stderr,
+ "Virtual character %lu in font %s ignored.\n",
+ cc, fontp->fontname);
+ Fseek(VF_file, (long) len, 1);
+ continue;
+ }
+ }
+ else { /* short form packet */
+ len = cmnd;
+ cc = one(VF_file);
+ width = num(VF_file, 3);
+ }
+ m = &fontp->macro[cc];
+ m->dvi_adv = width * fontp->dimconv;
+ if (len > 0) {
+ if (len <= availend - avail) {
+ m->pos = avail;
+ avail += len;
+ }
+ else {
+ m->free_me = True;
+ if (len <= VF_PARM_1) {
+ m->pos = avail = xmalloc(VF_PARM_2);
+ availend = avail + VF_PARM_2;
+ avail += len;
+ }
+ else m->pos = xmalloc((unsigned) len);
+ }
+ Fread((char *) m->pos, 1, len, VF_file);
+ m->end = m->pos + len;
+ }
+ if (debug & DBG_PK)
+ Printf("Read VF macro for character %lu; dy = %ld, length = %d\n",
+ cc, m->dvi_adv, len);
+ }
+ if (cmnd != POST)
+ oops("Wrong command byte found in VF macro list: %d", cmnd);
+
+ Fclose(VF_file);
+ fontp->file = NULL;
+ ++n_files_left;
+}
diff --git a/xautocnf.pat b/xautocnf.pat
@@ -0,0 +1,276 @@
+diff -ur autoconf-2.13/Makefile.in xautoconf-2.13/Makefile.in
+--- autoconf-2.13/Makefile.in Tue Jan 5 05:27:16 1999
++++ xautoconf-2.13/Makefile.in Mon Feb 1 14:44:50 1999
+@@ -49,7 +49,7 @@
+
+ # Directory in which to install library files.
+ datadir = @datadir@
+-acdatadir = $(datadir)/autoconf
++acdatadir = $(datadir)/xautoconf
+
+ # Directory in which to install documentation info files.
+ infodir = @infodir@
+@@ -178,7 +178,7 @@
+ if test -f standards.info || test -f $(srcdir)/standards.info; \
+ then cd $(infodir) && rm -f standards.info*; fi
+
+-${srcdir}/configure: configure.in $(M4FILES)
++${srcdir}/configure: configure.in
+ cd $(srcdir) && \
+ rm -f configure configure.tmp && \
+ $(M4) autoconf.m4 configure.in > configure.tmp && \
+diff -ur autoconf-2.13/acconfig.h xautoconf-2.13/acconfig.h
+--- autoconf-2.13/acconfig.h Tue Jan 5 05:27:26 1999
++++ xautoconf-2.13/acconfig.h Mon Feb 1 14:45:36 1999
+@@ -132,6 +132,9 @@
+ /* Define if you have the wait3 system call. */
+ #undef HAVE_WAIT3
+
++/* Define if your installation of X has X11/Xosdefs.h. */
++#undef HAVE_X11_XOSDEFS_H
++
+ /* Define as __inline if that's what the C compiler calls it. */
+ #undef inline
+
+diff -ur autoconf-2.13/acgeneral.m4 xautoconf-2.13/acgeneral.m4
+--- autoconf-2.13/acgeneral.m4 Tue Jan 5 05:27:37 1999
++++ xautoconf-2.13/acgeneral.m4 Mon Feb 1 15:11:41 1999
+@@ -169,10 +169,12 @@
+ # Initialize some variables set by options.
+ # The variables have the same names as the options, with
+ # dashes changed to underlines.
++aux_top=NONE
+ build=NONE
+ cache_file=./config.cache
+ exec_prefix=NONE
+ host=NONE
++imake=
+ no_create=
+ nonopt=NONE
+ no_recursion=
+@@ -187,6 +189,7 @@
+ verbose=
+ x_includes=NONE
+ x_libraries=NONE
++x_top=NONE
+ dnl Installation directory options.
+ dnl These are left unexpanded so users can "make install exec_prefix=/foo"
+ dnl and all the variables that are supposed to be based on exec_prefix
+@@ -234,6 +237,12 @@
+
+ case "$ac_option" in
+
++ -aux-top | --aux-top | --aux-to | --aux-t | --aux- | --aux | --au | --a)
++ ac_prev=aux_top ;;
++ -aux-top=* | --aux-top=* | --aux-to=* | --aux-t=* | --aux-=* | --aux=* \
++ | --au=* | --a=*)
++ aux_top="$ac_optarg" ;;
++
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+@@ -306,12 +315,15 @@
+ Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
++ --imake set flag for running from within imake
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+ Directory and file names:
++ --x-top=XTOP installation directory for X
++ --aux-top=AUXTOP secondary X top directory (e.g., for toolkit)
+ --prefix=PREFIX install architecture-independent files in PREFIX
+- [$ac_default_prefix]
++ [XTOP or $ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+@@ -344,8 +356,8 @@
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+- --x-includes=DIR X include files are in DIR
+- --x-libraries=DIR X library files are in DIR
++ --x-includes=DIR X include files are in DIR [XTOP/include or guessed]
++ --x-libraries=DIR X library files are in DIR [XTOP/lib or guessed]
+ changequote([, ])dnl
+ EOF
+ if test -n "$ac_help"; then
+@@ -358,6 +370,9 @@
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
++ --imake | --imak | --ima | --im | -imake | -imak | -ima | -im)
++ imake=yes ;;
++
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+@@ -529,10 +544,6 @@
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+- --x)
+- # Obsolete; use --with-x.
+- with_x=yes ;;
+-
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+@@ -547,6 +558,11 @@
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
++ -x-top | --x-top | --x-to | --x-t)
++ ac_prev=x_top ;;
++ -x-top=* | --x-top=* | --x-to=* | --x-t=*)
++ x_top="$ac_optarg" ;;
++
+ -*) AC_MSG_ERROR([$ac_option: invalid option; use --help to show usage])
+ ;;
+
+@@ -646,6 +662,9 @@
+ if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+ if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
++# Set prefix to x-top if appropriate.
++test "x$prefix" = xNONE && prefix="$x_top"
++
+ # confdefs.h avoids OS command line length limits that DEFS can exceed.
+ rm -rf conftest* confdefs.h
+ # AIX cpp loses on an empty file, so make sure it contains at least a newline.
+@@ -705,6 +724,7 @@
+ AC_SUBST(LDFLAGS)dnl
+ AC_SUBST(LIBS)dnl
+ AC_SUBST(exec_prefix)dnl
++AC_SUBST(x_top)dnl
+ AC_SUBST(prefix)dnl
+ AC_SUBST(program_transform_name)dnl
+ dnl Installation directory options.
+@@ -2072,6 +2092,9 @@
+ # Let make expand exec_prefix.
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
++# A kludge necessary for CPPFLAGS to allow quoted args
++CPPFLAGS="`echo "$CPPFLAGS" | sed 's/\\\"/\\\\\\\"/g'`"
++
+ # Any assignment to VPATH causes Sun make to only execute
+ # the first set of double-colon rules, so remove it if not needed.
+ # If there is a colon in the path, we need to keep it.
+@@ -2232,9 +2255,15 @@
+ fi
+ EOF
+
++if test -n "$imake"; then
++ ac_noimake_makefile=
++else
++ ac_noimake_makefile='Makefile '
++fi
++
+ cat >> $CONFIG_STATUS <<EOF
+
+-CONFIG_FILES=\${CONFIG_FILES-"$1"}
++CONFIG_FILES=\${CONFIG_FILES-"$ac_noimake_makefile$1"}
+ EOF
+ cat >> $CONFIG_STATUS <<\EOF
+ for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+diff -ur autoconf-2.13/acspecific.m4 xautoconf-2.13/acspecific.m4
+--- autoconf-2.13/acspecific.m4 Tue Jan 5 05:27:52 1999
++++ xautoconf-2.13/acspecific.m4 Mon Feb 1 15:07:16 1999
+@@ -716,6 +716,18 @@
+ fi])
+ if test $ac_cv_header_stdc = yes; then
+ AC_DEFINE(STDC_HEADERS)
++ AC_CACHE_CHECK([for X11/Xosdefs.h], ac_cv_x11_xosdefs_h,
++ [ac_cv_x11_xosdefs_h=no
++ if test -n "$x_includes"; then
++ if test -r "$x_includes/X11/Xosdefs.h"; then
++ ac_cv_x11_xosdefs_h=yes
++ fi
++ else
++ AC_TRY_CPP([#include <X11/Xosdefs.h>], ac_cv_x11_xosdefs_h=yes)
++ fi])
++ if test $ac_cv_x11_xosdefs_h = yes; then
++ AC_DEFINE(HAVE_X11_XOSDEFS_H)
++ fi
+ fi
+ ])
+
+@@ -2299,7 +2311,6 @@
+ # --without-x overrides everything else, but does not touch the cache.
+ AC_MSG_CHECKING(for X)
+
+-AC_ARG_WITH(x, [ --with-x use the X Window System])
+ # $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+ if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+@@ -2311,8 +2322,15 @@
+ else
+ AC_CACHE_VAL(ac_cv_have_x,
+ [# One or both of the vars are not set, and there is no cached value.
+-ac_x_includes=NO ac_x_libraries=NO
+-AC_PATH_X_XMKMF
++if test "x$x_top" != xNONE; then
++ ac_x_includes="$x_top/include" ac_x_libraries="$x_top/lib"
++ if test ! -f "$ac_x_includes/X11/Xos.h" || test ! -d "$ac_x_libraries"; then
++ AC_MSG_ERROR($x_top does not point to a valid X install tree)
++ fi
++else
++ ac_x_includes=NO ac_x_libraries=NO
++ AC_PATH_X_XMKMF
++fi
+ AC_PATH_X_DIRECT
+ if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then
+ # Didn't find X anywhere. Cache the known absence of X.
+@@ -2502,11 +2520,14 @@
+ dnl Find additional X libraries, magic flags, etc.
+ AC_DEFUN(AC_PATH_XTRA,
+ [AC_REQUIRE([AC_PATH_X])dnl
+-if test "$no_x" = yes; then
+- # Not all programs may use this symbol, but it does not hurt to define it.
+- AC_DEFINE(X_DISPLAY_MISSING)
++if test "$no_x" = yes || test -n "$imake"; then
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+ else
++ if test "x$aux_top" != xNONE; then
++ X_CFLAGS="$X_CFLAGS -I$aux_top/include"
++ X_LIBS="$X_LIBS -L$aux_top/lib"
++ fi
++
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+@@ -2524,12 +2545,18 @@
+ AC_TRY_LINK(, , ac_R_nospace=yes, ac_R_nospace=no)
+ if test $ac_R_nospace = yes; then
+ AC_MSG_RESULT(no)
++ if test "x$aux_top" != xNONE; then
++ X_LIBS="$X_LIBS -R$aux_top/lib"
++ fi
+ X_LIBS="$X_LIBS -R$x_libraries"
+ else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ AC_TRY_LINK(, , ac_R_space=yes, ac_R_space=no)
+ if test $ac_R_space = yes; then
+ AC_MSG_RESULT(yes)
++ if test "x$aux_top" != xNONE; then
++ X_LIBS="$X_LIBS -R $aux_top/lib"
++ fi
+ X_LIBS="$X_LIBS -R $x_libraries"
+ else
+ AC_MSG_RESULT(neither works)
+@@ -2611,6 +2638,13 @@
+ AC_SUBST(X_LIBS)dnl
+ AC_SUBST(X_EXTRA_LIBS)dnl
+ ])
++
++dnl Require the program to be compiled with X.
++AC_DEFUN(AC_REQUIRE_X,
++[AC_REQUIRE([AC_PATH_X])dnl
++if test "x$have_x" != xyes; then
++ AC_MSG_ERROR(this program cannot be compiled without X)
++fi])
+
+ dnl The old Cygwin32 macro is deprecated.
+ AC_DEFUN(AC_CYGWIN32,
diff --git a/xautocnf.txt b/xautocnf.txt
@@ -0,0 +1,16 @@
+The configure script provided with xdvi was created by a modified version
+of GNU autoconf version 2.13. If you need to re-generate it for any reason,
+you should get autoconf version 2.13, apply the patches in the file
+xautocnf.pat, and build with
+
+ ./configure --program-transform-name=s/^/x/
+
+(and whatever other arguments you find necessary), then
+
+ make all install
+
+The changes are only those necessary for xdvi; this is not intended to
+provide a general package for configure scripts for X programs, although
+it may provide a basis for such a package if anyone wants to pick this up.
+
+--Paul Vojta, vojta@math.berkeley.edu
diff --git a/xdvi-man.sed b/xdvi-man.sed
@@ -0,0 +1,3244 @@
+.\" Copyright (c) 1990-2013 Paul Vojta
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a copy
+.\" of this software and associated documentation files (the "Software"), to
+.\" deal in the Software without restriction, including without limitation the
+.\" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+.\" sell copies of the Software, and to permit persons to whom the Software is
+.\" furnished to do so, subject to the following conditions:
+.\"
+.\" The above copyright notice and this permission notice shall be included in
+.\" all copies or substantial portions of the Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+.\" IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+.\" THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+.\" WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+.\" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+.\" IN THE SOFTWARE.
+.\"
+.if t .ds Te T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.if n .ds Te TeX
+' # small and boldface (not all -man's provide it)
+.de SB
+\&\fB\s-1\&\\$1 \\$2\s0\fR
+..
+.TH XDVI 1 "18 April 2013" "X Version 11"
+.SH NAME
+xdvi \- DVI Previewer for the X Window System
+.SH SYNOPSIS
+.B xdvi
+.nh
+[\fB+\fP[\fIpage\fP]] [\fB\-s\fP \fIshrink\fP] [\fB\-S\fP \fIdensity\fP]
+#ifcolor
+[\fB\-nocolor\fP]
+#endif
+#ifgrey
+[\fB\-nogrey\fP] [\fB\-gamma\fP \fIg\fP] [\fB\-install\fP] [\fB\-noinstall\fP]
+#endif
+[\fB\-p\fP \fIpixels\fP]
+[\fB\-margins\fP \fIdimen\fP]
+[\fB\-sidemargin\fP \fIdimen\fP] [\fB\-topmargin\fP \fIdimen\fP]
+[\fB\-offsets\fP \fIdimen\fP]
+[\fB\-xoffset\fP \fIdimen\fP] [\fB\-yoffset\fP \fIdimen\fP]
+[\fB\-paper\fP \fIpapertype\fP] [\fB\-altfont\fP \fIfont\fP]
+#ifmakepk
+[\fB\-nomakepk\fP]
+#endif
+[\fB\-mfmode\fP \fImode-def\fP[\fB:\fP\fIdpi\fP]]
+#ifft
+[\fB\-nofreetypefonts\fP]
+#endif
+[\fB\-editor\fP \fIeditor\fP]
+[\fB\-sourceposition\fP \fIline\fP[\fB:\fP\fIcol\fP][\ ]\fIfilename\fP]
+[\fB\-nofork\fP]
+[\fB\-l\fP]
+[\fB\-rv\fP]
+#ifbuttons
+[\fB\-expert\fP]
+[\fB\-shrinkbutton\fP\fIn\fP \fIshrink\fP]
+#endif
+[\fB\-mgs\fP[\fIn\fP] \fIsize\fP] [\fB\-warnspecials\fP]
+[\fB\-hush\fP]
+[\fB\-hushchars\fP] [\fB\-hushchecksums\fP]
+[\fB\-safer\fP]
+[\fB\-fg\fP \fIcolor\fP] [\fB\-bg\fP \fIcolor\fP] [\fB\-hl\fP \fIcolor\fP]
+[\fB\-bd\fP \fIcolor\fP] [\fB\-cr\fP \fIcolor\fP]
+[\fB\-bw\fP \fIwidth\fP]
+[\fB\-display\fP \fIhost:display\fP] [\fB\-geometry\fP \fIgeometry\fP]
+[\fB\-icongeometry\fP \fIgeometry\fP] [\fB\-iconic\fP]
+#ifbuttons
+[\fB\-font\fP \fIfont\fP]
+#endif
+[\fB\-keep\fP] [\fB\-copy\fP] [\fB\-thorough\fP]
+[\fB\-wheelunit\fP \fIpixels\fP]
+[\fB\-noscan\fP]
+#ifps
+[\fB\-nopostscript\fP]
+[\fB\-allowshell\fP]
+#endif
+#ifdps
+[\fB\-nodps\fP]
+#endif
+#ifnews
+[\fB\-nonews\fP]
+#endif
+#ifghost
+[\fB\-noghostscript\fP]
+[\fB\-nogssafer\fP]
+[\fB\-gsalpha\fP]
+[\fB\-interpreter\fP \fIpath\fP]
+[\fB\-gspalette\fP \fIpalette\fP]
+#endif
+#iftool
+[\fB\-dvipspath\fP \fIpath\fP]
+#endif
+[\fB\-debug\fP \fIbitmask\fP] [\fB\-version\fP]
+.I dvi_file
+.hy
+.SH DESCRIPTION
+.B xdvi
+is a program which runs under the X window system. It is used to preview
+.I dvi
+files, such as are produced by
+.BR tex (1).
+.PP
+This program has the capability of showing the file shrunken by various
+(integer) factors, and also has a ``magnifying glass'' which allows one
+to see a small part of the unshrunk image momentarily.
+.PP
+Before displaying any page or part thereof, it checks to see if the
+.I dvi
+file has changed since the last time it was displayed. If this is the case,
+then
+.B xdvi
+will reinitialize itself for the new
+.I dvi
+file. For this reason, exposing parts of the
+.B xdvi
+window while \*(Te\& is running should be avoided. This feature allows you
+to preview many versions of the same file while running
+.B xdvi
+only once.
+#iftool
+.PP
+If
+.B xdvi
+is run without the
+.I dvi-file
+argument, then it pops up a window asking for a
+.I dvi
+file.
+#endif
+#ifbuttons
+.PP
+In addition to using keystrokes to move within the file,
+.B xdvi
+provides buttons on the right side of the window, which are synonymous
+with various sequences of keystrokes.
+#endif
+#ifps
+.PP
+.B xdvi
+can show PostScript<tm> specials by any of three methods.
+It will try first to use Display PostScript<tm>, then NeWS, then it
+will try to use Ghostscript to render the images. All of these options
+depend on additional software to work properly; moreover, some of them
+may not be compiled into this copy of
+.BR xdvi .
+.PP
+For performance reasons,
+.B xdvi
+does not render PostScript specials in the magnifying glass.
+#endif
+.SH OPTIONS
+In addition to specifying the
+.I dvi
+file (with or without the
+.B .dvi
+extension),
+.B xdvi
+supports the following command line options. If the option begins with a
+.RB ` + '
+instead of a
+.RB ` \- ',
+the option is restored to its default value. By default, these options can
+be set via the resource names given in parentheses in the description of
+each option.
+.TP
+.BI + page
+Specifies the first page to show. If
+.B +
+is given without a number, the last page is assumed; the first page is
+the default.
+#ifps
+.TP
+.B \-allowshell
+.RB ( .allowShell )
+This option enables the shell escape in PostScript specials.
+(For security reasons, shell escapes are disabled by default.)
+This option should be rarely used; in particular it should not be used just
+to uncompress files: that function is done automatically if the file name
+ends in
+.BR .Z ,
+.BR .gz ,
+or
+.BR .bz2 .
+Shell escapes are always turned off if the
+.B \-safer
+option is used.
+#endif
+.TP
+.BI \-altfont " font"
+.RB ( .altFont )
+Declares a default font to use when the font in the
+.I dvi
+file cannot be found. This is useful, for example, with PostScript <tm> fonts.
+.TP
+.BI \-background " color"
+.RB ( .background )
+Determines the color of the background. Same as
+.BR -bg .
+.TP
+.BI \-bd " color"
+.RB ( .borderColor )
+Determines the color of the window border.
+.TP
+.BI \-bg " color"
+.RB ( .background )
+Determines the color of the background.
+.TP
+.BI \-bordercolor " color"
+Same as
+.BR -bd .
+.TP
+.BI \-borderwidth " width"
+.RB ( .borderWidth )
+Specifies the width of the border of the window. Same as
+.BR -bw .
+.TP
+.BI \-bw " width"
+.RB ( .borderWidth )
+Specifies the width of the border of the window.
+.TP
+.B \-copy
+.RB ( .copy )
+Always use the
+.I copy
+operation when writing characters to the display.
+This option may be necessary for correct operation on a color display, but
+overstrike characters will be incorrect.
+#ifgrey
+If greyscale anti-aliasing is in use, the
+.B \-copy
+operation will disable the use of colorplanes and make overstrikes come
+out incorrectly.
+#endif
+See also
+.BR \-thorough .
+.TP
+.BI \-cr " color"
+.RB ( .cursorColor )
+Determines the color of the cursor. The default is the color of the page
+border.
+.TP
+.BI \-debug " bitmask"
+.RB ( .debugLevel )
+If nonzero, prints additional debugging information on standard output.
+The bitmask should be given as a decimal number. The values of the bits
+are defined in the source file
+.BR xdvi.h .
+.TP
+.BI \-density " density"
+.RB ( .densityPercent )
+Determines the density used when shrinking bitmaps for fonts.
+A higher value produces a lighter font. The default value is 40.
+#ifgrey
+If greyscaling is in use, this argument does not apply; use
+.B \-gamma
+instead.
+#endif
+See also the
+.RB ` S '
+keystroke.
+Same as
+.BR \-S .
+.TP
+.BI \-display " host" : display
+Specifies the host and screen to be used for displaying the
+.I dvi
+file. By default this is obtained from the environment variable
+.SB DISPLAY.
+#iftool
+.TP
+.BI \-dvipspath " path"
+.RB ( .dvipsPath )
+Use
+.I path
+as the
+.B dvips
+program to use when printing. By default it uses
+.BR dvips .
+#endif
+.TP
+.BI \-editor " editor"
+.RB ( .editor )
+Specifies the editor to be invoked for reading the source file corresponding to
+the
+.I dvi
+file. For details on how to do this, see the section on SOURCE SPECIALS.
+#ifbuttons
+.TP
+.B \-expert
+.RB ( .expert )
+Prevent the buttons from appearing. See also the
+.RB ` x '
+keystroke.
+#endif
+.TP
+.BI \-fg " color"
+.RB ( .foreground )
+Determines the color of the text (foreground).
+.TP
+.BI \-foreground " color"
+Same as
+.BR -fg .
+#ifbuttons
+.TP
+.BI \-font " font"
+.RB ( *font )
+Sets the font for use in the buttons.
+#endif
+#ifgrey
+.TP
+.BI \-gamma " gamma"
+.RB ( .gamma )
+Controls the interpolation of colors in the greyscale anti-aliasing color
+palette. Default value is 1.0. For 0 <
+.I gamma
+< 1, the fonts will be lighter (more like the background), and for
+.I gamma
+> 1, the fonts will be darker (more like the foreground). Negative
+values behave the same way, but use a slightly different algorithm.
+For color and grayscale displays; for monochrome, see
+.BR \-density .
+See also the
+.RB ` S '
+keystroke.
+#endif
+.TP
+.BI \-geometry " geometry"
+.RB ( *geometry )
+Specifies the initial geometry of the window.
+#ifghost
+.TP
+.BI \-gspalette " palette"
+.RB ( .palette )
+Specifies the palette to be used when using Ghostscript for rendering
+PostScript specials. Possible values are
+.BR Color ,
+.BR Greyscale ,
+and
+.BR Monochrome .
+The default is
+.BR Color .
+.TP
+.B \-gsalpha
+.RB ( .gsAlpha )
+Causes
+.B Ghostscript
+to be called with the
+.B x11alpha
+driver instead of the
+.B x11
+driver. The
+.B x11alpha
+driver enables anti-aliasing in PostScript figures, for a nicer appearance.
+It is available on newer versions of
+.BR Ghostscript .
+This option can also be toggled with the
+.RB ` V '
+keystroke.
+#endif
+.TP
+.BI \-hl " color"
+.RB ( .highlight )
+Determines the color of the page border. The default is the foreground color.
+.TP
+.B \-hush
+.RB ( .Hush )
+Causes
+.B xdvi
+to suppress all suppressible warnings.
+.TP
+.B \-hushchars
+.RB ( .hushLostChars )
+Causes
+.B xdvi
+to suppress warnings about references to characters which are not defined
+in the font.
+.TP
+.B \-hushchecksums
+.RB ( .hushChecksums )
+Causes
+.B xdvi
+to suppress warnings about checksum mismatches between the
+.I dvi
+file and the font file.
+.TP
+.BI \-icongeometry " geometry"
+.RB ( .iconGeometry )
+Specifies the initial position for the icon.
+.TP
+.B \-iconic
+.RB ( .iconic )
+Causes the
+.B xdvi
+window to start in the iconic state. The default is to start with the
+window open.
+#ifgrey
+.TP
+.B \-install
+.RB ( .install )
+If
+.B xdvi
+is running under a
+.B PseudoColor
+visual, then (by default) it will check for
+.B TrueColor
+visuals with more bits per pixel, and switch to such a visual if one exists.
+If no such visual exists, it will use the current visual and colormap. If
+.B \-install
+is selected, however, it will still use a
+.B TrueColor
+visual with a greater depth, if one is available; otherwise, it will
+install its own colormap on the current visual. If the current visual is not
+.BR PseudoColor ,
+then
+.B xdvi
+will not switch the visual or colormap, regardless of its options.
+The default value of the
+.B install
+resource is the special value,
+.BR maybe .
+There is no
+.B +install
+option. See also
+.BR \-noinstall ,
+and the GREYSCALING AND COLORMAPS section.
+#endif
+#ifghost
+.TP
+.BI \-interpreter " filename"
+.RB ( .interpreter )
+Use
+.I filename
+as the Ghostscript interpreter. By default it uses
+.BR @GS_PATH@ .
+#endif
+.TP
+.B \-keep
+.RB ( .keepPosition )
+Sets a flag to indicate that
+.B xdvi
+should not move to the home position when moving to a new page. See also the
+.RB ` k '
+keystroke.
+.TP
+.B \-l
+.RB ( .listFonts )
+Causes the names of the fonts used to be listed.
+.TP
+.BI \-margins " dimen"
+.RB ( .Margin )
+Specifies the size of both the top margin and side margin.
+This determines the ``home'' position of the page within the window as
+follows. If the entire page fits in the window, then the margin settings
+are ignored. If, even after removing the margins from the left, right,
+top, and bottom, the page still cannot fit in the window, then the page
+is put in the window such that the top and left margins are hidden, and
+presumably the upper left-hand corner of the text on the page will be
+in the upper left-hand corner of the window.
+Otherwise, the text is centered in the window.
+The dimension should be a decimal number optionally followed by
+any of the two-letter abbreviations for units accepted by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+By default, the unit will be
+.BR @DEFAULT_UNIT@.
+See also
+.BR \-sidemargin ", " \-topmargin ,
+and the keystroke
+.RB ` M .'
+.TP
+.BI \-mfmode " mode-def\fR[\fP\fB:\fPdpi\fR]\fP"
+.RB ( .mfMode )
+Specifies a
+.I mode-def
+string, which can be used in searching for fonts (see ENVIRONMENT, below).
+Generally, when changing the
+.IR mode-def ,
+it is also necessary to change the font size to the appropriate value
+for that mode. This is done by adding a colon and the value in dots per inch;
+for example,
+.BR "\-mfmode ljfour:600" .
+This method overrides any value given by the
+.B pixelsPerInch
+resource or the
+.B \-p
+command-line argument.
+#ifmakepk
+The metafont mode is also passed to
+.B metafont
+during automatic creation of fonts.
+#endif
+By default, it is
+.BR "@MFMODE@" .
+.TP
+.BI \-mgs " size"
+Same as
+.BR \-mgs1 .
+.TP
+.BI "\-mgs\fR[\fIn\fR]" " size"
+.RB ( .magnifierSize\fR[\fIn\fR] )
+Specifies the size of the window to be used for the ``magnifying glass''
+for Button
+.IR n .
+The size may be given as an integer (indicating that the magnifying glass
+is to be square), or it may be given in the form
+.IR width x height .
+See the MOUSE ACTIONS section. Defaults are 200x150, 400x250, 700x500,
+1000x800, and 1200x1200.
+#ifcolor
+.TP
+.B \-nocolor
+.RB ( .color )
+Turns off the use of color specials. This option can be toggled with the
+.RB ` C '
+keystroke.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nocolor
+corresponds to
+.BR color:off ;
+.B +nocolor
+to
+.BR color:on .)
+#endif
+#ifdps
+.TP
+.B \-nodps
+.RB ( .dps )
+Inhibits the use of Display PostScript<tm> for displaying PostScript<tm>
+specials. Other forms of PostScript emulation, if installed, will be used
+instead.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nodps
+corresponds to
+.BR dps:off ;
+.B +nodps
+to
+.BR dps:on .)
+#endif
+.TP
+.B \-nofork
+.RB ( .fork )
+When the
+.B \-sourceposition
+argument is used and there is no appropriate instance of
+.B xdvi
+already running, then the default behavior is for
+.B xdvi
+to run itself in the background (as if it were a daemon). This argument
+makes it run in the foreground instead. This is useful for debugging,
+or if
+.B xdvi
+is run from a broken set of
+.B emacs
+macros. If no
+.B \-sourceposition
+argument is given, then this option has no effect.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nofork
+corresponds to
+.BR fork:off ;
+.B +nofork
+to
+.BR fork:on .)
+#ifft
+.TP
+.B \-nofreetypefonts
+.RB ( .freetypeFonts )
+This will disable the use of the FreeType library to display PostScript<tm>
+Type 1 fonts. Use this option as a workaround when you encounter problems
+with the display of Type 1 fonts (but please don't forget to send a bug report
+in this case, to the URL mentioned in the section AUTHORS below).
+.br
+(Note:
+.B \-nofreetypefonts
+corresponds to
+.BR freetypeFonts:off ;
+.B +nofreetypefonts
+to
+.BR freetypeFonts:on .)
+#endif
+#ifghost
+.TP
+.B \-noghostscript
+.RB ( .ghostscript )
+Inhibits the use of Ghostscript for displaying PostScript<tm> specials.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-noghostscript
+corresponds to
+.BR ghostscript:off ;
+.B +noghostscript
+to
+.BR ghostscript:on .)
+#endif
+#ifgrey
+.TP
+.B \-nogrey
+.RB ( .grey )
+Turns off the use of greyscale anti-aliasing when printing shrunken bitmaps.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nogrey
+corresponds to
+.BR grey:off ;
+.B +nogrey
+to
+.BR grey:on .)
+See also the
+.RB ` G '
+keystroke.
+#endif
+#ifghost
+.TP
+.B \-nogssafer
+.RB ( .gsSafer )
+Normally, if Ghostscript is used to render PostScript specials, the Ghostscript
+interpreter is run with the option
+.BR \-dSAFER .
+The
+.B \-nogssafer
+option runs Ghostscript without
+.BR \-dSAFER .
+The
+.B \-dSAFER
+option in Ghostscript disables PostScript operators such as
+.BR deletefile ,
+to prevent possibly malicious PostScript programs from having any effect.
+It also prevents access to files whose paths reference the parent directory
+of the current directory (i.e., files whose paths contain the characters
+.RB `` ../ '');
+this is a feature of Ghostscript that cannot be overridden. If the
+.B \-safer
+option is specified, then this option has no effect; in that case Ghostscript
+is always run with
+.BR \-dSAFER .
+(For the
+.B \-nogssafer
+option, the logic of the corresponding resource is reversed:
+.B \-nogssafer
+corresponds to
+.BR gsSafer:off ;
+.B +nogssafer
+to
+.BR gsSafer:on .)
+#endif
+#ifgrey
+.TP
+.B \-noinstall
+.RB ( .install )
+Inhibit the default behavior of switching to a
+.B TrueColor
+visual if one is available with more bits per pixel than the current visual.
+This option corresponds to a resource of
+.BR install:off .
+There is no
+.B +noinstall
+option. See also
+.BR \-install ,
+and the GREYSCALING AND COLORMAPS section.
+#endif
+#ifmakepk
+.TP
+.B \-nomakepk
+.RB ( .makePk )
+Turns off automatic generation of font files that cannot be found by other
+means.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nomakepk
+corresponds to
+.BR makePk:off ;
+.B +nomakepk
+to
+.BR makePK:on .)
+#endif
+#ifnews
+.TP
+.B \-nonews
+.RB ( .news )
+Inhibits the use of NeWS<tm> for displaying PostScript<tm> specials.
+Ghostscript, if enabled by the installation, will be used instead.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nonews
+corresponds to
+.BR news:off ;
+.B +news
+to
+.BR news:on .)
+#endif
+#ifps
+.TP
+.B \-nopostscript
+.RB ( .postscript )
+Turns off rendering of PostScript<tm> specials. Bounding boxes, if known,
+will be displayed instead. This option can also be toggled with the
+.RB ` v '
+keystroke.
+(For this option, the logic of the corresponding resource is reversed:
+.B \-nopostscript
+corresponds to
+.BR postscript:off ;
+.B +postscript
+to
+.BR postscript:on .)
+#endif
+.TP
+.B \-noscan
+.RB ( .prescan )
+By default,
+.B xdvi
+does a preliminary scan of the
+.I dvi
+file, in order to process any
+.B papersize
+specials; this is especially important at startup since the paper size may be
+needed to determine the window size.
+#ifps
+If PostScript<tm> is in use, then prescanning is also necessary in order to
+properly process header files.
+#fi
+#ifcolor
+In addition, prescanning is needed to correctly determine the background color
+of a page.
+#fi
+This option turns off such prescanning.
+(Prescanning will be automatically be turned back on if
+.B xdvi
+detects any of the specials mentioned above.) (For the
+.B \-noscan
+option, the logic of the corresponding resource is reversed:
+.B \-noscan
+corresponds to
+.BR prescan:off ;
+.B +noscan
+to
+.BR prescan:on .)
+.TP
+.BI \-offsets " dimen"
+.RB ( .Offset )
+Specifies the size of both the horizontal and vertical offsets of the
+output on the page. By decree of the Stanford \*(Te\& Project,
+the default \*(Te\& page origin is always 1 inch over and down from
+the top-left page corner, even when non-American paper sizes are used.
+Therefore, the default offsets are 1.0 inch.
+The argument
+.I dimen
+should be a decimal number optionally followed by any of the two-letter
+abbreviations for units accepted by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+By default, the unit will be
+.BR @DEFAULT_UNIT@.
+See also
+.B \-xoffset
+and
+.BR \-yoffset .
+.TP
+.BI \-p " pixels"
+.RB ( .pixelsPerInch )
+Defines the size of the fonts to use, in pixels per inch. The
+default value is @BDPI@. This option is provided only for backwards
+compatibility; the preferred way of setting the font size is by setting the
+Metafont mode at the same time; see the
+.B \-mfmode
+option.
+.TP
+.BI \-paper " papertype"
+.RB ( .paper )
+Specifies the size of the printed page. This may be of the form
+\fIwidth\fBx\fIheight\fR optionally followed by a unit, where
+.I width
+and
+.I height
+are decimal numbers giving the width and height of the paper, respectively,
+and the unit is any of the two-letter abbreviations for units accepted
+by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+By default, the unit will be
+.BR @DEFAULT_UNIT@.
+There are also synonyms which may be used:
+.B letter
+(8.5x11in),
+.B us
+(8.5x11in, same as
+.BR letter ),
+.B legal
+(8.5x14in),
+.B foolscap
+(13.5x17in),
+as well as the ISO sizes
+.BR a1 - a7 ,
+.BR b1 - b7 ,
+.BR c1 - c7 .
+Each of these also has a landscape or `rotated' variant:
+.B letterr
+(11x8.5in),
+.BR a1r - a7r ,
+etc. Any of the above sizes may be preceded by a plus sign
+.RB (` + ');
+this causes the paper size given here to override any paper size given in the
+.I dvi
+file. The default paper size is @DEFAULT_PAGE_SIZE@.
+.TP
+.B \-rv
+.RB ( .reverseVideo )
+Causes the page to be displayed with white characters on a black background,
+instead of vice versa.
+.TP
+.BI \-s " shrink"
+.RB ( .shrinkFactor )
+Defines the initial shrink factor. The default value is @SHRINK@. If
+.I shrink
+is given as 0, then the initial shrink factor is computed so that the
+page fits within the window (as if the `s' keystroke were given without
+a number).
+.TP
+.BI \-S " density"
+.RB ( .densityPercent )
+Same as
+.BR \-density ,
+.I q.v.
+.TP
+.B \-safer
+.RB ( .safer )
+This option turns on all available security options; it is designed for use when
+.B xdvi
+is called by a browser that obtains a
+.I dvi
+or \*(Te\& file from another site.
+#ifps
+In the present case, this option selects
+#endif
+#ifghost
+.B +nogssafer
+and
+#endif
+#ifps
+.BR +allowshell .
+#endif
+#ifnops
+In the present case, this option is accepted but has no effect, since
+.B xdvi
+has been compiled without support for PostScript specials.
+#endif
+#ifbuttons
+.TP
+.BI \-shrinkbutton "n shrink"
+.RB ( .shrinkButton\fIn\fP )
+Specifies that the
+.IR n th
+button changing shrink factors shall change to shrink factor
+.IR factor .
+This is useful, e.g., when using 600 dpi fonts, since in that case shrinking
+by a factor of 4 is still not enough. Here
+.I n
+may be a number from 1 to 3 (in the default button layout, the ``Full Size''
+button is unaffected by these options). If the buttons are customized,
+higher values of
+.I n
+(up to 9) may be used.
+#endif
+.TP
+.BI \-sidemargin " dimen"
+.RB ( .sideMargin )
+Specifies the side margin (see
+.BR \-margins ).
+.TP
+.BI \-sourceposition " line\fR[\fP\fB:\fPcol\fR][ ]\fPfilename"
+.RB ( .sourcePosition )
+This option makes
+.B xdvi
+search in the
+.I dvi
+file for the place corresponding to the indicated line (and, optionally,
+column) in the .tex source file, and highlight the place found by drawing a
+rectangle in the
+.I highlight
+color (see the
+.B \-hl
+option) around the corresponding text. In addition, when run with this
+argument (and the
+.B \-nofork
+option is not given; q.v.),
+.B xdvi
+will always return immediately: if it finds another instance of
+.B xdvi
+already showing
+.I dvi_file,
+then it will cause that instance to raise its window and move to the given
+place in the
+.I dvi
+file; otherwise it will start up its own instance in the background.
+This option requires that
+.I dvi_file
+be prepared with source special information. See the section on SOURCE SPECIALS
+for more details.
+.TP
+.B \-thorough
+.RB ( .thorough )
+.B xdvi
+will usually try to ensure that overstrike characters
+.RI ( e.g. ,
+.BR \enotin )
+are printed correctly. On monochrome displays, this is always possible
+with one logical operation, either
+.I and
+or
+.IR or .
+On color displays, however, this may take two operations, one to set the
+appropriate bits and one to clear other bits. If this is the case, then
+by default
+.B xdvi
+will instead use the
+.I copy
+operation, which does not handle overstriking correctly. The
+.B \-thorough
+option chooses the slower but more correct choice. See also
+.BR \-copy .
+.TP
+.BI \-topmargin " dimen"
+.RB ( .topMargin )
+Specifies the top and bottom margins (see
+.BR \-margins ).
+.TP
+.BI \-version
+Print information on the version of
+.BR xdvi .
+.TP
+.B \-warnspecials
+.RB ( .warnSpecials )
+Causes
+.B xdvi
+to issue warnings about
+.B \especial
+strings that it cannot process.
+.TP
+.BI \-wheelunit " pixels"
+.RB ( .wheelUnit )
+Sets the number of pixels that a motion of a wheel mouse will move the
+image up, down, left, or right. If set to zero, the wheel mouse
+functionality is (essentially) disabled. The default value is 80.
+.TP
+.BI \-xoffset " dimen"
+.RB ( .xOffset )
+Specifies the size of the horizontal offset of the output on the page. See
+.BR \-offsets .
+.TP
+.BI \-yoffset " dimen"
+.RB ( .yOffset )
+Specifies the size of the vertical offset of the output on the page. See
+.BR -offsets .
+.SH KEYSTROKES
+.B xdvi
+recognizes the following keystrokes when typed in its window.
+Each may optionally be preceded by a (positive or negative) number, whose
+interpretation will depend on the particular keystroke.
+Also, the ``Home'', ``Prior'', ``Next'', and arrow cursor keys are synonyms for
+.RB ` ^ ',
+.RB ` b ',
+.RB ` f ',
+.RB ` l ',
+.RB ` r ',
+.RB ` u ',
+and
+.RB ` d '
+keys, respectively.
+#iftool
+.PP
+The key assignments given here are those that
+.B xdvi
+assigns by default. They can be changed--see CUSTOMIZATION, below.
+The names appearing in brackets at the beginning of each of the following
+keystroke definitions is the name assigned to the action associated with
+that key, for use when customizing. Users who do not customize their
+keystrokes may ignore these labels.
+#
+.TP
+.B q
+#tool.RB [ quit() ]
+Quits the program. Control-C and control-D will do this, too.
+.TP
+.B n
+#tool.RB [ forward-page() ]
+Moves to the next page (or to the
+.IR n th
+next page if a number is given). Synonyms are
+.RB ` f ',
+Return, and Line Feed.
+.TP
+.I Space
+#tool.RB [ down-or-next() ]
+Moves down two-thirds of a window-full, or to the next page if already at
+the bottom of the page.
+.TP
+.B p
+#tool.RB [ back-page() ]
+Moves to the previous page (or back
+.I n
+pages). Synonyms are
+.RB ` b '
+and control-H.
+.TP
+.I Delete
+#tool.RB [ up-or-previous() ]
+Moves up two-thirds of a window-full, or to the bottom of the previous page
+if already at the top of the page. The BackSpace key will also do this.
+.TP
+.B g
+#tool.RB [ goto-page() ]
+Moves to the page with the given number. Initially, the first page is assumed
+to be page number 1, but this can be changed with the
+.RB ` P '
+keystroke, below. If no page number is given, then it goes to the last page.
+.TP
+.B P
+#tool.RB [ declare-page-number() ]
+``This is page number
+.IR n .''
+This can be used to make the
+.RB ` g '
+keystroke refer to actual page numbers instead of absolute page numbers.
+.TP
+.IB Control\- L
+#tool.RB [ forward-page(0) ]
+Redisplays the current page.
+.TP
+.B ^
+#tool.RB [ home() ]
+Move to the ``home'' position of the page. This is normally the upper
+left-hand corner of the page, depending on the margins as described in the
+.B \-margins
+option, above.
+.TP
+.B u
+#tool.RB [ up() ]
+Moves up two thirds of a window-full.
+.TP
+.B d
+#tool.RB [ down() ]
+Moves down two thirds of a window-full.
+.TP
+.B l
+#tool.RB [ left() ]
+Moves left two thirds of a window-full.
+.TP
+.B r
+#tool.RB [ right() ]
+Moves right two thirds of a window-full.
+.TP
+.B c
+#tool.RB [ center() ]
+Moves the page so that the point currently beneath the cursor is moved to
+the middle of the window. It also (gasp!) warps the cursor to the same place.
+.TP
+.B M
+#tool.RB [ set-margins() ]
+Sets the margins so that the point currently under the cursor is the upper
+left-hand corner of the text in the page. Note that this command itself does
+not move the image at all. For details on how the margins are used, see
+the
+.B \-margins
+option.
+#iftool
+.TP
+.IB Control\- O
+.RB [ open-dvi-file() ]
+Pop up a window asking for a new
+.I dvi
+file.
+.TP
+.IB Control\- P
+.RB [ print() ]
+Pop up a window to allow
+.B xdvi
+to print the
+.I dvi
+file or a range of pages from it. The popup window is mostly self-explanatory,
+but the window showing
+.B dvips
+progress accepts some keystrokes that are not obvious. In that second window,
+.IB Control\- C
+is equivalent to clicking on the
+.B Cancel
+button,
+.I Return
+is equivalent to clicking on the
+.B Close window
+button, and
+.IB Control\- S
+and
+.IB Control\- Q
+select and deselect, respectively, the option of keeping the window open after
+.B dvips
+finishes.
+#endif
+.TP
+.B s
+#tool.RB [ set-shrink-factor() ]
+Changes the shrink factor to the given number. If no number is given, the
+smallest factor that makes the entire page fit in the window will be used.
+(Margins are ignored in this computation.)
+.TP
+.B S
+#tool.RB [ set-density() ]
+Sets the density factor to be used when shrinking bitmaps. This should
+be a number between 0 and 100; higher numbers produce lighter characters.
+#ifgrey
+If greyscaling mode is in effect, this changes the value of gamma instead.
+The new value of gamma is the given number divided by 100; negative values
+are allowed.
+#endif
+.TP
+.B R
+#tool.RB [ reread-dvi-file() ]
+Forces the
+.I dvi
+file to be reread. This allows you to preview many versions of the same
+file while running
+.B xdvi
+only once.
+.TP
+.B k
+#tool.RB [ set-keep-flag() ]
+Normally when
+.B xdvi
+switches pages, it moves to the home position as well. The
+.RB ` k '
+keystroke toggles a `keep-position' flag which, when set, will keep
+the same position when moving between pages. Also
+.RB ` 0k '
+and
+.RB ` 1k '
+clear and set this flag, respectively. See also the
+.B \-keep
+option.
+#ifbuttons
+.TP
+.B x
+#tool.RB [ set-expert-mode() ]
+Toggles expert mode (in which the buttons do not appear). Also
+.RB ` 0x '
+and
+.RB ` 1x '
+clear and reset this mode, respectively. See also the
+.B \-expert
+option.
+#endif
+#ifgrey
+.TP
+.B G
+#tool.RB [ set-greyscaling() ]
+This key toggles the use of greyscale anti-aliasing for displaying shrunken
+bitmaps. In addition, the key sequences
+.RB ` 0G '
+and
+.RB ` 1G '
+clear and set this flag, respectively. See also the
+.B \-nogrey
+option.
+#endif
+#ifcolor
+.TP
+.B C
+#tool.RB [ set-color() ]
+This key toggles the use of color specials. The key sequences
+.RB ` 0C '
+and
+.RB ` 1C '
+turn interpretation of color specials off and on, respectively.
+See also the
+.B \-nocolor
+option.
+#endif
+#ifps
+.TP
+.B v
+#tool.RB [ set-ps() ]
+This key toggles the rendering of PostScript<tm> specials. If rendering
+is turned off, then bounding boxes are displayed when available.
+In addition the key sequences
+.RB ` 0v '
+and
+.RB ` 1v '
+clear and set this flag, respectively. See also the
+.B \-nopostscript
+option.
+#endif
+#ifghost
+.TP
+.B V
+#tool.RB [ set-gs-alpha() ]
+This key toggles the anti-aliasing of PostScript<tm> specials when
+.B Ghostscript
+is used as renderer. In addition the key sequences
+.RB ` 0V '
+and
+.RB ` 1V '
+clear and set this flag, respectively. See also the
+.B \-gsalpha
+option.
+#endif
+.SH MOUSE ACTIONS
+If the shrink factor is set to any number other than one, then clicking
+any mouse button will pop up a ``magnifying glass'' which shows the unshrunk
+image in the vicinity of the mouse click. This subwindow disappears when
+the mouse button is released. Different mouse buttons produce different sized
+windows, as indicated by the
+.B \-mgs
+option. Moving the cursor while holding the button down will move the
+magnifying glass. To access this feature via customization, use the
+.B magnifier
+action. Its argument is either a string of the form
+.IR width x height ,
+as in the
+.BI \-mgs n
+command-line option, or one of the strings
+.B *1
+through
+.BR *5 ,
+referring to the value specified by the corresponding
+.BI \-mgs n
+option.
+.PP
+The scrollbars (if present) behave in the standard way: pushing Button 2
+in a scrollbar moves the top or left edge of the scrollbar to that point
+and optionally drags it;
+pushing Button 1 moves the image up or right by an amount equal to the distance
+from the button press to the upper left-hand corner of the window; pushing
+Button 3 moves the image down or left by the same amount.
+.PP
+The image can also be dragged around, by holding down the shift key
+and a mouse button. Shift-button 1 will allow vertical dragging only;
+Shift-button 3, horizontal dragging; and Shift-button 2 allows dragging
+in either direction. To access these actions via customization, use the
+.B drag
+action. This action should have one parameter, the character
+.RB `` | '',
+.RB `` - '',
+or
+.RB `` + '',
+indicating vertical dragging, horizontal dragging, or dragging in both
+directions.
+.PP
+Wheel mice are supported: motion of the wheel on such a mouse moves the
+image up, down, left, or right by the number of pixels indicated by the
+.B \-wheelunit
+option. To access this option via customization, use the
+.B wheel
+and
+.B hwheel
+action for vertical and horizontal scrolling, respectively. These actions
+take one parameter, giving the distance to scroll
+the image. If the parameter contains a decimal point, the distance is given
+in wheel units; otherwise, pixels. Not all wheel mice support horizontal
+scrolling.
+#iftool
+.SH UNBOUND ACTIONS
+The following actions have not been assigned any keystroke, but are available
+if customization is used.
+.TP
+.B shrink-to-dpi()
+This action takes one (required) argument. It sets the shrink factor to
+an integer so as to approximate the use of fonts with the corresponding
+number of dots per inch. If
+.B xdvi
+is using fonts scaled for
+.I p
+dots per inch, and the argument to
+.B shrink-to-dpi
+is
+.IR n ,
+then the corresponding shrink factor is the ratio
+.IR p / n ,
+rounded to the nearest integer.
+.SH CUSTOMIZATION
+Key and mouse button assignments can be changed by setting the
+.B mainTranslations
+resource to a string of translations as defined in the documentation for the
+X toolkit. The actions should take the form of action names as given in the
+KEYSTROKES and MOUSE ACTIONS sections.
+.PP
+Key actions will usually be without arguments, or they may give an argument
+to replace an optional number typed immediately prior to the action. The keys
+.BR 0 \- 9
+and hyphen cannot be reassigned, since they are used for inputting numbers.
+.PP
+Some key actions may take special arguments, as follows.
+The argument of
+.B goto-page
+may be the letter
+.RB ` e ',
+indicating the action of going to the end of the document.
+The argument of
+.B set-shrink-factor
+may be the letter
+.RB ` a ',
+indicating that the shrink factor should be set to the smallest value such that
+the page will fit in the window.
+The actions
+.BR up ,
+.BR down ,
+.BR left ,
+.BR right ,
+.BR up-or-previous ,
+and
+.BR down-or-next
+may give a decimal number, indicating what fraction of a window-full to move
+(in place of two thirds).
+Finally, for actions that would perform a toggle, such as
+.BR set-keep-flag ,
+the argument may be the letter
+.RB ` t ',
+indicating that the action should toggle regardless of what number may have
+been typed recently.
+.PP
+Mouse actions should refer only to
+.B ButtonPress
+events (e.g.,
+.BR "<Btn1Down>:magnifier(*1)" ).
+The corresponding motion and release events will then be handled internally.
+A key action may be bound to a mouse event, but not vice versa.
+.PP
+Usually the string of translations should begin with
+.RB `` #override '',
+indicating that the default key and mouse button assignments should not
+be discarded.
+.PP
+When keys or mouse buttons involving modifiers (such as Ctrl or Shift)
+are customized together with their non-modified equivalents, the modified
+keys should come first, for example:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+XDvi.mainTranslations: #override \\
+ Ctrl<Btn1Down>: magnifier(*3)\\n\\
+ Shift<Btn1Down>: magnifier(*2)\\n\\
+ <Btn1Down>: magnifier(*1)
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+Because
+.B xdvi
+needs to capture pointer motion events, and because the X Toolkit
+translations mechanism cannot accommodate both motion events and double-click
+events at the same time, it is not possible to specify double-click
+actions in
+.B xdvi
+customizations. For information on this and other aspects of translations,
+see the X Toolkit Intrinsics documentation.
+.PP
+There is no command-line option to set the
+.B mainTranslations
+resource, since changing this resource on the command line would be cumbersome.
+However, see the section on CUSTOMIZATION EXAMPLES for information on how
+to set the resource for testing purposes using the
+.B \-xrm
+command-line option.
+.PP
+Support of wheel mice is controlled by the
+.B wheelTranslations
+resource. Generally the only action routines called by this resource should be
+.B wheel
+and
+.BR hwheel .
+Its default value is
+.RS 5
+.nf
+.ft 3
+.sp 1n
+<Btn4Down>:wheel(-1.)\\n\\
+<Btn5Down>:wheel(1.)\\n\\
+<Btn6Down>:hwheel(-1.)\\n\\
+<Btn7Down>:hwheel(1.)
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+When specifying a value for this resource, all wheel actions should be
+included.
+.PP
+The X Toolkit routines that implement translations do not support event
+types of
+.B Btn6Down
+or
+.BR Btn7Down .
+Because of this,
+.B xdvi
+implements its own parser for translations given in
+.BR wheelTranslations .
+This parser is more limited than the parser built in to the X Toolkit.
+It should not begin with
+.RB `` #replace '',
+.RB `` #augment '',
+or
+.RB `` #override ''.
+Modifiers of the form
+.BI @ keysym
+are not supported, and the event type must be of the form
+.B BtnDown
+or
+.BI Btn n Down\fR,\fP
+where
+.I n
+is a positive integer without leading zeroes. Also, some limitations apply
+to the action field.
+#
+#ifbuttons
+.PP
+The button labels and actions may also be customized, in a similar manner.
+In this case the resource
+.B buttonTranslations
+should consist of a string describing the button labels and the associated
+actions. The string consists of substrings, separated by the newline
+character
+(`\fB\\n\fP'),
+each describing one button. Each substring consists of a string (to be
+used as the button's label), a colon, and a sequence of actions to be
+performed when the button is pushed. Unlike the situation with key actions,
+an action associated to a button should provide an argument (if applicable).
+.PP
+The label string may contain a colon if it is escaped by a backslash
+(`\fB\\\fP'). It also may contain some special sequences tied to the
+.BI \-shrinkbutton n
+command-line options. If the characters
+.RB ` $# '
+occur, then they are replaced by the argument of the corresponding
+.B \-shrinkbutton
+command-line option (if present). If no corresponding
+.B \-shrinkbutton
+option was given, then the value is taken from the list of actions, which
+is expected to contain at least one
+.B set-shrink-factor
+or
+.B shrink-to-dpi
+action. Likewise, the character sequence
+.RB ` $% '
+will be replaced by the percentage corresponding to the shrink factor,
+determined as above. In order for the
+.B \-shrinkbutton
+option to affect a given button, the label string must contain one of the
+character sequences
+.RB ` $# ',
+.RB ` $% ',
+or
+.RB ' $_ '.
+This last string flags a button to be affected by a
+.B \-shrinkbutton
+option, without making any numbers appear in the label text (the
+.RB ` $_ '
+will not appear in the label text).
+.PP
+Some resources are provided to allow customization of the geometry of
+the command buttons and the timing of the window that appears when
+.B dvips
+is processing a print request. Again, they are not changeable via
+command-line options, other than via the
+.B \-xrm
+option. All of these resources take integer values.
+.TP
+.B buttonSideSpacing
+The number of pixels to be placed on either side of the buttons.
+The default value is 6.
+.TP
+.B buttonTopSpacing
+The number of pixels between the top button and the top of the window.
+The default value is 50.
+.TP
+.B buttonBetweenSpacing
+The number of pixels between most buttons.
+The default value is 20.
+.TP
+.B buttonBetweenExtra
+The number of pixels of additional space to be inserted if the
+.B buttonTranslations
+resource string contains an extra newline character.
+The default value is 50.
+.TP
+.B buttonBorderWidth
+The border width of the button windows. The default value is 1.
+.TP
+.B dvipsHangTime
+The time, measured in milliseconds, that the ``Xdvi print process'' window will
+remain showing after
+.B dvips
+has successfully processed a print request. The default value is 700
+(0.7 seconds). If it is zero or negative, then the window will stay up until
+closed by the user.
+.TP
+.B dvipsFailHangTime
+This is the same as
+.BR dvipsHangTime ,
+except that it applies if
+.B dvips
+returns a status indicating failure. The default value is 3000 (3 seconds).
+#
+#iftool
+.SH CUSTOMIZATION EXAMPLES
+.PP
+Some users prefer that the window scroll smoothly when they hold down the
+arrow keys, instead of giving a large motion each time they type the keys.
+To get this scrolling behavior, the following resource can be used.
+.RS 5
+.nf
+.ft 3
+.sp 1n
+XDvi.mainTranslations: #override \\
+ <Key>Up:up(.01)\\n\\
+ <Key>Down:down(.01)\\n\\
+ <Key>Left:left(.01)\\n\\
+ <Key>Right:right(.01)
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+To set the
+.B mainTranslations
+resource for testing purposes, use the
+.B \-xrm
+command-line option provided by the X toolkit. For example,
+.RS 5
+.nf
+.ft 3
+.sp 1n
+xdvi \-xrm 'XDvi.mainTranslations: #override "z":quit()' ...
+.sp 1n
+.ft
+.fi
+.RE
+or
+.RS 5
+.nf
+.ft 3
+.sp 1n
+xdvi \-xrm 'XDvi.mainTranslations: #override <Key>z:quit()' ...
+.sp 1n
+.ft
+.fi
+.RE
+will cause the key
+.RB ` z '
+to quit
+.BR xdvi .
+This method also works with the other translation resources.
+#
+.SH SPECIALS (GENERALLY)
+Any of the specials used by
+.B xdvi
+may be preceded by the characters
+.RB `` xdvi: ''.
+Doing so does not change the behavior of the special under
+.BR xdvi ,
+but it causes other
+.I dvi
+viewers to ignore the special.
+.SH SOURCE SPECIALS
+With properly prepared
+.I dvi
+files,
+.B xdvi
+is capable of calling up an editor at the point in the file corresponding to
+any given point in the typeset output
+.RB (`` "reverse search" '').
+It can also be invoked so as to move to the place in the
+.I dvi
+file corresponding to a given line (and, optionally, column) in a given source
+file
+.RB (`` "forward search" '').
+Both of these capabilities require that the version of \*(Te\& used to
+produce the
+.I dvi
+file be compiled to support ``source specials,'' and that the
+.B \-src\-specials
+argument be used on the command line when running \*(Te\&.
+(Or, some special-purpose macro packages will also suffice for the above
+capabilities. In fact, column number information is not provided by any
+version of \*(Te\&; it must be provided by a macro package. This is because
+column information would make the
+.I dvi
+file too large; only special-purpose applications would benefit from it.)
+.P
+.B Reverse Search.
+Reverse search is done by moving the mouse to the desired position on the
+page displayed by
+.BR xdvi ,
+and pressing Button 1 while holding the Control button down.
+.P
+Each time this feature is used, a new copy of the editor is invoked.
+(The editor command can be a program such as
+.BR emacsclient ,
+however, which passes the information on to a running instance of an editor
+if possible.) The editor is specified by the
+.B \-editor
+command-line option, the
+.B .editor
+resource, or the
+.SB XEDITOR,
+.SB VISUAL,
+or
+.SB EDITOR
+environment variables; the first of these to specify a value determines the
+editor to call. If none of these are set, then the Unix editor
+.B vi
+is used. The value is a string called as a shell command, in which
+occurrences of the designator
+.RB `` %f ''
+are replaced by the file name, occurrences of
+.RB `` %l ''
+are replaced by the line number within the file, and (if supported)
+occurrences of
+.RB `` %c ''
+are replaced by the column number within the line. If no designator
+.RB `` %f ''
+occurs in the string, then
+.RB `` "+%l %f" ''
+is appended to the end of the string. If the string was found as the value
+of the
+.SB VISUAL
+or
+.SB EDITOR
+environment variables, then
+.RB `` "xterm -e "''
+is prepended to the string; if the editor is specified by other means, then
+it must be in the form of a shell command to pop up an X window with an
+editor in it.
+.P
+For debugging purposes, Ctrl-Button 2 will draw boxes around the first glyph
+or rule in a file occurring on source lines identified by source specials.
+In addition, Ctrl-Button 3 will draw similar boxes around all glyphs and rules
+in the file. These boxes are drawn in the color specified by the highlight
+color (the
+.B \-hl
+command-line option or the
+.B .highColor
+resource). In addition to glyphs and rules, certain PostScript specials also
+may be boxed (those providing a bounding box).
+.P
+The file to be edited is searched for first in the directory containing the
+.I dvi
+file, then in the path specified by the
+.SB XDVISOURCES
+or
+.SB TEXINPUTS
+environment variables.
+.P
+.B Forward search.
+Forward search is invoked on the command line (typically by a text editor),
+by specifying the
+.B \-sourceposition
+argument.
+.B xdvi
+The main dvi file
+.I dvi_file
+is specified as usual. ``Forward search'' means that xdvi will try to open
+the page in
+.I dvi_file
+corresponding to the given line number (and, optionally, column number)
+of the .tex source file
+.IR filename ,
+and highlight the place found by drawing a rectangle in the
+.I highlight
+color (see the
+.B \-hl
+option) around the corresponding text.
+.P
+In addition, the
+.B \-sourceposition
+option causes
+.B xdvi
+to run in client mode. ``Client mode'' means that if there is already
+another instance of
+.B xdvi
+running on this X display and displaying the same
+.IR dvi_file ,
+a new instance started with the
+.B -sourceposition
+option will only notify that running instance to perform the forward
+search, and exit after that. If no such instance of
+.B xdvi
+is found, then
+.B xdvi
+will start up a new instance in the background. Either way, when running
+in client mode,
+.B xdvi
+will always return immediately. This is set up so that other programs
+such as text editors may invoke
+.B xdvi
+in ``client mode'' to jump to a specific
+place in the
+.I dvi
+file corresponding to the current cursor position in the .tex file,
+and the user can continue editing without having to close the
+.B xdvi
+window first. (Note, however, that if the
+.B \-nofork
+argument is given on the command line, or the corresponding resource is
+set, then operation in client mode is a bit different in that
+.B xdvi
+will not run itself in the background if there is no instance already running.)
+.P
+The argument for
+.I filename
+should match the file name used for the source specials in the
+.I dvi
+file. The space before the
+.I filename
+is optional; it is only needed to avoid ambiguity if
+.I filename
+starts with a digit or a colon. Note that the argument needs to be enclosed
+in quotes if a space is used, to prevent the shell from
+misinterpreting the space as argument separator.
+.P
+Source specials in the
+.I dvi
+file must have one of the following formats:
+.RS 5
+.nf
+.sp 1n
+ \fBsrc:\fP\fIline\fP[ ]\fIfilename\fP
+ \fBsrc:\fP\fIline\fP\fB:\fP\fIcol\fP[ ]\fIfilename\fP
+ \fBsrc:\fP\fIline\fP
+ \fBsrc:\fP\fIline\fP\fB:\fP\fIcol\fP
+ \fBsrc::\fP\fIcol\fP
+.sp 1n
+.fi
+.RE
+.PP
+If
+.I filename
+or
+.I line
+are omitted, the most recent values are used. The first source special on
+each page must be in one of the first two forms, so that defaults are not
+inherited across pages.
+.SH PAPERSIZE SPECIALS
+.B xdvi
+accepts specials to set the paper size for the document. These specials
+should be of the form
+.RS 5
+.nf
+.sp 1n
+ \fBpapersize=\fP[\fB*\fP]\fIwidth\fP,\fIheight\fP
+.sp 1n
+.fi
+.RE
+.PP
+where
+.I width
+and
+.I height
+give the width and height of the paper, respectively. Each of these should
+appear in the form of a decimal number followed by any of the two-letter
+abbreviations for units accepted by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+If an asterisk
+.RB ( * )
+appears just before the width, then the measurements refer to the document
+dimensions (e.g.,
+.B pt
+as opposed to
+.BR truept ).
+This allows a macro package to vary the page size according to elements
+of the document; e.g.,
+.RS 5
+.nf
+.ft 3
+.sp 1n
+\\special{xdvi: papersize=*\\number\\wd\\mybox sp,\\number\\ht\\mybox sp}
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+Except for the asterisk, this format is compatible with
+.BR dvips .
+.P
+The last
+.B papersize
+special on a page determines the size of that page. If there is no such
+special on a given page, the most recent
+.B papersize
+is used, or, if there are no
+.B papersize
+specials on any preceding page, then the value of the
+.B paper
+resource (or
+.B \-paper
+option on the command line) is used. Thus the paper size may vary for
+different pages of the
+.I dvi
+file.
+.P
+If the
+.B paper
+resource (or
+.B \-paper
+command-line option) begins with a plus sign
+.RB (` + '),
+then all
+.B papersize
+specials in the
+.I dvi
+file are ignored.
+#ifcolor
+.SH COLOR SPECIALS
+The color specials supported by
+.B xdvi
+are the same as those supported by
+.BR dvips ,
+except that the literal PostScript color specification (as in the
+.B AggiePattern
+example in the
+.B dvips
+documentation) is not supported. In particular, the LaTeX
+.B color
+package will work with
+.BR xdvi .
+See the documentation of the LaTeX
+.B color
+package for details on its use, and also see the
+.B dvips
+documentation file
+.B dvips.tex
+for details on the syntax and semantics of the color specials.
+.P
+Support for color specials includes the same list of named colors as
+.BR dvips ,
+namely:
+.BR Apricot ,
+.BR Aquamarine ,
+.BR Bittersweet ,
+.BR Black ,
+.BR Blue ,
+.BR BlueGreen ,
+.BR BlueViolet ,
+.BR BrickRed ,
+.BR Brown ,
+.BR BurntOrange ,
+.BR CadetBlue ,
+.BR CarnationPink ,
+.BR Cerulean ,
+.BR CornflowerBlue ,
+.BR Cyan ,
+.BR Dandelion ,
+.BR DarkOrchid ,
+.BR Emerald ,
+.BR ForestGreen ,
+.BR Fuchsia ,
+.BR Goldenrod ,
+.BR Gray ,
+.BR Green ,
+.BR GreenYellow ,
+.BR JungleGreen ,
+.BR Lavender ,
+.BR LimeGreen ,
+.BR Magenta ,
+.BR Mahogany ,
+.BR Maroon ,
+.BR Melon ,
+.BR MidnightBlue ,
+.BR Mulberry ,
+.BR NavyBlue ,
+.BR OliveGreen ,
+.BR Orange ,
+.BR OrangeRed ,
+.BR Orchid ,
+.BR Peach ,
+.BR Periwinkle ,
+.BR PineGreen ,
+.BR Plum ,
+.BR ProcessBlue ,
+.BR Purple ,
+.BR RawSienna ,
+.BR Red ,
+.BR RedOrange ,
+.BR RedViolet ,
+.BR Rhodamine ,
+.BR RoyalBlue ,
+.BR RoyalPurple ,
+.BR RubineRed ,
+.BR Salmon ,
+.BR SeaGreen ,
+.BR Sepia ,
+.BR SkyBlue ,
+.BR SpringGreen ,
+.BR Tan ,
+.BR TealBlue ,
+.BR Thistle ,
+.BR Turquoise ,
+.BR Violet ,
+.BR VioletRed ,
+.BR White ,
+.BR WildStrawberry ,
+.BR Yellow ,
+.BR YellowGreen ,
+.BR YellowOrange .
+Note that these names are case sensitive.
+.P
+At present, the
+.B \ecolorbox
+and
+.B \efcolorbox
+macros are not supported. This includes use of the
+.B columncolor
+macro in the
+.B colortbl
+package, and the
+.B shaded
+environment in the
+.B framed
+La\*(Te\&2e package.
+#endif
+#ifgrey
+.SH GREYSCALING AND COLORMAPS
+The greyscale anti-aliasing feature in
+.B xdvi
+will not work at its best if the display does not have enough colors available.
+This can happen if other applications are using most of the colormap
+(even if they are iconified). If this occurs, then
+.B xdvi
+will print an error message and turn on the
+.B -copy
+option. This will result in overstrike characters appearing wrong;
+it may also result in poor display quality if the number of available
+colors is very small.
+.PP
+Typically this problem occurs on displays that allocate eight bits
+of video memory per pixel. To see how many bits per pixel your display
+uses, type
+.B xwininfo
+in an
+.B xterm
+window, and then click the mouse on the root window when asked. The
+``Depth:'' entry will tell you how many bits are allocated per pixel.
+.PP
+Displays using at least 15 bits per pixel are typically
+.B TrueColor
+visuals, which do not have this problem, since their colormap is
+permanently allocated and available to all applications. (The visual
+class is also displayed by
+.BR xwininfo .)
+For more information on visual classes see the documentation for the
+X Window System.
+.PP
+To alleviate this problem, therefore, one may (a) run with more bits
+per pixel (this may require adding more video memory or replacing the video
+card), (b) shut down other applications that may be using much of the colormap
+and then restart
+.BR xdvi ,
+or (c) run
+.B xdvi
+with the
+.B \-install
+option.
+.PP
+One application which is often the cause of this problem is
+.BR Netscape .
+In this case there are two more alternatives to remedying the situation.
+One can run
+.RB `` "netscape -install" ''
+to cause
+.B Netscape
+to install a private colormap. This can cause colors to change in
+bizarre ways when the mouse is moved to a different window.
+Or, one can run
+.RB `` "netscape -ncols 220" ''
+to limit
+.B Netscape
+to a smaller number of colors. A smaller number will ensure that
+other applications have more colors available, but will degrade the
+color quality in the
+.B Netscape
+window.
+#endif
+.SH SIGNALS
+When
+.B xdvi
+receives a
+.SB SIGUSR1
+signal, it rereads the
+.I dvi
+file.
+.SH ENVIRONMENT
+.TP
+.SB DISPLAY
+Specifies which graphics display terminal to use.
+#ifconfig
+.TP
+.SB TEXMFCNF
+Indicates a (colon-separated) list of directories to search for files named
+.BR texmf.cnf ,
+which are to be interpreted as configuration files. An extra colon anywhere
+in the list incorporates the compiled-in default value at that point.
+See the section CONFIGURATION FILES for more details on configuration files,
+how
+.B xdvi
+searches for them, and what they should contain.
+#endif
+.TP
+.SB TEXMF
+Indicates the top directory of \*(Te\& Directory Structure (TDS) trees to use
+when searching for files. It should be a list of directories, separated by
+colons. An extra colon anywhere in the variable incorporates the compiled-in
+default value at that point.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB XDVISIZES
+A list of font resolutions separated by colons. If a font cannot be found
+or made at its stated size, then these sizes are tried as a fallback.
+.B xdvi
+tries the actual size of the font before trying any of the given sizes.
+Each font resolution should be a positive integer, specifying the number
+of dots per inch, or a string of the form
+.BR magstep\fIn\fP ,
+where
+.I n
+is a number -9.5, -9, -8.5, ..., 8, 8.5, 9, or 9.5. The string
+.B magstep
+may be shortened to any non-empty initial substring (so that
+.B magstep0.5
+may be shortened to
+.B mag0.5
+or
+.B m0.5
+(but not
+.BR mag.5 )).
+The entries
+.BI magstep n
+signify the current pixels-per-inch value, multiplied by 1.2 raised to the
+.IR n th
+power, and rounded to the nearest integer.
+If the list begins with a colon, the system default sizes are used, as well.
+Sizes are expressed in dots per inch and must be integers.
+The current default set of sizes is @DEFAULT_FONT_SIZES@.
+.B xdvi
+will also try the actual size of the font before trying any of the given sizes.
+.TP
+.SB XDVIFONTS
+Determines the path(s) searched for
+.I pk
+and
+.I gf
+font pixel files. See the section on FILE SEARCHING for more details.
+#iftexfonts
+.TP
+.SB PKFONTS
+Determines the path(s) searched for
+.I pk
+and
+.I gf
+font pixel files if
+.SB XDVIFONTS
+is not set.
+.TP
+.SB TEXPKS
+Determines the path(s) searched for
+.I pk
+and
+.I gf
+font pixel files if neither
+.SB XDVIFONTS
+nor
+.SB PKFONTS
+is set.
+.TP
+.SB TEXFONTS
+Determines the path(s) searched for
+.I pk
+and
+.I gf
+font pixel files if none of
+.SB XDVIFONTS,
+.SB PKFONTS,
+and
+.SB TEXPKS
+are set. It may also be used for searching for fontmap files, encoding files,
+and Type 1 font files, if
+.B xdvi
+has been compiled with support for the FreeType library.
+If
+.SB TEXFONTS
+is used, it should not contain any
+.RB ` % '
+signs, since
+.B xdvi
+interprets this as a special character, but other applications do not.
+#endif
+.TP
+.SB XDVIVFS
+Determines the path(s) searched for virtual fonts
+.RI ( vf
+files). See the section on FILE SEARCHING for more details.
+#iftexfonts
+.TP
+.SB VFFONTS
+Determines the path(s) searched for
+.I vf
+fonts if
+.SB XDVIVFS
+is not set. If this is used, it should not contain any
+.RB ` % '
+signs, since
+.B xdvi
+interprets this as a special character, but other applications do not.
+#endif
+#ifps
+.TP
+.SB XDVIPICTS
+Determines the path(s) searched for PostScript figure files.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB TEXPICTS
+Determines the path(s) searched for PostScript figure files if
+.SB XDVIPICTS
+is not set.
+.TP
+.SB TEXINPUTS
+Determines the path(s) searched for PostScript figure files if neither
+.SB TEXPICTS
+nor
+.SB XDVIPICTS
+is set. Also determines the path(s) searched for source files if
+.SB XDVISOURCES
+is not set.
+.TP
+.SB XDVIHEADERS
+Determines the path(s) searched for PostScript header files.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB TEXPSHEADERS
+Determines the path(s) searched for PostScript header files if
+.SB XDVIHEADERS
+is not set.
+.TP
+.SB PSHEADERS
+Determines the path(s) searched for PostScript header files if neither
+.SB XDVIHEADERS
+nor
+.SB TEXPSHEADERS
+is set.
+#endif
+.TP
+.SB XDVISOURCES
+Determines the path(s) searched for source files when invoking the
+``source specials'' feature of
+.BR xdvi .
+#ifft
+.TP
+.SB XDVIT1FONTS
+Determines the path(s) searched for PostScript Type 1 fonts.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB T1FONTS
+Determines the path(s) searched for PostScript Type 1 fonts if
+.SB XDVIT1FONTS
+is not set.
+.TP
+.SB T1INPUTS
+Determines the path(s) searched for PostScript Type 1 fonts if neither
+.SB XDVIT1FONTS
+nor
+.SB T1FONTS
+is set. If none of these three variables is set, then
+.SB TEXFONTS,
+.SB XDVIHEADERS,
+.SB TEXPSHEADERS,
+and
+.SB PSHEADERS
+are checked (in that order) before using the compiled-in default value.
+.TP
+.SB XDVITYPE1CONFIG
+Determines the path(s) searched for dvips-style configuration files (such as
+.B config.ps
+and
+.BR config.xdvi )
+to determine which fontmap files to read when mapping TeX font names to
+Type 1 font names, Type 1 font files, encodings, etc.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB TEXCONFIG
+Determines the path(s) searched for dvips-style configuration files if
+.SB XDVITYPE1CONFIG
+is not set.
+.TP
+.SB XDVIFONTMAPS
+Determines the path(s) searched for fontmap files.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB TEXFONTMAPS
+Determines the path(s) searched for fontmap files if
+.SB XDVIFONTMAPS
+is not set. If neither of these variables is set, then
+.SB TEXFONTS
+is also checked before using the compiled-in default value.
+.TP
+.SB XDVIENCS
+Determines the path(s) searched for encoding files.
+See the section on FILE SEARCHING for more details.
+.TP
+.SB ENCFONTS
+Determines the path(s) searched for encoding files if
+.SB XDVIENCS
+is not set. If neither of these variables is set, then
+.SB TEXFONTS
+is also checked before using the compiled-in default value.
+.TP
+.SB XDVI_GS_LIB
+Determines the path(s) searched for Ghostscript-style Fontmap files.
+See the Ghostscript documentation for more details.
+.TP
+.SB GS_LIB
+Determines the path(s) searched for Ghostscript-style Fontmap files if
+.SB XDVI_GS_LIB
+is not set.
+#endif
+.TP
+.SB XEDITOR
+Determines the command to be executed to pop up the editor, if neither the
+.B \-editor
+command-line option nor the
+.B .editor
+resource are specified. See the section on SOURCE SPECIALS for details on
+the format.
+.TP
+.SB VISUAL
+Determines an editor to be popped up in an
+.B xterm
+window if neither
+.BR \-editor ,
+.BR .editor ,
+nor
+.SB XEDITOR
+is given.
+.TP
+.SB EDITOR
+Determines an editor to be popped up in an
+.B xterm
+window if neither
+.BR \-editor ,
+.BR .editor ,
+.SB XEDITOR,
+nor
+.SB VISUAL
+is given.
+#ifmakepk
+.TP
+.SB XDVIMAKEPK
+Address of the program (and, optionally, the order of its arguments) to
+be called when
+.B xdvi
+attempts to create a
+.I gf
+or
+.I pk
+font file. See the section on CREATING FONT FILES for more details.
+#endif
+#ifps
+.TP
+.SB TMPDIR
+The directory to use for storing temporary files created when uncompressing
+PostScript files.
+#endif
+#ifextraappdef
+.TP
+.SB XDVIINPUTS
+Colon-separated list of paths to search for an extra
+.I app-defaults
+file.
+#endif
+.SH FILE SEARCHING
+In order to accommodate the wide variety of ways in which fonts are stored
+on various sites,
+.B xdvi
+has a fairly elaborate mechanism for indicating where to look for font files.
+For other types of files, the mechanism is similar, but simpler. The method
+for looking for font pixel files will be described first; other file types will
+then be described. This section is quite technical; on first reading, it
+would probably be better to skip to the section on EXAMPLES OF FONT SEARCHING.
+.PP
+The environment variable
+.SB XDVIFONTS
+(or
+.SB PKFONTS,
+etc., if
+.SB XDVIFONTS
+is not set) contains a list of specifiers, separated by colons. An extra
+colon anywhere in that list causes the compiled-in default value to be
+substituted at that point. Or, if no such environment variable is used,
+the compiled-in default is also used instead.
+#ifconfig
+(However, see the section on CONFIGURATION FILES to see how they change the
+situation concerning defaults.)
+#endif
+.PP
+In each specifier, the following substitutions are first made:
+.TP
+.B %f
+Replaced by the font name.
+.TP
+.B %F
+Replaced by the font name (but without side effects; see below).
+.TP
+.B %d
+Replaced by the size of the font (in dots per inch).
+.TP
+.B %b
+Replaced by the base resolution; i.e., the value of the
+.B \-p
+parameter or the
+.B .pixelsPerInch
+resource.
+.TP
+.B %p
+Replaced by the font file format
+.RB (`` pk ''
+or
+.RB `` gf '').
+.TP
+.B %m
+Replaced by the
+.IR mode-def ,
+as given in the
+.B \-mfmode
+argument or the
+.B .mfMode
+resource.
+.TP
+.B %t
+Replaced, sequentially, by the directories given by the
+.B TEXMF
+environment variable (or its compiled-in default). This may only be used
+at the beginning of a specifier.
+.TP
+.B %s
+Replaced by
+.RB `` %qfonts/%p/{%m,modeless}// ''.
+This is compatible with the \*(Te\& Directory Structure (TDS) standard.
+This string may only be used at the end of a specifier.
+.TP
+.B %S
+Replaced by
+.RB `` %t/%s ''.
+.TP
+.B %q
+Replaced by the empty string. This has the side effect of enabling the
+``quick find'' feature, which is described below.
+.TP
+.B %Q
+Replaced by the empty string. Like
+.BR %q ,
+this enables the ``quick find'' feature. It also inhibits searching for the
+file by normal means if ``quick find'' is not available.
+.TP
+.B %%
+Replaced by a single percent sign. Likewise,
+.BR %: ,
+.BR %* ,
+etc. can be used to insert those special characters into the destination
+string.
+.PP
+If no
+.RB `` %f ''
+appears in the specifier, then the string
+.RB `` /%f.%d%p ''
+is added on the end.
+.PP
+The characters
+.BR * ,
+.BR ? ,
+.BR [ ,
+.BR ] ,
+.BR { ,
+and
+.B }
+are interpreted as wild cards, as in the C-shell
+.RB ( csh ).
+(This is here to pave the way for
+.I fli
+files, which have not been implemented yet.)
+In addition, a double slash
+.RB (`` // '')
+in the specifier indicates that any number of subdirectories may be inserted
+at that point.
+.PP
+There is an exception to the above procedure. If the font name begins
+with a slash
+.RB ( / ),
+then the font name is treated as an absolute path: the single specifier
+.RB `` %f.%d%p ''
+is used instead of the specifier(s) given by
+.SB XDVIFONTS.
+.PP
+The recursive search over subdirectories triggered by a double slash often
+causes a severe performance penalty; therefore,
+.B xdvi
+implements a speedup called ``quick find.'' This is triggered by the presence
+of a
+.RB `` %q ''
+or
+.RB `` %Q ''
+in the specifier. The location of such a string indicates that a file named
+.B ls-R
+should exist in that directory; that file should be the output of a
+.B ls -R
+or
+.B ls -LR
+command executed while in that directory. If such a file exists, then
+.B xdvi
+will search that file instead of searching through the directory tree.
+If such a file does not exist, and if
+.RB `` %Q ''
+was used, then
+.B xdvi
+will skip the specifier entirely.
+.PP
+In order for ``quick find'' to work,
+a few conditions must be met. First of all, the
+.RB `` %q ''
+or
+.RB `` %Q ''
+must occur immediately after a slash, and no later than immediately following
+the double slash. Secondly, there must be exactly one double slash in the
+specifier (having more than one double slash requires more complicated
+code in
+.BR xdvi ;
+if there are no double slashes then there is no need for ``quick find'').
+Third, there may be no wild cards other than
+.B {
+and
+.B }
+in the specifier. Finally,
+.BR %f ,
+.BR %F ,
+and
+.B %d
+may not occur in the specifier prior to the double slash. These conditions
+are all satisfied in the case of the \*(Te\& Directory Structure (TDS) standard.
+.PP
+An additional exception is that if a specifier or one of the alternatives in the
+.SB TEXMF
+environment variable begins with two exclamation points
+.RB (`` !! ''),
+then those characters are stripped off, and any subordinate search that
+could use an
+.B ls-R
+file, will be skipped if the
+.B ls-R
+file does not exist. In other words, any
+.RB `` %q ''
+strings are treated as
+.RB `` %Q ''.
+This feature has been included for compatibility with the
+.B Kpathsea
+library.
+.PP
+Finally, if a specifier or one of the alternatives in the
+.SB TEXMF
+environment variable begins with a tilde
+.RB ( ~ )
+(after the
+.RB `` !! '',
+if any), then
+.B xdvi
+will attempt to replace a string of the form
+.BI ~ username
+with the home directory of
+.IR username .
+The
+.I username
+is taken to be everything up through the next slash or the end of the string;
+if it is empty, then the current user's home directory is substituted instead.
+If the username does not exist, then the string is left unchanged.
+.SH SEARCHING FOR FONTS
+When
+.B xdvi
+searches for a font, the first thing it does is to look for a
+#ifft
+PostScript Type 1 font (unless Type 1 fonts have been turned off by the
+.B \-nofreetypefonts
+command-line argument or
+.B .freetypeFonts
+X resource). It does so by the following method.
+
+.PP
+First, it compiles a list of dvips-style map files, using the same procedure as
+.B dvips
+would use for a hypothetical printer named
+.BR xdvi .
+In other words, it searches the files
+.BR config.ps ,
+.B $HOME/.dvipsrc
+(where
+.B $HOME
+refers to the user's home directory), and
+.B config.xdvi
+to determine a list of map files to search for the font. It then searches
+those map files for an entry pertaining to the font in question. If an entry
+for the font is found, then that entry must give the PostScript name for
+the font, and may also give additional information such as the file name
+of a Type 1 font file containing the font, an encoding file to use for
+the font, or information on transformations to apply to the font
+(expansion/contraction and slanting). If the map files contain more than
+one entry for a given font, then the first entry encountered will be used.
+See the
+.B dvips
+documentation for details on this procedure.
+.PP
+If the map entry for the font gives a file name, then the named file is
+searched for and used (if found) to provide the font. Otherwise (if the
+map entry does not give a file name), then
+.B xdvi
+uses the PostScript name given in the map entry to search for the font in
+.B Fontmap
+files, using the same method as Ghostscript uses to search for PostScript
+fonts.
+.PP
+If an entry for the font is not found in one of the dvips map files, then
+it is assumed not to be available in Type 1 format, and
+.B xdvi
+will then search for a
+#endif
+.I pk
+or
+.I gf
+file, at the size required for the
+.I dvi
+file, using the strategy mentioned in the above subheading.
+#ifdosnames
+If that fails, it will try again, but for specifiers lacking a string
+.RB `` %f '',
+it will add the string
+.RB `` /dpi%d/%f.%p ''
+at the end (instead of
+.RB `` /%f.%d%p '').
+#endif
+It will also try a slightly different size, in case of rounding errors.
+.PP
+If no such bitmap file is found, it then searches for a virtual font.
+(A virtual font is a recipe for creating a font from characters in other fonts
+and from rectangles.) This uses the procedure described under FILE SEARCHING,
+except that: (1) the environment variable
+.SB XDVIVFS
+or its associated defaults is used in place of the environment variable
+.SB XDVIFONTS
+or its associated defaults;
+(2)
+.RB `` %d '',
+.RB `` %b '',
+.RB `` %p '',
+and
+.RB `` %m ''
+are not substituted;
+(3)
+.RB `` %s ''
+is replaced by
+.RB `` %qfonts/vf// '';
+(4) if no
+.RB `` %f ''
+appears in a specifier, then
+.RB `` /%f.vf ''
+is added at the end; and finally
+(5) if the file name begins with a slash, then
+.RB `` %f.vf ''
+replaces all the specifiers.
+.PP
+If no virtual font is found, then
+.B xdvi
+will
+#ifmakepk
+invoke Metafont to create the font in the correct size. Failing that, it will
+#endif
+try to find the nearest size.
+If the font cannot be found at all, then
+.B xdvi
+will try to vary the point size of the font (within a certain range),
+and if this fails, then it will use the font specified as the alternate
+font (see
+.BR \-altfont ).
+.SH EXAMPLE OF FONT SEARCHING
+This example describes how
+.B xdvi
+would search for the font
+.B cmr10
+at 300 dots per inch. First,
+#ifft
+.B xdvi
+searches the map files for an entry describing a font with TeX name
+.BR cmr10 .
+It will likely find a line
+.RS 5
+.nf
+.ft 3
+.sp 1n
+cmr10 CMR10 <cmr10.pfb
+.sp 1n
+.ft
+.fi
+.RE
+The (space-separated) entries in this line mean (in order) that the TeX name
+of the font is
+.BR cmr10 ,
+the PostScript name is
+.BR CMR10 ,
+and the font is located in the file
+.BR cmr10.pfb .
+This file is searched for using the methods listed in the section on
+FILE SEARCHING. This is done using the same procedure as for font files,
+except that:
+(1)
+.RB `` %f ''
+and
+.RB `` %F ''
+refer to the file name, not the font name;
+(2)
+.RB `` %d '',
+.RB `` %b '',
+.RB `` %p '',
+and
+.RB `` %m ''
+are not substituted;
+(3)
+.RB `` %s ''
+is replaced by
+.RB `` %qfonts/type1// '';
+(4) if no
+.RB `` %f ''
+appears in a specifier, then
+.RB `` /%f ''
+is added at the end; and finally
+(5) if the file name begins with a slash, then
+.RB `` %f ''
+replaces all the specifiers.
+.PP
+If no such map file entry is found, if the file
+.B cmr10.pfb
+cannot be found, or if Type 1 fonts have been turned off, then
+#endif
+.B xdvi
+searches for the font in raster format at 300 dpi. For example, if the
+specifier is
+.RB `` /usr/local/tex/fonts '',
+then
+.B xdvi
+looks for
+.B /usr/local/tex/fonts/cmr10.300pk
+and
+.BR /usr/local/tex/fonts/cmr10.300gf ,
+in that order (provided that
+.B xdvi
+is compiled to accept both
+.I pk
+and
+.I gf
+files, which is not necessarily the case).
+.PP
+For sites using the \*(Te\& Directory Structure (TDS) standard,
+.SB XDVIFONTS
+(or, better yet, its compiled-in default) should be set to
+.RB `` .:%S '';
+in that case, if
+.SB TEXMF
+(or, again, its compiled-in default) is set to
+.RB `` /usr/local/texmf '',
+then
+.B xdvi
+will look within that directory for the font file, in accordance with the
+TDS standard.
+.PP
+There may be several such TDS trees.
+.PP
+A common situation is one in which a user wishes to augment the set of fonts
+provided by the system. It is possible to do this without having to know
+or remember what the defaults are. For example, if the user has a small
+number of fonts, and keeps them all in one directory, say
+.BR /home/user/fonts ,
+then setting
+.SB XDVIFONTS
+to
+.RB `` /home/user/fonts: ''
+will cause
+.B xdvi
+to check that directory for font files before checking its default list.
+Similarly, setting
+.SB XDVIFONTS
+to
+.RB `` :/home/user/fonts ''
+will cause
+.B xdvi
+to check that directory
+.I after
+checking its default locations. This is true even if the system uses a TDS
+tree.
+#iftexfonts
+.PP
+If that directory also contains
+.I tfm
+files, then it is possible to set
+.SB TEXFONTS
+instead of
+.SB XDVIFONTS;
+in that case, \*(Te\& will also look for the
+.I tfm
+files in that directory. This feature depends on which implementation
+of \*(Te\& is in use. The
+.SB XDVIFONTS
+variable overrides the
+.SB TEXFONTS
+variable, so that on those sites where
+.SB TEXFONTS
+must be set explicitly, and therefore this feature is not useful, the
+.SB XDVIFONTS
+variable may be set to an empty string (i.e.,
+.RB `` "setenv XDVIFONTS" '')
+to cause
+.B xdvi
+to ignore
+.SB TEXFONTS.
+#endif
+.PP
+If the user has a large number of fonts and wishes to keep them in a TDS
+tree, then that is also possible with
+.BR xdvi :
+if, for example, the TDS tree is
+.BR /home/user/texmf ,
+then setting
+.SB TEXMF
+to
+.RB `` /home/user/texmf: ''
+will cause
+.B xdvi
+to check that TDS tree before its default actions. This assumes, however,
+that the site uses a TDS tree also (since
+.SB TEXMF
+is not used unless
+.RB `` %t ''
+or
+.RB `` %S ''
+occurs in a specifier somewhere). If the site does not use a TDS tree,
+then it would be best to set
+.SB XDVIFONTS
+to
+.RB `` /home/user/texmf/%s: '',
+instead.
+#ifmakepk
+.SH CREATING FONT FILES
+.PP
+When
+.B xdvi
+reaches a point where it cannot find a font in the correct size, it calls
+a program to create such a font file. The name of this program (usually
+a shell script) may be controlled by the environment variable
+.SB XDVIMAKEPK.
+Usually this variable would be set to the name of the script.
+In that case the script is called with options giving the font name,
+the requested resolution in dots per inch, the base resolution in dots
+per inch, a (possibly more accurate) indication of the magnification
+using magsteps (if possible), and the
+.I mode-def
+that Metafont is to use when creating the font file.
+.PP
+The
+.I mode-def
+used is the one given by the
+.B \-mfmode
+argument on the command line, the
+.B mfMode
+resource, or the compiled-in default (if any). If none of these are given,
+the string
+.RB `` @MKTEXPK_DEFAULT_MODE@ ''
+is used.
+.PP
+Optionally, the
+.SB XDVIMAKEPK
+variable may include the following designators:
+.TP
+.B %n
+Replaced by the font name.
+.TP
+.B %d
+Replaced by the resolution (in dots per inch) of the desired pixel file.
+.TP
+.B %b
+Replaced by the base resolution of the Metafont mode.
+.TP
+.B %m
+Replaced by an indication of the magnification to be applied.
+.TP
+.B %o
+Replaced by the Metafont
+.IR mode-def.
+.TP
+.B %r
+Replaced by a string of the form
+.BI ``>& digit '',
+enclosed in single quotes, where
+.I digit
+indicates a file number on which the program is to write the full path of the
+font file that it has created.
+.PP
+If the
+.SB XDVIMAKEPK
+string uses designators, if a
+.I mode-def
+is known to
+.BR xdvi ,
+but if no
+.RB `` %o ''
+designator was used, then the mode will be appended to the end of the string.
+Also, if no
+.RB `` %r ''
+was used, then
+.B xdvi
+expects the program to write the full path of the font file on its standard
+output.
+.PP
+By default,
+.SB XDVIMAKEPK
+equals
+.BR @MKTEXPK_PATH@ .
+If no designator
+.RB `` %n ''
+appears in the
+.SB XDVIMAKEPK
+string, then the string
+.B @MKTEXPK_TAIL@
+will be appended.
+.PP
+This mechanism is compatible with the font creation mechanism used in
+.BR dvips (1)
+and the
+.B Kpathsea
+library.
+#endif
+#ifps
+.SH SEARCHING FOR POSTSCRIPT FILES
+PostScript figure files and header files are searched for using a modification
+of the procedure used for font files.
+First, if the file name does not begin with a slash, then
+.B xdvi
+will look in the directory containing the
+.I dvi
+file. If it is not found there, then the
+.SB XDVIPICTS
+and
+.SB XDVIHEADERS
+environment variables determine the search strategy for PostScript
+figure files and header files, respectively. This is the same procedure as
+for font files, except that:
+(1)
+.RB `` %f ''
+and
+.RB `` %F ''
+refer to the file name, not the font name;
+(2)
+.RB `` %d '',
+.RB `` %b '',
+.RB `` %p '',
+and
+.RB `` %m ''
+are not substituted;
+(3)
+.RB `` %s ''
+is replaced by
+.RB `` {%qdvips//,%qtex//} ''
+for figure files or
+.RB `` %qdvips// ''
+for header files;
+(4) if no
+.RB `` %f ''
+appears in a specifier, then
+.RB `` /%f ''
+is added at the end; and finally
+(5) if the file name begins with a slash, then
+.RB `` %f ''
+replaces all the specifiers.
+Customarily,
+.SB XDVIPICTS
+will be the same as the \*(Te\& input directory.
+.PP
+There is an additional exception to the above strategy.
+If the file name begins with a backtick
+.RB ( ` ),
+then the remaining characters in the file name give a shell command (often
+.BR zcat )
+which is executed; its standard output is then sent to be interpreted as
+PostScript. Note that there is some potential for security problems here;
+see the
+.B \-allowshell
+command-line option. It is better to use compressed files directly (see below).
+.PP
+If a file name is given (as opposed to a shell command),
+if that file name ends in
+.RB `` .Z '',
+.RB `` .gz '',
+or
+.RB `` .bz2 '',
+and if the initial bytes of the file indicate that it was compressed with
+.BR compress (1),
+.BR gzip (1),
+or
+.BR bzip2 (1),
+respectively, then the file is first uncompressed with
+.BR "uncompress \-c" ,
+.BR "gunzip \-c" ,
+or
+.BR "bunzip2 \-c" ,
+respectively. This is preferred over using a backtick to call the command
+directly, since you do not have to specify
+.B \-allowshell
+and since it allows for path searching.
+#endif
+#ifextraappdef
+.SH X RESOURCES
+It is often desirable to set X Window System resources from a file within the
+.B texmf
+tree instead of within the X Window System directory hierarchy.
+For this reason,
+.B xdvi
+searches for a file named
+.RB `` XDvi ''
+in the main directory of all
+.B texmf
+trees, or in its subdirectories
+.B xdvi
+or
+.BR web2c .
+The search path for this file can be overridden by using the
+.SB XDVIINPUTS
+environment variable.
+#endif
+#ifconfig
+.SH CONFIGURATION FILES
+.B xdvi
+allows for any number of configuration files; these provide additional levels
+of defaults for file paths. For example, when searching for font pixel files,
+the hierarchy of defaults is as follows:
+.TP
+First
+The value of the
+.SB XDVIFONTS,
+.SB PKFONTS,
+.SB TEXPKS,
+or
+.SB TEXFONTS
+environment variable (if any).
+.TP
+ .
+The value of
+.SB PKFONTS
+given in the first config file searched.
+.TP
+ .
+ ...
+.TP
+ .
+The value of
+.SB PKFONTS
+given in the last config file searched.
+.TP
+Last
+The compiled-in default value.
+.PP
+The first of these in the list that is given is used; if an extra colon is
+present in that string, then the next in the list is used. Additional extra
+colons are ignored; if no extra colon is present, then the remainder of the
+list is ignored. Note that, unlike the situation with environment variables,
+only one name may be used in the config file. Additionally, if a config file
+defines a variable such as
+.SB PKFONTS
+more than once, only the first value is used.
+.PP
+Other special config file variables are:
+.TP 12
+.SB TEXMF
+Directories to substitute for
+.BR %t .
+But, see the caution below.
+.TP
+.SB VFFONTS
+Search specifiers for virtual fonts.
+#endif
+#ifconfigps
+.TP
+.SB TEXPICTS
+Search specifiers for PostScript figure files.
+.TP
+.SB PSHEADERS
+Search specifiers for PostScript header files.
+#endif
+#ifconfig
+.PP
+The configuration file may also define other variables; these (as well as
+.SB PKFONTS
+and the other variables listed above) will be substituted whenever they are
+referred to, using either the syntax
+.BI $ variable\fR,\fP
+in which
+.I variable
+consists of the longest string consisting of letters, digits, and underscores
+following the dollar sign, or the syntax
+.BI ${ variable }\fR,\fP
+which is interpreted without matching the braces. These substitutions occur
+before brace expansions, which in turn occur before tilde expansions.
+Substitutions of this sort are global: only the first definition of a
+variable is used, even if there are multiple configuration files.
+This holds also when variables such as
+.SB PKFONTS
+are substituted via
+.B $PKFONTS
+instead of the hierarchy of defaults mentioned earlier.
+Also, an environment variable will override a corresponding configuration
+file variable. Undefined variables are replaced with the empty string.
+.PP
+.B Note:
+Some configuration files define a variable
+.SB TEXMF
+and access it via
+.BR $TEXMF .
+When using such files with
+.BR xdvi ,
+it may be necessary to avoid using
+.B %t
+and
+.B $S
+if the definition is incompatible with how that special symbol is used by
+.BR xdvi .
+For example,
+.B xdvi
+does not support brace expansion within
+.SB TEXMF
+when it is used in the context of
+.BR %t ,
+so if a configuration file defines
+.SB TEXMF
+as a string involving braces, then
+.B $TEXMF/%s
+should be used instead of
+.BR %S .
+#endif
+#ifselfauto
+.PP
+When starting up,
+.B xdvi
+will determine where its executable file is located, and will define three
+special configuration file variables based on that information.
+It defines
+.SB SELFAUTOLOC
+to be the directory containing the binary,
+.SB SELFAUTODIR
+to be the parent of that directory, and
+.SB SELFAUTOPARENT
+to be the parent of that directory. For example, if
+.B xdvi
+is in the executable file
+.BR /usr/local/tex/texmf/bin/sunos4/xdvi ,
+then the value of
+.SB SELFAUTOLOC
+will be
+.BR /usr/local/tex/texmf/bin/sunos4 ,
+.SB SELFAUTODIR
+will be
+.BR /usr/local/tex/texmf/bin ,
+and
+.SB SELFAUTOPARENT
+will be
+.BR /usr/local/tex/texmf .
+These three variables are special: they cannot be defined in a configuration
+file or in the environment.
+#endif
+#ifconfig
+.PP
+The syntax of configuration files is as follows. Blank lines, and lines
+in which the first non-white character is
+.B #
+or
+.BR % ,
+are assumed to be comment lines, and are ignored.
+All other lines must be of the form
+.IB variable = value\fR,\fP
+in which
+.I variable
+is either a variable name or a qualified variable name (discussed below), and
+.I value
+is the value to be assigned to the variable. A qualified variable name
+is a variable name, followed by a period and a string.
+A definition using a qualified variable name will be ignored, unless
+the string matches either of (a) the argument of the
+.B \-name
+command-line argument (or the filename part of the path of the executable
+file for
+.B xdvi
+(usually ``xdvi''), if no
+.B \-name
+option was used); or (b) the string ``XDvi'' (the
+.I class
+of
+.BR xdvi ).
+Since only the first definition of a variable will have any effect, an
+unqualified definition should be placed after all qualified definitions
+of that same variable.
+.PP
+There may be several configuration files. They are located as follows.
+Initially, an environment variable
+.SB TEXMFCNF
+is used; it should contain a colon-separated list of directories.
+All of those directories will be searched for files named
+.BR texmf.cnf ,
+and those files will all be read. Those files may also define variables
+.SB TEXMFCNF;
+if so, then those variables are taken to be colon-separated lists of
+directories. This defines the data structure of a tree; this tree is
+read in the obvious depth-first order. Duplicate directories are skipped
+in order to avoid infinite loops. Finally, an extra colon anywhere in any
+of these lists causes the compiled-in default to be substituted at that
+point. In addition, if
+.SB TEXMFCNF
+is not defined in the environment, then the search starts with the compiled-in
+default (it is expected that this will usually be the case).
+.PP
+If there are more than one
+.B texmf
+tree, then it is expected that each of them will have its own configuration
+file; the easiest way to combine them is to link them together in a chain
+(a vertical tree). The last file in the chain can be set up as if it were
+the only configuration file, and all others could contain a definition of
+.SB TEXMFCNF
+pointing to the directory of the next configuration file in the chain,
+and definitions for
+.SB TEXMF
+or
+.SB PKFONTS,
+etc., with extra colons at the end so that the values from configuration
+files lower in the chain are also used.
+#endif
+#ifps
+.SH LIMITATIONS
+.B xdvi
+accepts many but not all types of PostScript specials accepted by
+.BR dvips .
+For example, it accepts most specials generated by
+.B epsf
+and
+.BR psfig .
+It does not, however, support
+.B bop\-hook
+or
+.BR eop\-hook ,
+nor does it allow PostScript commands to affect the rendering of things that
+are not PostScript (for example, the ``NEAT'' and rotated ``A'' examples in the
+.B dvips
+manual, and the
+.B PSfrag
+package). These restrictions are due to the design of
+.BR xdvi ;
+in all likelihood they will always remain.
+.PP
+La\*(Te\&2e rotation specials are not currently supported.
+.PP
+.B MetaPost
+files containing included text are not supported.
+#endif
+.SH FILES
+.PD 0
+#ifconfig
+@DEFAULT_CONFIG_PATH@ Directories to be searched for configuration files.
+#endif
+@DEFAULT_TEXMF_PATH@ \*(Te\& Directory Structure (TDS) directories.
+.TP 40
+@DEFAULT_FONT_PATH@ Font pixel files.
+@DEFAULT_VF_PATH@ Virtual font files.
+#ifps
+.TP
+@DEFAULT_FIG_PATH@ Directories containing PostScript figures.
+.TP
+@DEFAULT_HEADER_PATH@ Directories containing PostScript header files.
+#endif
+#ifft
+.TP
+@DEFAULT_DVIPS_CF_PATH@ Directories containing dvips configuration files.
+.TP
+@DEFAULT_FONTMAP_PATH@ Directories containing dvips-style fontmap files.
+.TP
+@DEFAULT_ENC_PATH@ Directories containing encoding files.
+.TP
+@DEFAULT_TYPE1_PATH@ Directories containing PostScript Type 1 font files.
+.TP
+@DEFAULT_GS_LIB_PATH@ Directories containing Ghostscript Fontmap files.
+#endif
+.PD
+.SH SEE ALSO
+.BR X (1),
+.BR dvips (1).
+.SH AUTHORS
+Eric Cooper, CMU, did a version for direct output to a QVSS.
+Modified for X by Bob Scheifler, MIT Laboratory for Computer Science.
+Modified for X11 by Mark Eichin, MIT SIPB.
+Additional enhancements by many others.
+The current maintainer is Paul Vojta, U.C. Berkeley.
+.PP
+Please report bugs to the SourceForge bug tracker:
+.PP
+.nf
+.B http://sourceforge.net/tracker/?func=add&group_id=23164&atid=377580
+.PP
diff --git a/xdvi.c b/xdvi.c
@@ -0,0 +1,3632 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work as noted in the modification history, below.
+
+\*========================================================================*/
+
+/*
+ * DVI previewer for X.
+ *
+ * Eric Cooper, CMU, September 1985.
+ *
+ * Code derived from dvi-imagen.c.
+ *
+ * Modification history:
+ * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
+ * 7/1988 Modified for X.11 --Mark Eichin, MIT
+ * 12/1988 Added 'R' option, toolkit, magnifying glass
+ * --Paul Vojta, UC Berkeley.
+ * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
+ * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
+ * 3/1990 Added VMS support --Scott Allendorf, U of Iowa
+ * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
+ * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
+ * and Lee Hetherington, MIT
+ * 4/1994 Added DPS support, bounding box
+ * --Ricardo Telichevesky
+ * and Luis Miguel Silveira, MIT RLE.
+ * 1/2001 Added source specials --including ideas from Stefan Ulrich,
+ * U Munich
+ *
+ * Compilation options:
+ * VMS compile for VMS
+ * XAW compile with X toolkit and Athena (Xaw) widgets
+ * XAW3D compile with Xaw3d variant of Xaw widgets. XAW should be
+ * defined, too.
+ * MOTIF compile with X toolkit and Motif widgets
+ * BUTTONS compile with buttons on the side of the window (needs toolkit)
+ * WORDS_BIGENDIAN store bitmaps internally with most significant bit first
+ * BMTYPE store bitmaps in unsigned BMTYPE
+ * BMBYTES sizeof(unsigned BMTYPE)
+ * ALTFONT default for -altfont option
+ * SHRINK default for -s option (shrink factor)
+ * MFMODE default for -mfmode option
+ * A4 use European size paper, and change default dimension to cm
+ * TEXXET support reflection dvi codes (right-to-left typesetting)
+ * GREY use grey levels to shrink fonts
+ * PS_GS use Ghostscript to render pictures/bounding boxes
+ * PS_DPS use display postscript to render pictures/bounding boxes
+ * PS_NEWS use the NeWS server to render pictures/bounding boxes
+ * GS_PATH path to call the Ghostscript interpreter by
+ */
+
+#define EXTERN
+#define INIT(x) =x
+
+#include "xdvi.h"
+
+#if !lint
+static char copyright[] UNUSED =
+"@(#) Copyright (c) 1994-2003 Paul Vojta. All rights reserved.\n";
+#endif
+
+#include <math.h> /* sometimes includes atof() */
+#include <ctype.h>
+
+#if NeedVarargsPrototypes /* this is for usage() */
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifndef ALTFONT
+#define ALTFONT "cmr10"
+#endif
+
+#ifndef SHRINK
+#define SHRINK 3
+#endif
+
+#ifndef BDPI
+#define BDPI 300
+#endif
+
+#ifndef MFMODE
+#define MFMODE NULL
+#endif
+
+#if defined(PS_GS) && !defined(GS_PATH)
+#define GS_PATH "gs"
+#endif
+
+#if A4
+#define DEFAULT_PAPER "a4"
+#else
+#define DEFAULT_PAPER "letter"
+#endif
+
+#include "version.h"
+
+#ifdef X_NOT_STDC_ENV
+#ifndef atof
+extern double atof ARGS((_Xconst char *));
+#endif
+#endif
+
+/* Xlib and Xutil are already included */
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include "xdvi.icon"
+
+#ifdef TOOLKIT
+
+#ifdef OLD_X11_TOOLKIT
+#include <X11/Atoms.h>
+#else /* not OLD_X11_TOOLKIT */
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#endif /* not OLD_X11_TOOLKIT */
+
+#include <X11/Shell.h> /* needed for def. of XtNiconX */
+
+#if XtSpecificationRelease >= 4
+
+#ifndef MOTIF
+# if XAW3D
+# include <X11/Xaw3d/Viewport.h>
+# else
+# include <X11/Xaw/Viewport.h>
+# endif
+#define VPORT_WIDGET_CLASS viewportWidgetClass
+#define DRAW_WIDGET_CLASS drawWidgetClass
+#else /* MOTIF */
+#include <Xm/MainW.h>
+#include <Xm/ToggleB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/MenuShell.h>
+#include <Xm/DrawingA.h>
+#include <Xm/Protocols.h>
+#define VPORT_WIDGET_CLASS xmMainWindowWidgetClass
+#define DRAW_WIDGET_CLASS xmDrawingAreaWidgetClass
+#endif /* MOTIF */
+
+#ifdef BUTTONS
+#ifndef MOTIF
+# if XAW3D
+# include <X11/Xaw3d/Command.h>
+# else
+# include <X11/Xaw/Command.h>
+# endif
+#define FORM_WIDGET_CLASS formWidgetClass
+#else /* MOTIF */
+#include <Xm/Form.h>
+#define FORM_WIDGET_CLASS xmFormWidgetClass
+#endif /* MOTIF */
+#endif /* BUTTONS */
+
+#else /* XtSpecificationRelease < 4 */
+
+#if NeedFunctionPrototypes
+typedef void *XtPointer;
+#else
+typedef char *XtPointer;
+#endif
+
+#include <X11/Viewport.h>
+#define VPORT_WIDGET_CLASS viewportWidgetClass
+#define DRAW_WIDGET_CLASS drawWidgetClass
+#ifdef BUTTONS
+#include <X11/Command.h>
+#define FORM_WIDGET_CLASS formWidgetClass
+#endif
+
+#endif /* XtSpecificationRelease */
+
+# if XtSpecificationRelease < 5
+# define XtScreenDatabase(s) (DISP->db)
+# endif
+
+# if HAVE_X11_INTRINSICI_H
+# include <X11/IntrinsicI.h>
+# else
+
+/* Taken from <X11/TranslateI.h> in libXt-1.0.4 (Oct. 2006) */
+typedef struct _LateBindings {
+ unsigned int knot:1;
+ unsigned int pair:1;
+ unsigned short ref_count;
+ KeySym keysym;
+} LateBindings, *LateBindingsPtr;
+
+# endif /* HAVE_X11_INTRINSICI_H */
+
+#else /* not TOOLKIT */
+
+typedef int Position;
+
+#endif /* not TOOLKIT */
+
+#if XlibSpecificationRelease < 5
+typedef char *XPointer;
+#define XScreenNumberOfScreen(s) ((s) - ScreenOfDisplay(DISP, 0))
+#endif
+
+/*
+ * Cursors and masks for dragging operations.
+ */
+
+#define drag_vert_width 7
+#define drag_vert_height 17
+#define drag_vert_x_hot 3
+#define drag_vert_y_hot 8
+static _Xconst unsigned char drag_vert_bits[] = {
+ 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x2a, 0x1c, 0x08, 0x00};
+static _Xconst unsigned char drag_vert_mask[] = {
+ 0x08, 0x1c, 0x3e, 0x7f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+ 0x1c, 0x7f, 0x3e, 0x1c, 0x08};
+
+#define drag_horiz_width 17
+#define drag_horiz_height 7
+#define drag_horiz_x_hot 8
+#define drag_horiz_y_hot 3
+static _Xconst unsigned char drag_horiz_bits[] = {
+ 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x04, 0x40, 0x00, 0xfe, 0xff, 0x00,
+ 0x04, 0x40, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
+static _Xconst unsigned char drag_horiz_mask[] = {
+ 0x08, 0x20, 0x00, 0x0c, 0x60, 0x00, 0xfe, 0xff, 0x00, 0xff, 0xff, 0x01,
+ 0xfe, 0xff, 0x00, 0x0c, 0x60, 0x00, 0x08, 0x20, 0x00};
+
+#define drag_omni_width 17
+#define drag_omni_height 17
+#define drag_omni_x_hot 8
+#define drag_omni_y_hot 8
+static _Xconst unsigned char drag_omni_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x05, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x08, 0x21, 0x00, 0x04, 0x41, 0x00,
+ 0xfe, 0xff, 0x00, 0x04, 0x41, 0x00, 0x08, 0x21, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x01, 0x00, 0x40, 0x05, 0x00, 0x80, 0x03, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00};
+static _Xconst unsigned char drag_omni_mask[] = {
+ 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x07, 0x00, 0xe0, 0x0f, 0x00,
+ 0x80, 0x03, 0x00, 0x88, 0x23, 0x00, 0x8c, 0x63, 0x00, 0xfe, 0xff, 0x00,
+ 0xff, 0xff, 0x01, 0xfe, 0xff, 0x00, 0x8c, 0x63, 0x00, 0x88, 0x23, 0x00,
+ 0x80, 0x03, 0x00, 0xe0, 0x0f, 0x00, 0xc0, 0x07, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0x01, 0x00};
+
+#ifdef VMS
+/*
+ * Magnifying glass cursor
+ *
+ * Developed by Tom Sawyer, April 1990
+ * Contibuted by Hunter Goatley, January 1991
+ *
+ */
+
+#define mag_glass_width 16
+#define mag_glass_height 16
+#define mag_glass_x_hot 6
+#define mag_glass_y_hot 6
+static char mag_glass_bits[] = {
+ 0xf8, 0x03, 0x0c, 0x06, 0xe2, 0x09, 0x13, 0x1a, 0x01, 0x14, 0x01, 0x14,
+ 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x03, 0x10, 0x02, 0x18, 0x0c, 0x34,
+ 0xf8, 0x6f, 0x00, 0xd8, 0x00, 0xb0, 0x00, 0xe0
+};
+#include <decw$cursor.h> /* Include the DECWindows cursor symbols */
+static int DECWCursorFont; /* Space for the DECWindows cursor font */
+static Pixmap MagnifyPixmap; /* Pixmap to hold our special mag-glass */
+#include <X11/Xresource.h> /* Motif apparently needs this one */
+#endif /* VMS */
+
+/*
+ * Command line flags.
+ */
+
+static Dimension bwidth = 2;
+
+#define fore_Pixel resource._fore_Pixel
+#define back_Pixel resource._back_Pixel
+#ifdef TOOLKIT
+struct _resource resource;
+#define brdr_Pixel resource._brdr_Pixel
+#define hl_Pixel resource._hl_Pixel
+#define cr_Pixel resource._cr_Pixel
+#else /* not TOOLKIT */
+static _Xconst char *brdr_color;
+static _Xconst char *high_color;
+static _Xconst char *curs_color;
+static Pixel hl_Pixel, cr_Pixel;
+#endif /* not TOOLKIT */
+
+XColor cr_Color;
+
+struct mg_size_rec mg_size[5] = {{200, 150}, {400, 250}, {700, 500},
+ {1000, 800}, {1200, 1200}};
+
+static char *curr_page;
+
+struct WindowRec mane = {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0};
+struct WindowRec alt = {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0};
+/* currwin is temporary storage except for within redraw() */
+struct WindowRec currwin= {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0};
+
+#ifdef lint
+#ifdef TOOLKIT
+WidgetClass widgetClass;
+#ifndef MOTIF
+WidgetClass viewportWidgetClass;
+#ifdef BUTTONS
+WidgetClass formWidgetClass, compositeWidgetClass, commandWidgetClass;
+#endif /* BUTTONS */
+#else /* MOTIF */
+WidgetClass xmMainWindowWidgetClass, xmDrawingAreaWidgetClass;
+#ifdef BUTTONS
+WidgetClass xmFormWidgetClass, xmBulletinBoardWidgetClass;
+WidgetClass xmPushButtonWidgetClass;
+#endif /* BUTTONS */
+#endif /* MOTIF */
+#endif /* TOOLKIT */
+#endif /* lint */
+
+static char * atom_names[] = {"XDVI WINDOWS", "DVI NAME", "SRC GOTO",
+#if TOOLKIT
+ "WM_DELETE_WINDOW",
+#endif
+#if XAW
+ "WM_PROTOCOLS",
+#endif
+ };
+
+/*
+ * Data for options processing
+ */
+
+static _Xconst char silent[] = " "; /* flag value for usage() */
+
+static _Xconst char subst[] = "x"; /* another flag value */
+
+static _Xconst char *subst_val[] = {
+#ifdef BUTTONS
+ "-shrinkbutton[1-9] <shrink>",
+#endif
+ "-mgs[n] <size>"};
+
+#ifdef TOOLKIT
+
+static XrmOptionDescRec options[] = {
+{"-s", ".shrinkFactor", XrmoptionSepArg, (XPointer) NULL},
+#ifndef VMS
+{"-S", ".densityPercent", XrmoptionSepArg, (XPointer) NULL},
+#endif
+{"-density", ".densityPercent", XrmoptionSepArg, (XPointer) NULL},
+#if COLOR
+{"-nocolor", ".color", XrmoptionNoArg, (XPointer) "off"},
+{"+nocolor", ".color", XrmoptionNoArg, (XPointer) "on"},
+#endif
+#ifdef GREY
+{"-nogrey", ".grey", XrmoptionNoArg, (XPointer) "off"},
+{"+nogrey", ".grey", XrmoptionNoArg, (XPointer) "on"},
+{"-gamma", ".gamma", XrmoptionSepArg, (XPointer) NULL},
+{"-install", ".install", XrmoptionNoArg, (XPointer) "on"},
+{"-noinstall", ".install", XrmoptionNoArg, (XPointer) "off"},
+#endif
+{"-p", ".pixelsPerInch", XrmoptionSepArg, (XPointer) NULL},
+{"-margins", ".Margin", XrmoptionSepArg, (XPointer) NULL},
+{"-sidemargin", ".sideMargin", XrmoptionSepArg, (XPointer) NULL},
+{"-topmargin", ".topMargin", XrmoptionSepArg, (XPointer) NULL},
+{"-offsets", ".Offset", XrmoptionSepArg, (XPointer) NULL},
+{"-xoffset", ".xOffset", XrmoptionSepArg, (XPointer) NULL},
+{"-yoffset", ".yOffset", XrmoptionSepArg, (XPointer) NULL},
+{"-paper", ".paper", XrmoptionSepArg, (XPointer) NULL},
+{"-altfont", ".altFont", XrmoptionSepArg, (XPointer) NULL},
+#ifdef MKTEXPK
+{"-nomakepk", ".makePk", XrmoptionNoArg, (XPointer) "off"},
+{"+nomakepk", ".makePk", XrmoptionNoArg, (XPointer) "on"},
+#endif
+{"-mfmode", ".mfMode", XrmoptionSepArg, (XPointer) NULL},
+{"-editor", ".editor", XrmoptionSepArg, (XPointer) NULL},
+{"-sourceposition",".sourcePosition", XrmoptionSepArg, (XPointer) NULL},
+{"-nofork", ".fork", XrmoptionNoArg, (XPointer) "off"},
+{"+nofork", ".fork", XrmoptionNoArg, (XPointer) "on"},
+{"-l", ".listFonts", XrmoptionNoArg, (XPointer) "on"},
+{"+l", ".listFonts", XrmoptionNoArg, (XPointer) "off"},
+#if FREETYPE
+{"-nofreetypefonts", ".freetypeFonts", XrmoptionNoArg, (XPointer) "off"},
+{"+nofreetypefonts", ".freetypeFonts", XrmoptionNoArg, (XPointer) "on"},
+#endif
+#ifdef BUTTONS
+{"-expert", ".expert", XrmoptionNoArg, (XPointer) "on"},
+{"+expert", ".expert", XrmoptionNoArg, (XPointer) "off"},
+{"-shrinkbutton1",".shrinkButton1",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton2",".shrinkButton2",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton3",".shrinkButton3",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton4",".shrinkButton4",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton5",".shrinkButton5",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton6",".shrinkButton6",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton7",".shrinkButton7",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton8",".shrinkButton8",XrmoptionSepArg, (XPointer) NULL},
+{"-shrinkbutton9",".shrinkButton9",XrmoptionSepArg, (XPointer) NULL},
+#endif
+{"-mgs", ".magnifierSize1",XrmoptionSepArg, (XPointer) NULL},
+{"-mgs1", ".magnifierSize1",XrmoptionSepArg, (XPointer) NULL},
+{"-mgs2", ".magnifierSize2",XrmoptionSepArg, (XPointer) NULL},
+{"-mgs3", ".magnifierSize3",XrmoptionSepArg, (XPointer) NULL},
+{"-mgs4", ".magnifierSize4",XrmoptionSepArg, (XPointer) NULL},
+{"-mgs5", ".magnifierSize5",XrmoptionSepArg, (XPointer) NULL},
+{"-warnspecials", ".warnSpecials", XrmoptionNoArg, (XPointer) "on"},
+{"+warnspecials", ".warnSpecials", XrmoptionNoArg, (XPointer) "off"},
+{"-hush", ".Hush", XrmoptionNoArg, (XPointer) "on"},
+{"+hush", ".Hush", XrmoptionNoArg, (XPointer) "off"},
+{"-hushchars", ".hushLostChars", XrmoptionNoArg, (XPointer) "on"},
+{"+hushchars", ".hushLostChars", XrmoptionNoArg, (XPointer) "off"},
+{"-hushchecksums", ".hushChecksums", XrmoptionNoArg, (XPointer) "on"},
+{"+hushchecksums", ".hushChecksums", XrmoptionNoArg, (XPointer) "off"},
+{"-safer", ".safer", XrmoptionNoArg, (XPointer) "on"},
+{"+safer", ".safer", XrmoptionNoArg, (XPointer) "off"},
+{"-fg", ".foreground", XrmoptionSepArg, (XPointer) NULL},
+{"-foreground", ".foreground", XrmoptionSepArg, (XPointer) NULL},
+{"-bg", ".background", XrmoptionSepArg, (XPointer) NULL},
+{"-background", ".background", XrmoptionSepArg, (XPointer) NULL},
+{"-hl", ".highlight", XrmoptionSepArg, (XPointer) NULL},
+{"-cr", ".cursorColor", XrmoptionSepArg, (XPointer) NULL},
+{"-icongeometry",".iconGeometry",XrmoptionSepArg, (XPointer) NULL},
+{"-keep", ".keepPosition",XrmoptionNoArg, (XPointer) "on"},
+{"+keep", ".keepPosition",XrmoptionNoArg, (XPointer) "off"},
+{"-copy", ".copy", XrmoptionNoArg, (XPointer) "on"},
+{"+copy", ".copy", XrmoptionNoArg, (XPointer) "off"},
+{"-thorough", ".thorough", XrmoptionNoArg, (XPointer) "on"},
+{"+thorough", ".thorough", XrmoptionNoArg, (XPointer) "off"},
+{"-wheelunit", ".wheelUnit", XrmoptionSepArg, (XPointer) NULL},
+#if PS
+{"-nopostscript",".postscript", XrmoptionNoArg, (XPointer) "off"},
+{"+nopostscript",".postscript", XrmoptionNoArg, (XPointer) "on"},
+{"-allowshell", ".allowShell", XrmoptionNoArg, (XPointer) "on"},
+{"+allowshell", ".allowShell", XrmoptionNoArg, (XPointer) "off"},
+#ifdef PS_DPS
+{"-nodps", ".dps", XrmoptionNoArg, (XPointer) "off"},
+{"+nodps", ".dps", XrmoptionNoArg, (XPointer) "on"},
+#endif
+#ifdef PS_NEWS
+{"-nonews", ".news", XrmoptionNoArg, (XPointer) "off"},
+{"+nonews", ".news", XrmoptionNoArg, (XPointer) "on"},
+#endif
+#ifdef PS_GS
+{"-noghostscript",".ghostscript", XrmoptionNoArg, (XPointer) "off"},
+{"+noghostscript",".ghostscript", XrmoptionNoArg, (XPointer) "on"},
+{"-nogssafer", ".gsSafer", XrmoptionNoArg, (XPointer) "off"},
+{"+nogssafer", ".gsSafer", XrmoptionNoArg, (XPointer) "on"},
+{"-gsalpha", ".gsAlpha", XrmoptionNoArg, (XPointer) "on"},
+{"+gsalpha", ".gsAlpha", XrmoptionNoArg, (XPointer) "off"},
+{"-interpreter",".interpreter", XrmoptionSepArg, (XPointer) NULL},
+{"-gspalette", ".palette", XrmoptionSepArg, (XPointer) NULL},
+#endif
+#endif /* PS */
+{"-noscan", ".prescan", XrmoptionNoArg, (XPointer) "off"},
+{"+noscan", ".prescan", XrmoptionNoArg, (XPointer) "on"},
+{"-dvipspath", ".dvipsPath", XrmoptionSepArg, (XPointer) NULL},
+{"-debug", ".debugLevel", XrmoptionSepArg, (XPointer) NULL},
+{"-version", ".version", XrmoptionNoArg, (XPointer) "on"},
+{"+version", ".version", XrmoptionNoArg, (XPointer) "off"},
+{"--version", ".version", XrmoptionNoArg, (XPointer) "on"},
+};
+
+#if MAKING_HEADER
+ "XDVI_KR_BEGIN1"
+#endif
+
+#if !CC_K_AND_R || MAKING_HEADER
+
+static _Xconst char base_translations[] = ""
+"^<Key>c:quit()\n" /* Control keys first */
+"^<Key>d:quit()\n"
+"^<Key>m:forward-page()\n"
+"^<Key>j:forward-page()\n"
+"^<Key>l:forward-page(0)\n"
+"^<Key>h:back-page()\n"
+"^<Key>o:open-dvi-file()\n"
+"^<Key>p:print()\n"
+"a<Key>p:show-display-attributes()\n"
+#ifdef VMS
+"^<Key>z:quit()\n"
+#endif
+"\"q\":quit()\n"
+"\"d\":down()\n"
+"\"f\":forward-page()\n"
+"\"n\":forward-page()\n"
+"\" \":down-or-next()\n"
+"<Key>Return:forward-page()\n"
+"\"p\":back-page()\n"
+"\"b\":back-page()\n"
+"<Key>Delete:up-or-previous()\n"
+"<Key>BackSpace:up-or-previous()\n"
+#if MOTIF
+"<Key>osfDelete:up-or-previous()\n"
+"<Key>osfBackSpace:up-or-previous()\n"
+#endif
+"\"P\":declare-page-number()\n"
+"\"g\":goto-page()\n"
+"\"\\^\":home()\n"
+"\"c\":center()\n"
+"\"k\":set-keep-flag()\n"
+"\"l\":left()\n"
+"\"r\":right()\n"
+"\"u\":up()\n"
+"\"M\":set-margins()\n"
+"\"s\":set-shrink-factor()\n"
+"\"S\":set-density()\n"
+"<Key>Home:home()\n"
+"<Key>Left:left()\n"
+"<Key>Up:up()\n"
+"<Key>Right:right()\n"
+"<Key>Down:down()\n"
+"<Key>Prior:back-page()\n"
+"<Key>Next:forward-page()\n"
+#ifdef XK_KP_Left
+"<Key>KP_Home:home()\n"
+"<Key>KP_Left:left()\n"
+"<Key>KP_Up:up()\n"
+"<Key>KP_Right:right()\n"
+"<Key>KP_Down:down()\n"
+"<Key>KP_Prior:back-page()\n"
+"<Key>KP_Next:forward-page()\n"
+"<Key>KP_Delete:up-or-previous()\n"
+"<Key>KP_Enter:forward-page()\n"
+#endif
+#if GREY
+"\"G\":set-greyscaling()\n"
+#endif
+#if COLOR
+"\"C\":set-color()\n"
+#endif
+#if PS
+"\"v\":set-ps()\n"
+#endif
+#if PS_GS
+"\"V\":set-gs-alpha()\n"
+#endif
+#if BUTTONS
+"\"x\":set-expert-mode()\n"
+#endif
+"<Key>Escape:discard-number()\n" /* Esc */
+"s<Btn1Down>:drag(|)\n"
+"s<Btn2Down>:drag(+)\n"
+"s<Btn3Down>:drag(-)\n"
+"c<Btn1Down>:source-special()\n"
+"c<Btn2Down>:show-source-specials()\n"
+"c<Btn3Down>:show-all-boxes()\n"
+"<Btn1Down>:magnifier(*1)\n"
+"<Btn2Down>:magnifier(*2)\n"
+"<Btn3Down>:magnifier(*3)\n"
+"\"R\":reread-dvi-file()";
+
+#else /* CC_K_AND_R && not MAKING_HEADER */
+# include "krheader.h"
+#endif
+
+#if MAKING_HEADER
+ "XDVI_KR_END1"
+#endif
+
+#define offset(field) XtOffsetOf(struct _resource, field)
+
+static char XtRBool3[] = "Bool3"; /* resource for Bool3 */
+
+#if EXTRA_APP_DEFAULTS
+static XtResource pre_app_resources[] = {
+{"name", "Name", XtRString, sizeof(char *),
+ offset(progname), XtRString, (XtPointer) NULL},
+{"debugLevel", "DebugLevel", XtRString, sizeof(char *),
+ offset(debug_arg), XtRString, (XtPointer) NULL},
+};
+#endif
+
+static XtResource application_resources[] = {
+#if CFGFILE && !EXTRA_APP_DEFAULTS
+{"name", "Name", XtRString, sizeof(char *),
+ offset(progname), XtRString, (XtPointer) NULL},
+#endif
+{"shrinkFactor", "ShrinkFactor", XtRInt, sizeof(int),
+ offset(shrinkfactor), XtRImmediate, (XtPointer) SHRINK},
+{"densityPercent", "DensityPercent", XtRInt, sizeof(int),
+ offset(_density), XtRString, "40"},
+{"mainTranslations", "MainTranslations", XtRString, sizeof(char *),
+ offset(main_translations), XtRString, (XtPointer) NULL},
+{"wheelTranslations", "WheelTranslations", XtRString, sizeof(char *),
+ offset(wheel_translations), XtRString, (XtPointer) "<Btn4Down>:wheel(-1.)\n\
+ <Btn5Down>:wheel(1.)\n<Btn6Down>:hwheel(-1.)\n<Btn7Down>:hwheel(1.)"},
+{"wheelUnit", "WheelUnit", XtRInt, sizeof(int),
+ offset(wheel_unit), XtRImmediate, (XtPointer) 80},
+{"dvipsHangTime", "DvipsHangTime", XtRInt, sizeof(int),
+ offset(dvips_hang), XtRImmediate, (XtPointer) 700},
+{"dvipsFailHangTime", "DvipsFailHangTime", XtRInt, sizeof(int),
+ offset(dvips_fail_hang), XtRImmediate, (XtPointer) 5000},
+#ifdef GREY
+{"gamma", "Gamma", XtRFloat, sizeof(float),
+ offset(_gamma), XtRString, "1"},
+#endif
+{"pixelsPerInch", "PixelsPerInch", XtRInt, sizeof(int),
+ offset(_pixels_per_inch), XtRImmediate, (XtPointer) BDPI},
+{"sideMargin", "Margin", XtRString, sizeof(char *),
+ offset(sidemargin), XtRString, (XtPointer) NULL},
+{"topMargin", "Margin", XtRString, sizeof(char *),
+ offset(topmargin), XtRString, (XtPointer) NULL},
+{"xOffset", "Offset", XtRString, sizeof(char *),
+ offset(xoffset), XtRString, (XtPointer) NULL},
+{"yOffset", "Offset", XtRString, sizeof(char *),
+ offset(yoffset), XtRString, (XtPointer) NULL},
+{"paper", "Paper", XtRString, sizeof(char *),
+ offset(paper), XtRString, (XtPointer) DEFAULT_PAPER},
+{"altFont", "AltFont", XtRString, sizeof(char *),
+ offset(_alt_font), XtRString, (XtPointer) ALTFONT},
+#ifdef MKTEXPK
+{"makePk", "MakePk", XtRBoolean, sizeof(Boolean),
+ offset(makepk), XtRString, "true"},
+#endif
+{"mfMode", "MfMode", XtRString, sizeof(char *),
+ offset(mfmode), XtRString, MFMODE},
+{"editor", "Editor", XtRString, sizeof(char *),
+ offset(editor), XtRString, (XtPointer) NULL},
+{"sourcePosition", "SourcePosition", XtRString, sizeof(char *),
+ offset(src_pos), XtRString, (XtPointer) NULL},
+{"fork", "Fork", XtRBoolean, sizeof(Boolean),
+ offset(src_fork), XtRString, "true"},
+{"listFonts", "ListFonts", XtRBoolean, sizeof(Boolean),
+ offset(_list_fonts), XtRString, "false"},
+#if FREETYPE
+{"freetypeFonts", "FreetypeFonts", XtRBoolean, sizeof(Boolean),
+ offset(freetype), XtRString, "true"},
+#endif
+{"reverseVideo", "ReverseVideo", XtRBoolean, sizeof(Boolean),
+ offset(reverse), XtRString, "false"},
+{"warnSpecials", "WarnSpecials", XtRBoolean, sizeof(Boolean),
+ offset(_warn_spec), XtRString, "false"},
+{"hushLostChars", "Hush", XtRBoolean, sizeof(Boolean),
+ offset(_hush_chars), XtRString, "false"},
+{"hushChecksums", "Hush", XtRBoolean, sizeof(Boolean),
+ offset(_hush_chk), XtRString, "false"},
+{"safer", "Safer", XtRBoolean, sizeof(Boolean),
+ offset(safer), XtRString, "false"},
+#ifdef VMS
+{"foreground", "Foreground", XtRString, sizeof(char *),
+ offset(fore_color), XtRString, (XtPointer) NULL},
+{"background", "Background", XtRString, sizeof(char *),
+ offset(back_color), XtRString, (XtPointer) NULL},
+#endif
+{"iconGeometry", "IconGeometry", XtRString, sizeof(char *),
+ offset(icon_geometry), XtRString, (XtPointer) NULL},
+{"keepPosition", "KeepPosition", XtRBoolean, sizeof(Boolean),
+ offset(keep_flag), XtRString, "false"},
+#if PS
+{"postscript", "Postscript", XtRBoolean, sizeof(Boolean),
+ offset(_postscript), XtRString, "true"},
+{"allowShell", "AllowShell", XtRBoolean, sizeof(Boolean),
+ offset(allow_shell), XtRString, "false"},
+#ifdef PS_DPS
+{"dps", "DPS", XtRBoolean, sizeof(Boolean),
+ offset(useDPS), XtRString, "true"},
+#endif
+#ifdef PS_NEWS
+{"news", "News", XtRBoolean, sizeof(Boolean),
+ offset(useNeWS), XtRString, "true"},
+#endif
+#ifdef PS_GS
+{"ghostscript", "Ghostscript", XtRBoolean, sizeof(Boolean),
+ offset(useGS), XtRString, "true"},
+{"gsSafer", "Safer", XtRBoolean, sizeof(Boolean),
+ offset(gs_safer), XtRString, "true"},
+{"gsAlpha", "Alpha", XtRBoolean, sizeof(Boolean),
+ offset(gs_alpha), XtRString, "false"},
+{"interpreter", "Interpreter", XtRString, sizeof(char *),
+ offset(gs_path), XtRString, (XtPointer) GS_PATH},
+{"palette", "Palette", XtRString, sizeof(char *),
+ offset(gs_palette), XtRString, (XtPointer) "Color"},
+#endif
+#endif /* PS */
+{"prescan", "Prescan", XtRBoolean, sizeof(Boolean),
+ offset(prescan), XtRString, "true"},
+{"copy", "Copy", XtRBoolean, sizeof(Boolean),
+ offset(copy), XtRString, "false"},
+{"thorough", "Thorough", XtRBoolean, sizeof(Boolean),
+ offset(thorough), XtRString, "false"},
+#if !EXTRA_APP_DEFAULTS
+{"debugLevel", "DebugLevel", XtRString, sizeof(char *),
+ offset(debug_arg), XtRString, (XtPointer) NULL},
+#endif
+{"version", "Version", XtRBoolean, sizeof(Boolean),
+ offset(version_flag), XtRString, "false"},
+#if BUTTONS
+{"expert", "Expert", XtRBoolean, sizeof(Boolean),
+ offset(expert), XtRString, "false"},
+{"buttonTranslations", "ButtonTranslations", XtRString, sizeof(char *),
+ offset(button_translations), XtRString, (XtPointer) default_button_config},
+{"shrinkButton1", "ShrinkButton1", XtRInt, sizeof(int),
+ offset(shrinkbutton[0]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton2", "ShrinkButton2", XtRInt, sizeof(int),
+ offset(shrinkbutton[1]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton3", "ShrinkButton3", XtRInt, sizeof(int),
+ offset(shrinkbutton[2]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton4", "ShrinkButton4", XtRInt, sizeof(int),
+ offset(shrinkbutton[3]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton5", "ShrinkButton5", XtRInt, sizeof(int),
+ offset(shrinkbutton[4]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton6", "ShrinkButton6", XtRInt, sizeof(int),
+ offset(shrinkbutton[5]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton7", "ShrinkButton7", XtRInt, sizeof(int),
+ offset(shrinkbutton[6]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton8", "ShrinkButton8", XtRInt, sizeof(int),
+ offset(shrinkbutton[7]), XtRImmediate, (XtPointer) 0},
+{"shrinkButton9", "ShrinkButton9", XtRInt, sizeof(int),
+ offset(shrinkbutton[8]), XtRImmediate, (XtPointer) 0},
+{"buttonSideSpacing", "ButtonSpacing", XtRDimension, sizeof(Dimension),
+ offset(btn_side_spacing), XtRImmediate, (XtPointer) 6},
+{"buttonTopSpacing", "ButtonSpacing", XtRDimension, sizeof(Dimension),
+ offset(btn_top_spacing), XtRImmediate, (XtPointer) 50},
+{"buttonBetweenSpacing", "ButtonSpacing", XtRDimension, sizeof(Dimension),
+ offset(btn_between_spacing), XtRImmediate, (XtPointer) 20},
+{"buttonBetweenExtra", "ButtonSpacing", XtRDimension, sizeof(Dimension),
+ offset(btn_between_extra), XtRImmediate, (XtPointer) 50},
+{"buttonBorderWidth", "BorderWidth", XtRDimension, sizeof(Dimension),
+ offset(btn_border_width), XtRImmediate, (XtPointer) 1},
+#endif
+{"magnifierSize1", "MagnifierSize", XtRString, sizeof(char *),
+ offset(mg_arg[0]), XtRString, (XtPointer) NULL},
+{"magnifierSize2", "MagnifierSize", XtRString, sizeof(char *),
+ offset(mg_arg[1]), XtRString, (XtPointer) NULL},
+{"magnifierSize3", "MagnifierSize", XtRString, sizeof(char *),
+ offset(mg_arg[2]), XtRString, (XtPointer) NULL},
+{"magnifierSize4", "MagnifierSize", XtRString, sizeof(char *),
+ offset(mg_arg[3]), XtRString, (XtPointer) NULL},
+{"magnifierSize5", "MagnifierSize", XtRString, sizeof(char *),
+ offset(mg_arg[4]), XtRString, (XtPointer) NULL},
+#if COLOR
+{"color", "Color", XtRBoolean, sizeof(Boolean),
+ offset(_use_color), XtRString, "true"},
+#endif
+{"dvipsPath", "DvipsPath", XtRString, sizeof(char *),
+ offset(dvips_path), XtRString, (XtPointer) DEFAULT_DVIPS_PATH},
+#ifdef GREY
+{"grey", "Grey", XtRBoolean, sizeof(Boolean),
+ offset(_use_grey), XtRString, "true"},
+{"install", "Install", XtRBool3, sizeof(Bool3),
+ offset(install), XtRString, "maybe"},
+};
+
+static XtResource app_pixel_resources[] = { /* get these later */
+#endif /* GREY */
+{"foreground", "Foreground", XtRPixel, sizeof(Pixel),
+ offset(_fore_Pixel), XtRString, XtDefaultForeground},
+{"background", "Background", XtRPixel, sizeof(Pixel),
+ offset(_back_Pixel), XtRString, XtDefaultBackground},
+{"borderColor", "BorderColor", XtRPixel, sizeof(Pixel),
+ offset(_brdr_Pixel), XtRPixel, (XtPointer) &resource._fore_Pixel},
+{"highlight", "Highlight", XtRPixel, sizeof(Pixel),
+ offset(_hl_Pixel), XtRPixel, (XtPointer) &resource._fore_Pixel},
+{"cursorColor", "CursorColor", XtRPixel, sizeof(Pixel),
+ offset(_cr_Pixel), XtRPixel, (XtPointer) &resource._fore_Pixel},
+};
+#undef offset
+
+static _Xconst char *usagestr[] = {
+ /* shrinkFactor */ "shrink",
+#ifndef VMS
+ /* S */ "density",
+ /* density */ silent,
+#else
+ /* density */ "density",
+#endif
+#ifdef GREY
+ /* gamma */ "g",
+#endif
+ /* p */ "pixels",
+ /* margins */ "dimen",
+ /* sidemargin */ "dimen",
+ /* topmargin */ "dimen",
+ /* offsets */ "dimen",
+ /* xoffset */ "dimen",
+ /* yoffset */ "dimen",
+ /* paper */ "papertype",
+ /* altfont */ "font",
+ /* mfmode */ "mode-def",
+ /* editor */ "editor",
+ /* sourceposition */ "\"linenumber filename\"",
+ /* rv */ "^-l", "-rv",
+#ifdef BUTTONS
+ /* shrinkbutton1 */ subst,
+ /* shrinkbutton2 */ silent,
+ /* shrinkbutton3 */ silent,
+ /* shrinkbutton4 */ silent,
+ /* shrinkbutton5 */ silent,
+ /* shrinkbutton6 */ silent,
+ /* shrinkbutton7 */ silent,
+ /* shrinkbutton8 */ silent,
+ /* shrinkbutton9 */ silent,
+#endif
+ /* mgs */ subst,
+ /* mgs1 */ silent,
+ /* mgs2 */ silent,
+ /* mgs3 */ silent,
+ /* mgs4 */ silent,
+ /* mgs5 */ silent,
+ /* bw */ "^-safer", "-bw <width>",
+ /* fg */ "color",
+ /* foreground */ silent,
+ /* bg */ "color",
+ /* background */ silent,
+ /* hl */ "color",
+ /* bd */ "^-hl", "-bd <color>",
+ /* cr */ "color",
+#ifndef VMS
+ /* display */ "^-cr", "-display <host:display>",
+#else
+ /* display */ "^-cr", "-display <host::display>",
+#endif
+ /* geometry */ "^-cr", "-geometry <geometry>",
+ /* icongeometry */ "geometry",
+ /* iconic */ "^-icongeometry", "-iconic",
+#ifdef BUTTONS
+ /* font */ "^-icongeometry", "-font <font>",
+#endif
+ /* wheelunit */ "pixels",
+#ifdef PS_GS
+ /* interpreter */ "path",
+ /* gspalette */ "monochrome|grayscale|color",
+#endif
+ /* dvipspath */ "path",
+ /* debug */ "bitmask",
+ /* [dummy] */ "z"
+};
+
+
+#ifndef MOTIF
+
+#ifdef NOQUERY
+#define drawWidgetClass widgetClass
+#else
+
+/* ARGSUSED */
+static XtGeometryResult
+QueryGeometry(w, constraints, reply)
+ Widget w;
+ XtWidgetGeometry *constraints, *reply;
+{
+ reply->request_mode = CWWidth | CWHeight;
+ reply->width = page_w;
+ reply->height = page_h;
+ return XtGeometryAlmost;
+}
+
+#include <X11/IntrinsicP.h>
+#include <X11/CoreP.h>
+
+#ifdef lint
+WidgetClassRec widgetClassRec;
+#endif
+
+ /* if the following gives you trouble, just compile with -DNOQUERY */
+static WidgetClassRec drawingWidgetClass = {
+ {
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Draw",
+ /* widget_size */ sizeof(WidgetRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize*/ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ NULL,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ NULL,
+ /* num_resources */ 0,
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ FALSE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave*/ FALSE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ XtInheritResize,
+ /* expose */ XtInheritExpose,
+ /* set_values */ NULL,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ XtInheritAcceptFocus,
+ /* version */ XtVersion,
+ /* callback_offsets */ NULL,
+ /* tm_table */ XtInheritTranslations,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+#define drawWidgetClass &drawingWidgetClass
+
+#endif /* NOQUERY */
+#endif /* MOTIF */
+
+static Arg vport_args[] = {
+#if ! MOTIF
+#ifdef BUTTONS
+ {XtNborderWidth, (XtArgVal) 0},
+ {XtNtop, (XtArgVal) XtChainTop},
+ {XtNbottom, (XtArgVal) XtChainBottom},
+ {XtNleft, (XtArgVal) XtChainLeft},
+ {XtNright, (XtArgVal) XtChainRight},
+#endif
+ {XtNallowHoriz, (XtArgVal) True},
+ {XtNallowVert, (XtArgVal) True},
+#else /* MOTIF */
+ {XmNscrollingPolicy, (XtArgVal) XmAUTOMATIC},
+ {XmNborderWidth, (XtArgVal) 0},
+ {XmNleftAttachment, (XtArgVal) XmATTACH_FORM},
+ {XmNtopAttachment, (XtArgVal) XmATTACH_FORM},
+ {XmNbottomAttachment, (XtArgVal) XmATTACH_FORM},
+ {XmNrightAttachment, (XtArgVal) XmATTACH_FORM},
+#endif /* MOTIF */
+};
+
+static Arg draw_args[] = {
+#ifndef MOTIF
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal) 0},
+ {XtNx, (XtArgVal) 0},
+ {XtNy, (XtArgVal) 0},
+ {XtNlabel, (XtArgVal) ""},
+#else /* MOTIF */
+ {XmNwidth, (XtArgVal) 0},
+ {XmNheight, (XtArgVal) 0},
+ {XmNbottomAttachment, (XtArgVal) XmATTACH_WIDGET},
+#endif /* MOTIF */
+};
+
+#if BUTTONS
+static Arg form_args[] = {
+#if !MOTIF
+ {XtNdefaultDistance, (XtArgVal) 0},
+#else /* MOTIF */
+ {XmNhorizontalSpacing, (XtArgVal) 0},
+ {XmNverticalSpacing, (XtArgVal) 0},
+#endif /* MOTIF */
+};
+#endif
+
+#else /* not TOOLKIT */
+
+static char *display;
+static char *geometry;
+static char *margins;
+static char *offsets;
+static Boolean hush;
+static Boolean iconic = False;
+
+#define ADDR(x) (XPointer) &resource.x
+
+static struct option {
+ _Xconst char *name;
+ _Xconst char *resource;
+ enum {FalseArg, TrueArg, StickyArg, SepArg}
+ argclass;
+ enum {BooleanArg, Bool3Arg, StringArg, NumberArg, FloatArg}
+ argtype;
+ int classcount;
+ _Xconst char *usagestr;
+ XPointer address;
+} options[] = {
+{"+", NULL, StickyArg, StringArg, 1,
+ NULL, (XPointer) &curr_page},
+{"-s", "shrinkFactor", SepArg, NumberArg, 1,
+ "shrink", (XPointer) &shrink_factor},
+#ifndef VMS
+{"-S", NULL, SepArg, NumberArg, 2,
+ "density", ADDR(_density)},
+{"-density", "densityPercent", SepArg, NumberArg, 1,
+ silent, ADDR(_density)},
+#else
+{"-density", "densityPercent", SepArg, NumberArg, 1,
+ "density", ADDR(_density)},
+#endif
+#if COLOR
+{"-nocolor", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(_use_color)},
+{"+nocolor", "color", TrueArg, BooleanArg, 1,
+ NULL, ADDR(_use_color)},
+#endif
+#ifdef GREY
+{"-nogrey", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(_use_grey)},
+{"+nogrey", "grey", TrueArg, BooleanArg, 1,
+ NULL, ADDR(_use_grey)},
+{"-gamma", "gamma", SepArg, FloatArg, 1,
+ "g", ADDR(_gamma)},
+{"-install", NULL, TrueArg, Bool3Arg, 2,
+ NULL, ADDR(install)},
+{"-noinstall", "install", FalseArg, Bool3Arg, 1,
+ NULL, ADDR(install)},
+#endif
+{"-p", "pixelsPerInch", SepArg, NumberArg, 1,
+ "pixels", ADDR(_pixels_per_inch)},
+{"-margins", "Margin", SepArg, StringArg, 3,
+ "dimen", (XPointer) &margins},
+{"-sidemargin", "sideMargin", SepArg, StringArg, 1,
+ "dimen", ADDR(sidemargin)},
+{"-topmargin", "topMargin", SepArg, StringArg, 1,
+ "dimen", ADDR(topmargin)},
+{"-offsets", "Offset", SepArg, StringArg, 3,
+ "dimen", (XPointer) &offsets},
+{"-xoffset", "xOffset", SepArg, StringArg, 1,
+ "dimen", ADDR(xoffset)},
+{"-yoffset", "yOffset", SepArg, StringArg, 1,
+ "dimen", ADDR(yoffset)},
+{"-paper", "paper", SepArg, StringArg, 1,
+ "papertype", ADDR(paper)},
+{"-altfont", "altFont", SepArg, StringArg, 1,
+ "font", ADDR(_alt_font)},
+#ifdef MKTEXPK
+{"-nomakepk", "makePk", FalseArg, BooleanArg, 2,
+ NULL, ADDR(makepk)},
+{"+nomakepk", "makePk", TrueArg, BooleanArg, 1,
+ NULL, ADDR(makepk)},
+#endif
+{"-mfmode", "mfMode", SepArg, StringArg, 1,
+ "mode-def", ADDR(mfmode)},
+{"-editor", "editor", SepArg, StringArg, 1,
+ "editor", ADDR(editor)},
+{"-sourceposition","sourcePosition", SepArg, StringArg, 1,
+ "\"linenumber filename\"",ADDR(src_pos)},
+{"-nofork", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(src_fork)},
+{"+nofork", "fork", TrueArg, BooleanArg, 1,
+ NULL, ADDR(src_fork)},
+{"-l", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(_list_fonts)},
+{"+l", "listFonts", FalseArg, BooleanArg, 1,
+ NULL, ADDR(_list_fonts)},
+#if FREETYPE
+{"-nofreetypefonts", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(freetype)},
+{"+nofreetypefonts", "freetypeFonts", TrueArg, BooleanArg, 1,
+ NULL, ADDR(freetype)},
+#endif
+{"-rv", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(reverse)},
+{"+rv", "reverseVideo", FalseArg, BooleanArg, 1,
+ NULL, ADDR(reverse)},
+{"-mgs", NULL, SepArg, StringArg, 2,
+ subst, ADDR(mg_arg[0])},
+{"-mgs1", "magnifierSize1",SepArg, StringArg, 1,
+ silent, ADDR(mg_arg[0])},
+{"-mgs2", "magnifierSize2",SepArg, StringArg, 1,
+ silent, ADDR(mg_arg[1])},
+{"-mgs3", "magnifierSize3",SepArg, StringArg, 1,
+ silent, ADDR(mg_arg[2])},
+{"-mgs4", "magnifierSize4",SepArg, StringArg, 1,
+ silent, ADDR(mg_arg[3])},
+{"-mgs5", "magnifierSize5",SepArg, StringArg, 1,
+ silent, ADDR(mg_arg[4])},
+{"-warnspecials", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(_warn_spec)},
+{"+warnspecials", "warnSpecials", FalseArg, BooleanArg, 1,
+ NULL, ADDR(_warn_spec)},
+{"-hush", NULL, TrueArg, BooleanArg, 6,
+ NULL, (XPointer) &hush},
+{"+hush", "Hush", FalseArg, BooleanArg, 5,
+ NULL, (XPointer) &hush},
+{"-hushchars", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(_hush_chars)},
+{"+hushchars", "hushLostChars", FalseArg, BooleanArg, 1,
+ NULL, ADDR(_hush_chars)},
+{"-hushchecksums", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(_hush_chk)},
+{"+hushchecksums","hushChecksums", FalseArg, BooleanArg, 1,
+ NULL, ADDR(_hush_chk)},
+{"-safer", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(safer)},
+{"+safer", "safer", FalseArg, BooleanArg, 1,
+ NULL, ADDR(safer)},
+{"-bw", NULL, SepArg, NumberArg, 2,
+ "width", (XPointer) &bwidth},
+{"-borderwidth", "borderWidth", SepArg, NumberArg, 1,
+ silent, (XPointer) &bwidth},
+{"-fg", NULL, SepArg, StringArg, 2,
+ "color", ADDR(fore_color)},
+{"-foreground", "foreground", SepArg, StringArg, 1,
+ silent, ADDR(fore_color)},
+{"-bg", NULL, SepArg, StringArg, 2,
+ "color", ADDR(back_color)},
+{"-background", "background", SepArg, StringArg, 1,
+ silent, ADDR(back_color)},
+{"-hl", "highlight", SepArg, StringArg, 1,
+ "color", (XPointer) &high_color},
+{"-bd", NULL, SepArg, StringArg, 2,
+ "color", (XPointer) &brdr_color},
+{"-bordercolor","borderColor", SepArg, StringArg, 1,
+ silent, (XPointer) &brdr_color},
+{"-cr", "cursorColor", SepArg, StringArg, 1,
+ "color", (XPointer) &curs_color},
+#ifndef VMS
+{"-display", NULL, SepArg, StringArg, 1,
+ "host:display", (XPointer) &display},
+#else
+{"-display", NULL, SepArg, StringArg, 1,
+ "host::display", (XPointer) &display},
+#endif
+{"-geometry", "geometry", SepArg, StringArg, 1,
+ "geometry", (XPointer) &geometry},
+{"-icongeometry","iconGeometry",StickyArg, StringArg, 1,
+ "geometry", ADDR(icon_geometry)},
+{"-iconic", NULL, TrueArg, BooleanArg, 2,
+ NULL, (XPointer) &iconic},
+{"+iconic", "iconic", FalseArg, BooleanArg, 1,
+ NULL, (XPointer) &iconic},
+{"-keep", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(keep_flag)},
+{"+keep", "keepPosition", FalseArg, BooleanArg, 1,
+ NULL, ADDR(keep_flag)},
+{"-copy", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(copy)},
+{"+copy", "copy", FalseArg, BooleanArg, 1,
+ NULL, ADDR(copy)},
+{"-thorough", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(thorough)},
+{"+thorough", "thorough", FalseArg, BooleanArg, 1,
+ NULL, ADDR(thorough)},
+{"-wheelunit", "wheelUnit", SepArg, NumberArg, 1,
+ "pixels", ADDR(wheel_unit)},
+#if PS
+{"-nopostscript", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(_postscript)},
+{"+nopostscript", "postscript", TrueArg, BooleanArg, 1,
+ NULL, ADDR(_postscript)},
+{"-allowshell", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(allow_shell)},
+{"+allowshell", "allowShell", FalseArg, BooleanArg, 1,
+ NULL, ADDR(allow_shell)},
+#ifdef PS_DPS
+{"-nodps", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(useDPS)},
+{"+nodps", "dps", TrueArg, BooleanArg, 1,
+ NULL, ADDR(useDPS)},
+#endif
+#ifdef PS_NEWS
+{"-nonews", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(useNeWS)},
+{"+nonews", "news", TrueArg, BooleanArg, 1,
+ NULL, ADDR(useNeWS)},
+#endif
+#ifdef PS_GS
+{"-noghostscript",NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(useGS)},
+{"+noghostscript","ghostscript", TrueArg, BooleanArg, 1,
+ NULL, ADDR(useGS)},
+{"-nogssafer", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(gs_safer)},
+{"+nogssafer", "gsSafer", TrueArg, BooleanArg, 1,
+ NULL, ADDR(gs_safer)},
+{"-gsalpha", NULL, TrueArg, BooleanArg, 2,
+ NULL, ADDR(gs_alpha)},
+{"+gsalpha", "gsAlpha", FalseArg, BooleanArg, 1,
+ NULL, ADDR(gs_alpha)},
+{"-interpreter", "interpreter", SepArg, StringArg, 1,
+ "path", ADDR(gs_path)},
+{"-gspalette", "palette", SepArg, StringArg, 1,
+ "monochrome|grayscale|color", ADDR(gs_palette)},
+#endif
+#endif /* PS */
+{"-noscan", NULL, FalseArg, BooleanArg, 2,
+ NULL, ADDR(prescan)},
+{"+noscan", "prescan", TrueArg, BooleanArg, 1,
+ NULL, ADDR(prescan)},
+{"-debug", "debugLevel", SepArg, StringArg, 1,
+ "bitmask", ADDR(debug_arg)},
+{"-version", NULL, TrueArg, BooleanArg, 3,
+ NULL, ADDR(version_flag)},
+{"+version", "version", FalseArg, BooleanArg, 2,
+ NULL, ADDR(version_flag)},
+{"--version", NULL, TrueArg, BooleanArg, 1,
+ NULL, ADDR(version_flag)},
+};
+
+#endif /* not TOOLKIT */
+
+static void usage VARGS((_Xconst char *, ...)) NORETURN;
+
+#if NeedVarargsPrototypes
+static void
+usage(_Xconst char *message, ...)
+#else
+/* VARARGS */
+void
+usage(va_alist)
+ va_dcl
+#endif
+{
+#if !NeedVarargsPrototypes
+ _Xconst char *message;
+#endif
+ va_list args;
+#if TOOLKIT
+ XrmOptionDescRec *opt;
+ _Xconst char **usageptr = usagestr;
+#else
+ struct option *opt;
+#endif
+ _Xconst char **sv = subst_val;
+ _Xconst char *str1;
+ _Xconst char *str2;
+ int col = 23;
+ int n;
+
+ Fprintf(stderr, "%s: ", prog);
+
+#if NeedVarargsPrototypes
+ va_start(args, message);
+#else
+ va_start(args);
+ message = va_arg(args, _Xconst char *);
+#endif
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+
+ Fputs("\n\nUsage: xdvi [+[<page>]]", stderr);
+ for (opt = options; opt < options + XtNumber(options); ++opt) {
+#if TOOLKIT
+ str1 = opt->option;
+ if (*str1 != '-') continue;
+ str2 = NULL;
+ if (opt->argKind != XrmoptionNoArg) {
+ str2 = *usageptr++;
+ if (str2 == silent) continue;
+ if (str2 == subst) {
+ str1 = *sv++;
+ str2 = NULL;
+ }
+ }
+ for (;;) {
+ n = strlen(str1) + 3;
+ if (str2 != NULL) n += strlen(str2) + 3;
+ if (col + n < 80) Putc(' ', stderr);
+ else {
+ Fputs("\n\t", stderr);
+ col = 8 - 1;
+ }
+ if (str2 == NULL)
+ Fprintf(stderr, "[%s]", str1);
+ else
+ Fprintf(stderr, "[%s <%s>]", str1, str2);
+ col += n;
+ if (**usageptr != '^'
+ || strcmp(*usageptr + 1, opt->option) != 0) break;
+ ++usageptr;
+ str1 = *usageptr++;
+ str2 = NULL;
+ }
+#else /* not TOOLKIT */
+ str1 = opt->name;
+ str2 = opt->usagestr;
+ if (*str1 != '-' || str2 == silent) continue;
+ if (str2 == subst) {
+ str1 = *sv++;
+ str2 = NULL;
+ }
+ n = strlen(str1) + 3;
+ if (str2 != NULL) n += strlen(str2) + 3;
+ if (col + n < 80) Putc(' ', stderr);
+ else {
+ Fputs("\n\t", stderr);
+ col = 8 - 1;
+ }
+ if (str2 == NULL)
+ Fprintf(stderr, "[%s]", str1);
+ else
+ Fprintf(stderr, "[%s <%s>]", str1, str2);
+ col += n;
+#endif /* not TOOLKIT */
+ }
+ if (col + 9 < 80) Putc(' ', stderr);
+ else Fputs("\n\t", stderr);
+ Fputs("dvi_file\n", stderr);
+ exit(1);
+}
+
+int
+atopix(arg, allow_minus)
+ _Xconst char *arg;
+ Boolean allow_minus;
+{
+ int len = strlen(arg);
+ _Xconst char *arg_end = arg;
+ char tmp[11];
+ double factor;
+
+ if (allow_minus && *arg_end == '-') ++arg_end;
+ while ((*arg_end >= '0' && *arg_end <= '9') || *arg_end == '.')
+ if (arg_end >= arg + XtNumber(tmp) - 1) return 0;
+ else ++arg_end;
+ bcopy(arg, tmp, arg_end - arg);
+ tmp[arg_end - arg] = '\0';
+
+#if A4
+ factor = 1.0 / 2.54; /* cm */
+#else
+ factor = 1.0; /* inches */
+#endif
+ if (len > 2)
+ switch (arg[len - 2] << 8 | arg[len - 1]) {
+#if A4
+ case 'i' << 8 | 'n': factor = 1.0; break;
+#else
+ case 'c' << 8 | 'm': factor = 1.0 / 2.54; break;
+#endif
+ case 'm' << 8 | 'm': factor = 1.0 / 25.4; break;
+ case 'p' << 8 | 't': factor = 1.0 / 72.27; break;
+ case 'p' << 8 | 'c': factor = 12.0 / 72.27; break;
+ case 'b' << 8 | 'p': factor = 1.0 / 72.0; break;
+ case 'd' << 8 | 'd': factor = 1238.0 / 1157.0 / 72.27; break;
+ case 'c' << 8 | 'c': factor = 12 * 1238.0 / 1157.0 / 72.27;
+ break;
+ case 's' << 8 | 'p': factor = 1.0 / 72.27 / 65536; break;
+ }
+
+ return (int) (factor * atof(tmp) * pixels_per_inch + 0.5);
+}
+
+/**
+ ** Main program starts here.
+ **/
+
+#ifdef TOOLKIT
+
+#ifdef GREY
+static Arg temp_args1[] = {
+ {XtNdepth, (XtArgVal) 0},
+ {XtNvisual, (XtArgVal) 0},
+ {XtNcolormap, (XtArgVal) 0},
+};
+#define temp_args1a (temp_args1 + 2)
+#endif
+
+static Arg temp_args2[] = {
+ {XtNiconX, (XtArgVal) 0},
+ {XtNiconY, (XtArgVal) 0},
+};
+
+static Arg temp_args3 = {XtNborderWidth, (XtArgVal) &bwidth};
+
+static Pixmap icon_pm;
+static Arg temp_args4 = {XtNiconPixmap, (XtArgVal) &icon_pm};
+
+static Arg set_wh_args[] = {
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal) 0},
+};
+
+
+#ifdef GREY
+
+/*
+ * Alternate routine to convert color name to Pixel (needed to substitute
+ * "black" or "white" for BlackPixelOfScreen, etc., since a different
+ * visual and colormap are in use).
+ */
+
+#if XtSpecificationRelease >= 5
+
+/*ARGSUSED*/
+static Boolean
+XdviCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret)
+ Display *dpy;
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr fromVal;
+ XrmValuePtr toVal;
+ XtPointer *closure_ret;
+{
+ XrmValue replacement_val;
+ Boolean default_is_fg;
+
+ if ((strcmp((String) fromVal->addr, XtDefaultForeground) == 0
+ && (default_is_fg = True))
+ || (strcmp((String) fromVal->addr, XtDefaultBackground) == 0
+ && ((default_is_fg = False), True))) {
+ replacement_val.size = sizeof(String);
+ replacement_val.addr = (default_is_fg == resource.reverse)
+ ? "white" : "black";
+ fromVal = &replacement_val;
+ }
+
+ return
+ XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret);
+}
+
+#else /* XtSpecificationRelease < 5 */
+
+/*
+ * Copied from the X11R4 source code.
+ */
+
+#define done(type, value) \
+ { \
+ if (toVal->addr != NULL) { \
+ if (toVal->size < sizeof(type)) { \
+ toVal->size = sizeof(type); \
+ return False; \
+ } \
+ *(type*)(toVal->addr) = (value); \
+ } \
+ else { \
+ static type static_val; \
+ static_val = (value); \
+ toVal->addr = (XtPointer)&static_val; \
+ } \
+ toVal->size = sizeof(type); \
+ return True; \
+ }
+
+static Boolean
+XdviCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret)
+ Display* dpy;
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr fromVal;
+ XrmValuePtr toVal;
+ XtPointer *closure_ret;
+{
+ String str = (String)fromVal->addr;
+ XColor screenColor;
+ XColor exactColor;
+ Screen *screen;
+ Colormap colormap;
+ Status status;
+ String params[1];
+ Cardinal num_params=1;
+
+ if (*num_args != 2)
+ XtErrorMsg("wrongParameters", "cvtStringToPixel",
+ "XtToolkitError",
+ "String to pixel conversion needs screen and colormap arguments",
+ (String *)NULL, (Cardinal *)NULL);
+
+ screen = *((Screen **) args[0].addr);
+ colormap = *((Colormap *) args[1].addr);
+
+ if (strcmp(str, XtDefaultBackground) == 0) {
+ *closure_ret = False;
+ str = (resource.reverse ? "black" : "white");
+ }
+ else if (strcmp(str, XtDefaultForeground) == 0) {
+ *closure_ret = False;
+ str = (resource.reverse ? "white" : "black");
+ }
+
+ if (*str == '#') { /* some color rgb definition */
+
+ status = XParseColor(DisplayOfScreen(screen), colormap,
+ (char*)str, &screenColor);
+
+ if (status != 0)
+ status = XAllocColor(DisplayOfScreen(screen), colormap,
+ &screenColor);
+ } else /* some color name */
+
+ status = XAllocNamedColor(DisplayOfScreen(screen), colormap,
+ (char*)str, &screenColor, &exactColor);
+ if (status == 0) {
+ params[0] = str;
+ XtWarningMsg("noColormap", "cvtStringToPixel",
+ "XtToolkitError",
+ "Cannot allocate colormap entry for \"%s\"",
+ params,&num_params);
+ return False;
+ } else {
+ *closure_ret = (char*)True;
+ done(Pixel, screenColor.pixel);
+ }
+}
+#undef done
+
+#endif /* XtSpecificationRelease < 5 */
+
+/*
+ * Convert string to yes/no/maybe. Adapted from the X toolkit.
+ */
+
+/*ARGSUSED*/
+static Boolean
+XdviCvtStringToBool3(dpy, args, num_args, fromVal, toVal, closure_ret)
+ Display *dpy;
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr fromVal;
+ XrmValuePtr toVal;
+ XtPointer *closure_ret;
+{
+ String str = (String)fromVal->addr;
+ static Bool3 value;
+
+ if ( memicmp(str, "true", 5) == 0
+ || memicmp(str, "yes", 4) == 0
+ || memicmp(str, "on", 3) == 0
+ || memicmp(str, "1", 2) == 0) value = True;
+
+ else if (memicmp(str, "false", 6) == 0
+ || memicmp(str, "no", 3) == 0
+ || memicmp(str, "off", 4) == 0
+ || memicmp(str, "0", 2) == 0) value = False;
+
+ else if (memicmp(str, "maybe", 6) == 0) value = Maybe;
+
+ else {
+ XtDisplayStringConversionWarning(dpy, str, XtRBoolean);
+ return False;
+ }
+
+ if (toVal->addr != NULL) {
+ if (toVal->size < sizeof(Bool3)) {
+ toVal->size = sizeof(Bool3);
+ return False;
+ }
+ *(Bool3 *)(toVal->addr) = value;
+ }
+ else toVal->addr = (XPointer) &value;
+
+ toVal->size = sizeof(Bool3);
+ return True;
+}
+
+#endif /* GREY */
+
+#else /* not TOOLKIT */
+
+struct _resource resource = {
+ /* wheel_unit */ 80,
+ /* density */ 40,
+#ifdef GREY
+ /* gamma */ 1.0,
+#endif
+ /* pixels_per_inch */ BDPI,
+ /* sidemargin */ NULL,
+ /* topmargin */ NULL,
+ /* xoffset */ NULL,
+ /* yoffset */ NULL,
+ /* paper */ DEFAULT_PAPER,
+ /* alt_font */ ALTFONT,
+#ifdef MKTEXPK
+ /* makepk */ True,
+#endif
+ /* mfmode */ MFMODE,
+ /* editor */ NULL,
+ /* src_pos */ NULL,
+ /* src_fork */ True,
+ /* list_fonts */ False,
+#if FREETYPE
+ /* freetype */ True,
+#endif
+ /* reverse */ False,
+ /* warn_spec */ False,
+ /* hush_chars */ False,
+ /* hush_chk */ False,
+ /* safer */ False,
+ /* fore_color */ NULL,
+ /* back_color */ NULL,
+ /* fore_Pixel */ (Pixel) 0,
+ /* back_Pixel */ (Pixel) 0,
+ /* icon_geometry */ NULL,
+ /* keep_flag */ False,
+ /* copy */ False,
+ /* thorough */ False,
+#if PS
+ /* postscript */ True,
+ /* allow_shell */ False,
+#ifdef PS_DPS
+ /* useDPS */ True,
+#endif
+#ifdef PS_NEWS
+ /* useNeWS */ True,
+#endif
+#ifdef PS_GS
+ /* useGS */ True,
+ /* gs_safer */ True,
+ /* gs_alpha */ False,
+ /* gs_path */ GS_PATH,
+ /* gs_palette */ "Color",
+#endif
+#endif /* PS */
+ /* prescan */ True,
+ /* debug_arg */ NULL,
+ /* version_flag */ False,
+ /* mg_arg */ {NULL, NULL, NULL, NULL, NULL},
+#if COLOR
+ /* use_color */ True,
+#endif
+#ifdef GREY
+ /* use_grey */ True,
+ /* install */ Maybe,
+#endif
+};
+
+static Pixel
+string_to_pixel(strp) /* adapted from the toolkit */
+ char **strp;
+{
+ char *str = *strp;
+ Status status;
+ XColor color, junk;
+
+ if (*str == '#') { /* an rgb definition */
+ status = XParseColor(DISP, our_colormap, str, &color);
+ if (status != 0)
+ status = XAllocColor(DISP, our_colormap, &color);
+ }
+ else /* a name */
+ status = XAllocNamedColor(DISP, our_colormap, str, &color, &junk);
+ if (status == 0) {
+ WARN1(XmDIALOG_WARNING,
+ "Cannot allocate colormap entry\nfor \"%s\"", str);
+ *strp = NULL;
+ return (Pixel) 0;
+ }
+ return color.pixel;
+}
+
+/*
+ * Process the option table. This is not guaranteed for all possible
+ * option tables, but at least it works for this one.
+ */
+
+static void
+parse_options(argc, argv)
+ int argc;
+ char **argv;
+{
+ char **arg;
+ char **argvend = argv + argc;
+ char *optstring;
+ XPointer addr;
+ struct option *opt, *lastopt, *candidate;
+ int len1, len2, matchlen;
+
+ /*
+ * Step 1. Process command line options.
+ */
+ for (arg = argv + 1; arg < argvend; ++arg) {
+ len1 = strlen(*arg);
+ candidate = NULL;
+ matchlen = 0;
+ for (opt = options; opt < options + XtNumber(options); ++opt) {
+ len2 = strlen(opt->name);
+ if (opt->argclass == StickyArg) {
+ if (matchlen <= len2 && !strncmp(*arg, opt->name, len2)) {
+ candidate = opt;
+ matchlen = len2;
+ }
+ }
+ else if (len1 <= len2 && matchlen <= len1 &&
+ !strncmp(*arg, opt->name, len1)) {
+ if (len1 == len2) {
+ candidate = opt;
+ break;
+ }
+ if (matchlen < len1) candidate = opt;
+ else if (candidate && candidate->argclass != StickyArg)
+ candidate = NULL;
+ matchlen = len1;
+ }
+ }
+ if (candidate == NULL) {
+ if (**arg == '-')
+ usage("Invalid argument \"%s\".", *arg);
+ else if (dvi_name)
+ usage(
+ "More than one dvi file name given:\n\t\"%s\", \"%s\".",
+ dvi_name, *arg);
+ else {
+ dvi_name = *arg;
+ continue;
+ }
+ }
+ /* flag it for subsequent processing */
+ candidate->resource = (char *) candidate;
+ /* store the value */
+ addr = candidate->address;
+ switch (candidate->argclass) {
+ case FalseArg: *((Boolean *) addr) = False; continue;
+ case TrueArg: *((Boolean *) addr) = True; continue;
+ case StickyArg: optstring = *arg + strlen(candidate->name);
+ break;
+ case SepArg:
+ ++arg;
+ if (arg >= argvend)
+ usage("Option \"%s\" appears without an argument.",
+ arg[-1]);
+ optstring = *arg;
+ break;
+ }
+ switch (candidate->argtype) {
+ case StringArg: *((char **) addr) = optstring; break;
+ case NumberArg: *((int *) addr) = atoi(optstring); break;
+ case FloatArg: *((float *) addr) = atof(optstring); break;
+ default: ;
+ }
+ }
+ /*
+ * Step 2. Propagate classes for command line arguments. Backwards.
+ */
+ for (opt = options + XtNumber(options) - 1; opt >= options; --opt)
+ if (opt->resource == (char *) opt) {
+ addr = opt->address;
+ lastopt = opt + opt->classcount;
+ for (candidate = opt; candidate < lastopt; ++candidate) {
+ if (candidate->resource != NULL) {
+ switch (opt->argtype) {
+ case BooleanArg:
+ case Bool3Arg: /* same type as Boolean */
+ *((Boolean *) candidate->address) =
+ *((Boolean *) addr);
+ break;
+ case StringArg:
+ *((char **) candidate->address) =
+ *((char **) addr);
+ break;
+ case NumberArg:
+ *((int *) candidate->address) = *((int *) addr);
+ break;
+ case FloatArg:
+ *((float *) candidate->address) =
+ *((float *) addr);
+ break;
+ }
+ candidate->resource = NULL;
+ }
+ }
+ }
+
+ if ((DISP = XOpenDisplay(display)) == NULL)
+ oops("Can't open display");
+ SCRN = DefaultScreenOfDisplay(DISP);
+ /*
+ * Step 3. Handle resources (including classes).
+ */
+ for (opt = options; opt < options + XtNumber(options); ++opt)
+ if (opt->resource &&
+ ((optstring = XGetDefault(DISP, prog, opt->resource)) ||
+ (optstring = XGetDefault(DISP, "XDvi", opt->resource))))
+ {
+ lastopt = opt + opt->classcount;
+ for (candidate = opt; candidate < lastopt; ++candidate)
+ if (candidate->resource != NULL) switch (opt->argtype) {
+ case Bool3Arg:
+ if ( memicmp(optstring, "maybe", 6) == 0)
+ {
+ * (Bool3 *) candidate->address = Maybe;
+ break;
+ }
+ /* otherwise, fall through; the underlying */
+ /* types of Bool3 and Boolean are the same. */
+ case BooleanArg:
+ * (Boolean *) candidate->address =
+ ( memicmp(optstring, "true", 5) == 0
+ || memicmp(optstring, "yes", 4) == 0
+ || memicmp(optstring, "on", 3) == 0
+ || memicmp(optstring, "1", 2) == 0);
+ break;
+ case StringArg:
+ * (char **) candidate->address = optstring;
+ break;
+ case NumberArg:
+ * (int *) candidate->address = atoi(optstring);
+ break;
+ case FloatArg:
+ * (float *) candidate->address =
+ atof(optstring);
+ }
+ }
+}
+
+#endif /* not TOOLKIT */
+
+/*
+ * Routines for running as source-special client.
+ *
+ * Resources are used as follows:
+ *
+ * ATOM_XDVI_WINDOWS is attached to the root window of the default screen
+ * of the display; it contains a list of (hopefully active) xdvi
+ * windows.
+ * ATOM_DVI_FILE is attached to the main xdvi window; it tells the world
+ * what dvi file is being viewed. It is set by that copy of xdvi
+ * and read by this routine. The first 8 bytes are the inode
+ * number, and the rest is the file name. We use 8 instead of
+ * sizeof(ino_t) because the latter may vary from machine to
+ * machine, and the format needs to be machine independent.
+ * ATOM_SRC_GOTO is attached to the main xdvi window; it tells that copy
+ * of xdvi to go to that position in the dvi file. It is set by
+ * this routine and read by the displaying copy of xdvi.
+ */
+
+static int XdviErrorHandler P2H(Display *, XErrorEvent *);
+
+static unsigned long xdvi_next_request = 0;
+static int xerrno;
+static int (*XdviOldErrorHandler) ARGS((Display *, XErrorEvent *));
+
+static int
+XdviErrorHandler(d, event)
+ Display *d;
+ XErrorEvent *event;
+{
+ if (event->serial != xdvi_next_request
+ || event->error_code != BadWindow)
+ return XdviOldErrorHandler(d, event);
+
+ xerrno = 1;
+ return 0;
+}
+
+static int
+XdviGetWindowProperty(display, w, property, long_offset, long_length, delete,
+ req_type, actual_type_return, actual_format_return, nitems_return,
+ bytes_after_return, prop_return)
+ Display *display;
+ Window w;
+ Atom property;
+ long long_offset, long_length;
+ Bool delete;
+ Atom req_type;
+ Atom *actual_type_return;
+ int *actual_format_return;
+ unsigned long *nitems_return;
+ unsigned long *bytes_after_return;
+ unsigned char **prop_return;
+{
+ int retval;
+
+ xdvi_next_request = NextRequest(display);
+ xerrno = 0;
+
+ retval = XGetWindowProperty(display, w, property, long_offset,
+ long_length, delete, req_type, actual_type_return,
+ actual_format_return, nitems_return, bytes_after_return, prop_return);
+
+ return (xerrno != 0 ? BadWindow : retval);
+}
+
+/*
+ * src_client_check() - Check for another running copy of xdvi viewing
+ * the same file. If one exists, return true and send that copy of xdvi
+ * the argument to -sourceposition. If not, return false.
+ */
+
+static Boolean
+src_client_check()
+{
+ long *window_list;
+ size_t window_list_len;
+ long *window_list_end;
+ long *wp;
+ unsigned char *p;
+ Boolean need_rewrite;
+ Boolean retval = False;
+
+ /*
+ * Get window list. Copy it over
+ * (we'll be calling property_get_data() again).
+ */
+
+ window_list_len = property_get_data(DefaultRootWindow(DISP),
+ ATOM_XDVI_WINDOWS, &p, XGetWindowProperty);
+
+ if (window_list_len == 0) {
+ if (debug & DBG_CLIENT)
+ puts("No \"xdvi windows\" property found");
+ return False;
+ }
+
+ if (window_list_len % sizeof(long) != 0) {
+ if (debug & DBG_CLIENT)
+ puts(
+ "\"xdvi windows\" property had incorrect size; deleting it.");
+ XDeleteProperty(DISP, DefaultRootWindow(DISP), ATOM_XDVI_WINDOWS);
+ return False;
+ }
+
+ window_list = xmalloc(window_list_len);
+ memcpy(window_list, p, window_list_len);
+
+ XdviOldErrorHandler = XSetErrorHandler(XdviErrorHandler);
+
+ /* Loop over list of windows. */
+
+ need_rewrite = False;
+ window_list_len /= sizeof(long);
+ window_list_end = window_list + window_list_len;
+ for (wp = window_list; wp < window_list_end; ++wp) {
+ Window w = *wp;
+ unsigned char *buf_ret;
+ size_t len;
+
+ if (debug & DBG_CLIENT) {
+ printf("Checking window %08lx -- ", w);
+ fflush(stdout);
+ }
+
+ len = property_get_data(w, ATOM_DVI_FILE, &buf_ret,
+ XdviGetWindowProperty);
+
+ if (len == 0) {
+ if (debug & DBG_CLIENT)
+ puts("(null)");
+ --window_list_len;
+ --window_list_end;
+ memcpy(wp, wp + 1, (window_list_end - wp) * sizeof(long));
+ --wp;
+ need_rewrite = True;
+ continue;
+ }
+
+ if (debug & DBG_CLIENT) {
+ unsigned long ino;
+ int i;
+
+ ino = 0;
+ for (i = 7; i >= 0; --i)
+ ino = (ino << 8) | buf_ret[i];
+ printf("%lu `%s'\n", ino, buf_ret + 8);
+ }
+
+ if (len == dvi_property_length
+ && memcmp(buf_ret, dvi_property, len) == 0) {
+
+ if (debug & DBG_CLIENT)
+ puts("Matched!");
+
+ XChangeProperty(DISP, w,
+ ATOM_SRC_GOTO, ATOM_SRC_GOTO, 8, PropModeReplace,
+ (_Xconst unsigned char *) resource.src_pos,
+ strlen(resource.src_pos));
+
+ retval = True;
+ break;
+ }
+ }
+
+ (void) XSetErrorHandler(XdviOldErrorHandler);
+
+ if (need_rewrite)
+ XChangeProperty(DISP, DefaultRootWindow(DISP),
+ ATOM_XDVI_WINDOWS, ATOM_XDVI_WINDOWS, 32, PropModeReplace,
+ (unsigned char *) window_list, window_list_len);
+
+ return retval;
+}
+
+
+/*
+ * Translations of valid paper types to dimensions, which are used
+ * internally.
+ */
+
+static _Xconst char *paper_types[] = {
+ "letter", "8.5x11in",
+ "letterr", "11x8.5in",
+ "us", "8.5x11in",
+ "usr", "11x8.5in",
+ "legal", "8.5x14in",
+ "legalr", "14x8.5in",
+ "foolscap", "13.5x17.0in", /* ??? */
+ "foolscapr", "17x13.5in",
+ NULL, NULL, /* hack used for formatting the list */
+
+ /* ISO `A' formats, Portrait */
+ "a1", "594x841mm",
+ "a2", "420x594mm",
+ "a3", "297x420mm",
+ "a4", "210x297mm",
+ "a5", "148x210mm",
+ "a6", "105x148mm",
+ "a7", "74x105mm",
+ NULL, NULL,
+
+ /* ISO `A' formats, Landscape */
+ "a1r", "840x594mm",
+ "a2r", "594x420mm",
+ "a3r", "420x297mm",
+ "a4r", "297x210mm",
+ "a5r", "210x148mm",
+ "a6r", "148x105mm",
+ "a7r", "105x74mm",
+ NULL, NULL,
+
+ /* ISO `B' formats, Portrait */
+ "b1", "707x1000mm",
+ "b2", "500x707mm",
+ "b3", "353x500mm",
+ "b4", "250x353mm",
+ "b5", "176x250mm",
+ "b6", "125x176mm",
+ "b7", "88x125mm",
+ NULL, NULL,
+
+ /* ISO `B' formats, Landscape */
+ "b1r", "1000x707mm",
+ "b2r", "707x500mm",
+ "b3r", "500x353mm",
+ "b4r", "353x250mm",
+ "b5r", "250x176mm",
+ "b6r", "176x125mm",
+ "b7r", "125x88mm",
+ NULL, NULL,
+
+ /* ISO `C' formats, Portrait */
+ "c1", "648x917mm",
+ "c2", "458x648mm",
+ "c3", "324x458mm",
+ "c4", "229x324mm",
+ "c5", "162x229mm",
+ "c6", "114x162mm",
+ "c7", "81x114mm",
+ NULL, NULL,
+
+ /* ISO `C' formats, Landscape */
+ "c1r", "917x648mm",
+ "c2r", "648x458mm",
+ "c3r", "458x324mm",
+ "c4r", "324x229mm",
+ "c5r", "229x162mm",
+ "c6r", "162x114mm",
+ "c7r", "114x81mm",
+};
+
+static Boolean
+set_paper_type() {
+ _Xconst char *arg, *arg1;
+ char temp[21];
+ _Xconst char **p;
+ char *q;
+
+ arg = resource.paper;
+ if (*arg == '+') {
+ ++arg;
+ ignore_papersize_specials = True;
+ }
+ if (strlen(arg) > sizeof(temp) - 1) return False;
+ q = temp;
+ for (;;) { /* convert to lower case */
+ char c = *arg++;
+ if (c >= 'A' && c <= 'Z') c ^= ('a' ^ 'A');
+ *q++ = c;
+ if (c == '\0') break;
+ }
+ arg = temp;
+ /* perform substitutions */
+ for (p = paper_types; p < paper_types + XtNumber(paper_types); p += 2)
+ if (*p != NULL && strcmp(temp, *p) == 0) {
+ arg = p[1];
+ break;
+ }
+ arg1 = index(arg, 'x');
+ if (arg1 == NULL) return False;
+ unshrunk_paper_w = atopix(arg, False);
+ unshrunk_paper_h = atopix(arg1 + 1, False);
+ return (unshrunk_paper_w != 0 && unshrunk_paper_h != 0);
+}
+
+
+#if EXTRA_APP_DEFAULTS
+
+/*
+ * Information on how to search for miscellaneous text files.
+ */
+
+#include "filf-app.h" /* application-related defs, etc. */
+#include "filefind.h"
+
+static _Xconst char no_f_str_text[] = "/%f";
+
+static struct findrec search_text = {
+ /* path1 */ NULL,
+#if CFGFILE
+ /* envptr */ NULL,
+#endif
+ /* path2 */ ".:%S",
+ /* type */ "miscellaneous text",
+ /* fF_etc */ "fF",
+ /* x_var_char */ 'f',
+ /* n_var_opts */ 2,
+ /* no_f_str */ no_f_str_text,
+ /* no_f_str_end */ no_f_str_text + sizeof(no_f_str_text) - 1,
+ /* abs_str */ "%f",
+#if USE_GF
+ /* no_f_str_flags */ F_FILE_USED,
+ /* abs_str_flags */ F_FILE_USED,
+ /* pk_opt_char */ 'f',
+ /* pk_gf_addr */ NULL,
+#endif
+ /* pct_s_str */ ":xdvi:web2c",
+ {
+ /* v.stephead */ NULL,
+ /* v.pct_s_head */ NULL,
+ /* v.pct_s_count */ 0,
+ /* v.pct_s_atom */ NULL,
+ /* v.rootp */ NULL,
+ }
+};
+
+#endif /* EXTRA_APP_DEFAULTS */
+
+
+#if TOOLKIT
+
+struct modifierinf {
+ int len;
+ _Xconst char *name;
+ Modifiers mask;
+ KeySym keysym;
+};
+
+/* Allowed modifiers, sorted by length and then lexicographically. */
+
+static struct modifierinf modifiers[] = {
+ {1, "a", 0, XK_Alt_L},
+ {1, "c", ControlMask, 0},
+ {1, "h", 0, XK_Hyper_L},
+ {1, "l", LockMask, 0},
+ {1, "m", 0, XK_Meta_L},
+ {1, "s", ShiftMask, 0},
+ {2, "su", 0, XK_Super_L},
+ {3, "Alt", 0, XK_Alt_L},
+ {4, "Ctrl", ControlMask, 0},
+ {4, "Lock", LockMask, 0},
+ {4, "Meta", 0, XK_Meta_L},
+ {4, "Mod1", Mod1Mask, 0},
+ {4, "Mod2", Mod2Mask, 0},
+ {4, "Mod3", Mod3Mask, 0},
+ {4, "Mod4", Mod4Mask, 0},
+ {4, "Mod5", Mod5Mask, 0},
+ {5, "Hyper", 0, XK_Hyper_L},
+ {5, "Shift", ShiftMask, 0},
+ {5, "Super", 0, XK_Super_L},
+ {7, "Button1", Button1Mask, 0},
+ {7, "Button2", Button2Mask, 0},
+ {7, "Button3", Button3Mask, 0},
+ {7, "Button4", Button4Mask, 0},
+ {7, "Button5", Button5Mask, 0},
+};
+
+#define MODSCTRLINDEX 1 /* index of "c" in the above array */
+#define MODSMETAINDEX 4 /* index of "m" */
+
+
+static Bool
+compile_modifiers(pp, wactp)
+ _Xconst char **pp;
+ struct wheel_acts *wactp;
+{
+ _Xconst char *p = *pp;
+ _Xconst char *p1;
+ Bool exclusive = False;
+ LateBindingsPtr latep = NULL;
+ int nlate;
+
+ while (*p == ' ' || *p == '\t') ++p;
+
+ p1 = p;
+ while ((*p1 | ('a' ^ 'A')) >= 'a' && (*p1 | ('a' ^ 'A')) <= 'z')
+ ++p1;
+
+ if (p1 - p == 3 && memcmp(p, "Any", 3) == 0) {
+ wactp->mask = wactp->value = 0;
+ p = p1;
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p != '<')
+ return False;
+ }
+ else if (p1 - p == 4 && memcmp(p, "None", 4) == 0) {
+ wactp->mask = ~0;
+ wactp->value = 0;
+ p = p1;
+ while (*p == ' ' || *p == '\t') ++p;
+ if (*p != '<')
+ return False;
+ }
+ else {
+ if (*p == '!') {
+ exclusive = True;
+ do {
+ ++p;
+ } while (*p == ' ' || *p == '\t');
+ }
+
+ for (;;) {
+ Bool negated = False;
+ struct modifierinf *mp;
+
+ if (*p == '<')
+ break;
+
+ if (*p == '~') {
+ negated = True;
+ ++p;
+ }
+
+ if (*p == '^') {
+ mp = &modifiers[MODSCTRLINDEX];
+ ++p;
+ }
+ else if (*p == '$') {
+ mp = &modifiers[MODSMETAINDEX];
+ ++p;
+ }
+ else {
+ int min, max;
+
+ p1 = p;
+ while (((*p | ('a' ^ 'A')) >= 'a'
+ && (*p | ('a' ^ 'A')) <= 'z')
+ || (*p >= '0' && *p <= '9'))
+ ++p;
+
+ /* do binary search */
+ min = -1;
+ max = XtNumber(modifiers);
+ for (;;) {
+ int i, diff;
+
+ i = (min + max) / 2;
+ if (i == min)
+ return False; /* if not found */
+ mp = &modifiers[i];
+
+ diff = (p - p1) - mp->len;
+ if (diff == 0)
+ diff = memcmp(p1, mp->name, p - p1);
+
+ if (diff == 0)
+ break;
+ if (diff > 0) min = i;
+ else max = i;
+ }
+ }
+ if (mp->mask) {
+ wactp->mask |= mp->mask;
+ if (!negated) wactp->value |= mp->mask;
+ }
+ else {
+ LateBindingsPtr lp1;
+
+ if (latep == NULL) {
+ nlate = 3;
+ latep = xmalloc(3 * sizeof(LateBindings));
+ latep->ref_count = 1;
+ }
+ else {
+ nlate += 2;
+ latep = xrealloc(latep, nlate * sizeof(LateBindings));
+ }
+ lp1 = &latep[nlate - 3];
+ lp1->knot = lp1[1].knot = negated;
+ lp1->pair = True;
+ lp1->keysym = mp->keysym;
+ ++lp1;
+ lp1->pair = False;
+ lp1->ref_count = 0;
+ lp1->keysym = mp->keysym + 1;
+ ++lp1;
+ lp1->knot = lp1->pair = False;
+ lp1->ref_count = 0;
+ lp1->keysym = 0;
+ }
+
+ while (*p == ' ' || *p == '\t') ++p;
+ }
+ }
+
+ wactp->late_bindings = latep;
+ *pp = p;
+
+ return True;
+}
+
+static Bool
+compile_evtype(pp, buttonp)
+ _Xconst char **pp;
+ unsigned int *buttonp;
+{
+ _Xconst char *p = *pp;
+ _Xconst char *p0;
+
+ ++p; /* already assumed to be '<' */
+ while (*p == ' ' || *p == '\t') ++p;
+
+ p0 = p;
+ while (((*p | ('a' ^ 'A')) >= 'a' && (*p | ('a' ^ 'A')) <= 'z')
+ && p - p0 < 3)
+ ++p;
+
+ if (p - p0 != 3 || memcmp(p0, "Btn", 3) != 0)
+ return False;
+
+ if (*p >= '1' && *p <= '9') {
+ unsigned int n = *p - '0';
+
+ while (*++p >= '0' && *p <= '9')
+ n = n * 10 + (*p - '0');
+
+ *buttonp = n;
+ }
+
+ p0 = p;
+ while (((*p | ('a' ^ 'A')) >= 'a' && (*p | ('a' ^ 'A')) <= 'z'))
+ ++p;
+
+ if (p - p0 != 4 || memcmp(p0, "Down", 4) != 0)
+ return False;
+
+ while (*p == ' ' || *p == '\t') ++p;
+
+ if (*p++ != '>')
+ return False;
+
+ while (*p == ' ' || *p == '\t') ++p;
+
+ if (*p++ != ':')
+ return False;
+
+ *pp = p;
+
+ return True;
+}
+
+static void
+compile_wheel_actions()
+{
+ struct wheel_acts **wactpp;
+ struct wheel_acts *wactp;
+ _Xconst char *p = resource.wheel_translations;
+ _Xconst char *p_end = p + strlen(p);
+ struct wheel_acts wact;
+
+ wactpp = &wheel_actions;
+
+ for (;;) {
+ while (*p == ' ' || *p == '\t') ++p;
+
+ if (*p == '\n') continue;
+ if (*p == '\0') break;
+
+ wact.mask = wact.value = 0;
+ wact.button = 0;
+
+ if (!compile_modifiers(&p, &wact)
+ || !compile_evtype(&p, &wact.button))
+ fprintf(stderr, "%s: syntax error in wheel translations\n",
+ prog);
+ else if (compile_action(p, &wact.action) || wact.action != NULL) {
+ wactp = xmalloc(sizeof(struct wheel_acts));
+ *wactp = wact;
+
+ *wactpp = wactp;
+ wactpp = &wactp->next;
+ }
+
+ p = memchr(p, '\n', p_end - p);
+ if (p == NULL) break;
+ ++p;
+ }
+
+ *wactpp = NULL;
+}
+
+#endif /* TOOLKIT */
+
+
+/*
+ * main program
+ */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+
+#ifndef TOOLKIT
+ XSizeHints size_hints;
+ XWMHints wmhints;
+ int flag;
+ int x_thick = 0;
+ int y_thick = 0;
+#endif /* TOOLKIT */
+#ifdef MOTIF
+ Widget menubar;
+ Widget scale_menu;
+#endif
+ Dimension screen_w, screen_h;
+ int i;
+
+ /*
+ * Step 1: Process command-line options and resources.
+ */
+
+#ifndef VMS
+ prog = rindex(*argv, '/');
+#else
+ prog = rindex(*argv, ']');
+#endif
+ if (prog != NULL) ++prog; else prog = *argv;
+
+#ifdef VMS
+ if (index(prog, '.') != NULL) *index(prog, '.') = '\0';
+#endif
+
+#if SELFAUTO
+ argv0 = argv[0];
+#endif
+
+#if TOOLKIT
+
+ top_level = XtInitialize(prog, "XDvi", options, XtNumber(options),
+ &argc, argv);
+ XtAddActions(Actions, num_actions);
+
+ while (--argc > 0) {
+ char *current_arg = *++argv;
+
+ if (*current_arg == '+')
+ if (curr_page != NULL)
+ usage("More than one page-number argument given.");
+ else curr_page = current_arg + 1;
+ else if (dvi_name != NULL)
+ usage("More than one dvi file name given, \
+or invalid argument:\n\t\"%s\", \"%s\".",
+ dvi_name, current_arg);
+ else dvi_name = current_arg;
+ }
+
+ DISP = XtDisplay(top_level);
+ SCRN = XtScreen(top_level);
+
+#if GREY
+ XtSetTypeConverter(XtRString, XtRBool3, XdviCvtStringToBool3,
+ NULL, 0, XtCacheNone, NULL);
+#endif
+
+#if XAW
+ accels_cr = XtParseAcceleratorTable(
+ "<Key>Return:set()notify()unset()");
+ accels_cr_click = XtParseAcceleratorTable(
+ "<Key>Return:set()notify()unset()\n\
+<Btn1Down>:set()\n\
+<Btn1Up>:notify()unset()");
+#endif
+
+#if EXTRA_APP_DEFAULTS
+ /* get resource.progname and resource.debug_arg */
+ XtGetApplicationResources(top_level, (XtPointer) &resource,
+ pre_app_resources, XtNumber(pre_app_resources), (ArgList) NULL, 0);
+
+ if (resource.progname != NULL)
+ prog = resource.progname;
+ if (resource.debug_arg != NULL)
+ debug = isdigit(*resource.debug_arg) ? atoi(resource.debug_arg)
+ : DBG_ALL;
+
+ readconfig();
+
+ search_text.path1 = getenv("XDVIINPUTS");
+ search_text.envptr = ffgetenv("XDVIINPUTS");
+ /* clear it if it's a getenv() placeholder */
+ if (search_text.envptr != NULL && search_text.envptr->value == NULL)
+ search_text.envptr = NULL;
+
+ {
+ FILE *f;
+ _Xconst char *path;
+ XrmDatabase db;
+
+ f = filefind("XDvi", &search_text, &path);
+ if (f != NULL) {
+ fclose(f); /* too early to worry about n_files_left */
+ db = XtScreenDatabase(SCRN);
+ (void) XrmCombineFileDatabase(path, &db, False);
+ free((char *) path);
+ }
+ }
+#endif /* EXTRA_APP_DEFAULTS */
+
+ {
+ XrmDatabase db = XtScreenDatabase(SCRN);
+
+ /* It's easier to do this than track creations and deletions of the
+ scrollbars. */
+ XrmPutStringResource(&db,
+ "XDvi.file.form.vport.vertical.translations",
+ "#override<Btn4Down>:file-scroll(-w)\n<Btn5Down>:file-scroll(w)");
+ XrmPutStringResource(&db,
+ "XDvi.file.form.vport.horizontal.translations",
+ "#override<Btn4Down>:file-scroll(-w)\n<Btn5Down>:file-scroll(w)");
+ }
+
+ XtGetApplicationResources(top_level, (XtPointer) &resource,
+ application_resources, XtNumber(application_resources),
+ (ArgList) NULL, 0);
+ shrink_factor = resource.shrinkfactor;
+
+#if CFGFILE && !EXTRA_APP_DEFAULTS
+ if (resource.progname != NULL)
+ prog = resource.progname;
+#endif
+
+#else /* not TOOLKIT */
+
+ parse_options(argc, argv);
+
+#endif /* not TOOLKIT */
+
+ if (resource.version_flag) {
+ Printf("xdvi version %s\n", VERSION);
+ exit(0);
+ }
+
+#if !EXTRA_APP_DEFAULTS
+ if (resource.debug_arg != NULL)
+ debug = isdigit(*resource.debug_arg) ? atoi(resource.debug_arg)
+ : DBG_ALL;
+#endif
+
+ /* Check early for whether to pass off to a different xdvi process
+ * (-sourceposition argument for reverse source special lookup). */
+
+#if XlibSpecificationRelease >= 6
+ if (!XInternAtoms(DISP, atom_names, XtNumber(atom_names), False, atoms))
+#else
+ if ((atoms[0] = XInternAtom(DISP, atom_names[0], False)) == None
+ || (atoms[1] = XInternAtom(DISP, atom_names[1], False)) == None
+ || (atoms[2] = XInternAtom(DISP, atom_names[2], False)) == None
+# if TOOLKIT
+ || (atoms[3] = XInternAtom(DISP, atom_names[3], False)) == None
+# endif
+# if XAW
+ || (atoms[4] = XInternAtom(DISP, atom_names[4], False)) == None
+# endif
+ )
+#endif
+ oops("XInternAtoms failed.");
+
+ if (debug & DBG_CLIENT) {
+ for (i = 0; i < XtNumber(atom_names); ++i)
+ printf("Atom(%s) = %lu\n", atom_names[i], atoms[i]);
+ }
+
+#if GREY
+ our_depth = DefaultDepthOfScreen(SCRN);
+ our_visual = DefaultVisualOfScreen(SCRN);
+ our_colormap = DefaultColormapOfScreen(SCRN);
+
+ if (resource.install != False && our_visual->class == PseudoColor) {
+ /* look for a TrueColor visual with more bits */
+ XVisualInfo template;
+ XVisualInfo *list;
+ int nitems_return;
+
+ template.screen = XScreenNumberOfScreen(SCRN);
+ template.class = TrueColor;
+ list = XGetVisualInfo(DISP, VisualScreenMask | VisualClassMask,
+ &template, &nitems_return);
+ if (list != NULL) {
+ XVisualInfo *list1;
+ XVisualInfo *best = NULL;
+
+ for (list1 = list; list1 < list + nitems_return; ++list1)
+ if (list1->depth > our_depth
+# if PS_GS
+ /* Not all depths are supported by ghostscript; see
+ * xdev->vinfo->depth in gdevxcmp.c (ghostscript-6.51).
+ * SGI supports additional depths of 12 and 30. */
+ && (list1->depth == 1 || list1->depth == 2
+ || list1->depth == 4 || list1->depth == 8
+ || list1->depth == 15 || list1->depth == 16
+ || list1->depth == 24 || list1->depth == 32)
+# endif
+ && (best == NULL || list1->depth > best->depth))
+ best = list1;
+ if (best != NULL) {
+ our_depth = best->depth;
+ our_visual = best->visual;
+ our_colormap = XCreateColormap(DISP,
+ RootWindowOfScreen(SCRN), our_visual, AllocNone);
+ XInstallColormap(DISP, our_colormap);
+# if TOOLKIT
+ temp_args1[0].value = (XtArgVal) our_depth;
+ temp_args1[1].value = (XtArgVal) our_visual;
+ temp_args1[2].value = (XtArgVal) our_colormap;
+ XtSetValues(top_level, temp_args1, XtNumber(temp_args1));
+ XtSetTypeConverter(XtRString, XtRPixel,
+ XdviCvtStringToPixel,
+ (XtConvertArgList) colorConvertArgs, 2,
+ XtCacheByDisplay, NULL);
+ {
+ /* This is needed so that popup windows have the right
+ visual and colormap. It is unnecessary for newer
+ versions of Motif (Motif 2.1.0, Solaris 9) but
+ needed for older versions (Motif 1.2.5, Solaris 2.6).
+ It is also needed for all versions of Xaw. */
+
+ XrmDatabase db = XtScreenDatabase(SCRN);
+ XrmValue val;
+
+ val.size = sizeof our_visual;
+ val.addr = (XtPointer) &our_visual;
+ XrmPutResource(&db, "XDvi*visual", XtRVisual, &val);
+
+ val.size = sizeof our_colormap;
+ val.addr = (XtPointer) &our_colormap;
+ XrmPutResource(&db, "XDvi*colormap", XtRColormap, &val);
+ }
+# else
+ /* Can't use {Black,White}PixelOfScreen() any more */
+ if (!resource.fore_color)
+ resource.fore_color =
+ (resource.reverse ? "white" : "black");
+ if (!resource.back_color)
+ resource.back_color =
+ (resource.reverse ? "black" : "white");
+# endif
+ }
+ XFree(list);
+ }
+ }
+
+ if (resource.install == True && our_visual->class == PseudoColor) {
+ XColor tmp_color;
+
+ /* This next bit makes sure that the standard black and white pixels
+ are allocated in the new colormap. */
+
+ tmp_color.pixel = BlackPixelOfScreen(SCRN);
+ XQueryColor(DISP, our_colormap, &tmp_color);
+ XAllocColor(DISP, our_colormap, &tmp_color);
+
+ tmp_color.pixel = WhitePixelOfScreen(SCRN);
+ XQueryColor(DISP, our_colormap, &tmp_color);
+ XAllocColor(DISP, our_colormap, &tmp_color);
+
+ our_colormap = XCopyColormapAndFree(DISP, our_colormap);
+# if TOOLKIT
+ temp_args1a[0].value = (XtArgVal) our_colormap;
+ XtSetValues(top_level, temp_args1a, 1);
+# endif
+ }
+
+#endif /* GREY */
+
+ enable_intr();
+
+ if (dvi_name == NULL) {
+#if TOOLKIT
+ postpone_popups = False;
+ Act_open_dvi_file(NULL, NULL, NULL, 0);
+ (void) read_events(EV_GE_NEWDOC);
+ ev_flags &= ~EV_NEWDOC;
+ postpone_popups = True;
+#else
+ usage("You must give a dvi file name.");
+#endif
+ }
+ else {
+ char *new_name;
+ size_t n;
+
+ n = strlen(dvi_name);
+
+ /*
+ * Try foo.dvi before foo, in case there's an executable foo with
+ * documentation foo.tex. Unless it already ends with ".dvi".
+ */
+
+ if (n < 4 || memcmp(dvi_name + n - 4, ".dvi", 4) != 0) {
+ new_name = xmalloc(n + 5);
+ memcpy(new_name, dvi_name, n);
+ memcpy(new_name + n, ".dvi", 5);
+ if (open_dvi_file(new_name)) /* if found */
+ dvi_name = new_name;
+ else
+ free(new_name);
+ }
+
+ /* Then try `foo', in case the user likes DVI files without `.dvi'
+ (or if `foo' already included .dvi). */
+
+ if (dvi_file == NULL) {
+ if (!open_dvi_file(dvi_name)) {
+ perror(dvi_name);
+ return 1;
+ }
+ dvi_name = xstrdup(dvi_name);
+ }
+ }
+
+ if (resource.src_pos != NULL) {
+ if (src_client_check()) {
+ XFlush(DISP); /* necessary to get the property set */
+ return 0;
+ }
+ else if (resource.src_fork) {
+ /*
+ * No suitable xdvi found, so we start one by
+ * self-backgrounding.
+ */
+ Fflush(stdout); /* these avoid double buffering */
+ Fflush(stderr);
+ XFlush(DISP);
+ if (fork()) /* if initial process (do NOT use vfork()!) */
+ return 0;
+ /* Need to adjust for changed process ID */
+ prep_fd(ConnectionNumber(DISP), False);
+ }
+ }
+
+ /* Needed for source specials and for calling ghostscript */
+ xputenv("DISPLAY", XDisplayString(DISP));
+
+ if (resource.mfmode != NULL) {
+ char *p;
+
+ p = rindex(resource.mfmode, ':');
+ if (p != NULL) {
+ unsigned int len;
+ char *p1;
+
+ ++p;
+ len = p - resource.mfmode;
+ p1 = xmalloc(len);
+ bcopy(resource.mfmode, p1, len - 1);
+ p1[len - 1] = '\0';
+ resource.mfmode = p1;
+ pixels_per_inch = atoi(p);
+ }
+ }
+ if (shrink_factor < 0)
+ usage("Invalid shrink factor: %d.", shrink_factor);
+ if (density <= 0)
+ usage("Invalid shrink density: %d.", density);
+ if (pixels_per_inch <= 0)
+ usage("Invalid dpi value: %d.", pixels_per_inch);
+
+ if (shrink_factor > 1) {
+ bak_shrink = shrink_factor;
+ mane.shrinkfactor = shrink_factor; /* otherwise it's 1 */
+ }
+ if (resource.sidemargin) home_x = atopix(resource.sidemargin, False);
+ if (resource.topmargin) home_y = atopix(resource.topmargin, False);
+ offset_x = resource.xoffset ? atopix(resource.xoffset, True)
+ : pixels_per_inch;
+ offset_y = resource.yoffset ? atopix(resource.yoffset, True)
+ : pixels_per_inch;
+ if (!set_paper_type()) {
+ _Xconst char **p;
+
+ Fprintf(stderr,
+ "%s: Unrecognized paper type \"%s\". Legal values are:\n ",
+ prog, resource.paper);
+ for (p = paper_types; p < paper_types + XtNumber(paper_types);
+ p += 2)
+ if (*p == NULL) Fputs("\n ", stderr);
+ else Fprintf(stderr, " %s", *p);
+ Fputs("\n\
+ (the names ending in `r' are `rotated' or `landscape' variants),\n\n\
+or: a specification `WIDTHxHEIGHT' followed by a dimension unit\n\
+ (pt, pc, in, bp, cm, mm, dd, cc, or sp).\n\n\
+Either of the above may be preceded by a plus sign (`+'); this causes the\n\
+argument is to override any papersize specials in the dvi file.\n\n", stderr);
+ xdvi_exit(1);
+ }
+ for (i = 0; i < 5; ++i)
+ if (resource.mg_arg[i] != NULL) {
+ char *s;
+
+ mg_size[i].w = mg_size[i].h = atoi(resource.mg_arg[i]);
+ s = index(resource.mg_arg[i], 'x');
+ if (s != NULL) {
+ mg_size[i].h = atoi(s + 1);
+ if (mg_size[i].h <= 0) mg_size[i].w = 0;
+ }
+ }
+#if PS
+ if (resource.safer) {
+ resource.allow_shell = False;
+#ifdef PS_GS
+ resource.gs_safer = True;
+#endif
+ }
+#endif /* PS */
+#ifdef PS_GS
+ {
+ _Xconst char *CGMcgm = "CGMcgm";
+ _Xconst char *cgmp;
+
+ cgmp = index(CGMcgm, resource.gs_palette[0]);
+ if (cgmp == NULL)
+ oops("Invalid value %s for gs palette option",
+ resource.gs_palette);
+ if (cgmp >= CGMcgm + 3) {
+ static char gsp[] = "x";
+
+ gsp[0] = *(cgmp - 3);
+ resource.gs_palette = gsp;
+ }
+ }
+#endif
+
+#if CFGFILE && !EXTRA_APP_DEFAULTS
+ readconfig(); /* read config file(s). */
+#endif
+
+ /*
+ * Step 2: Settle colormap issues. This should be done before
+ * other widgets are created, so that they get the right
+ * pixel values. (The top-level widget won't have the right
+ * values, but I don't think that makes any difference.)
+ */
+
+#if GREY && TOOLKIT
+ XtGetApplicationResources(top_level, (XtPointer) &resource,
+ app_pixel_resources, XtNumber(app_pixel_resources),
+ (ArgList) NULL, 0);
+#endif
+
+#ifndef TOOLKIT
+ fore_Pixel = (resource.fore_color
+ ? string_to_pixel(&resource.fore_color)
+ : (resource.reverse ? WhitePixelOfScreen(SCRN)
+ : BlackPixelOfScreen(SCRN)));
+ back_Pixel = (resource.back_color
+ ? string_to_pixel(&resource.back_color)
+ : (resource.reverse ? BlackPixelOfScreen(SCRN)
+ : WhitePixelOfScreen(SCRN)));
+ brdr_Pixel = (brdr_color ? string_to_pixel(&brdr_color) : fore_Pixel);
+ hl_Pixel = (high_color ? string_to_pixel(&high_color) : fore_Pixel);
+ cr_Pixel = (curs_color ? string_to_pixel(&curs_color) : fore_Pixel);
+#endif /* not TOOLKIT */
+
+ copy = resource.copy;
+
+#if GREY || COLOR
+ fore_color_data.pixel = fore_Pixel;
+ back_color_data.pixel = back_Pixel;
+ XQueryColors(DISP, our_colormap, color_data, 2);
+#endif
+
+#if COLOR
+ fg_initial.r = fore_color_data.red;
+ fg_initial.g = fore_color_data.green;
+ fg_initial.b = fore_color_data.blue;
+ bg_initial.r = back_color_data.red;
+ bg_initial.g = back_color_data.green;
+ bg_initial.b = back_color_data.blue;
+#endif
+
+#if GREY
+ if (our_depth == 1)
+ use_grey = False;
+
+ if (use_grey && our_visual->class != TrueColor) {
+ init_plane_masks();
+ if (!copy) {
+ /* Retain back_color_data.pixel for psgs.c. */
+ XColor tmp_color;
+
+ tmp_color = back_color_data;
+ tmp_color.pixel = back_Pixel;
+ XStoreColor(DISP, our_colormap, &tmp_color);
+ }
+ }
+#endif
+
+ /*
+ * Step 3: Initialize the dvi file and set titles.
+ */
+
+ init_font_open();
+ init_dvi_file();
+ if (curr_page) {
+ current_page = (*curr_page ? atoi(curr_page) : total_pages) - 1;
+ if (current_page < 0 || current_page >= total_pages)
+ usage("Invalid initial page number: %d.", current_page + 1);
+ }
+ if (resource.prescan)
+ prescan();
+ unshrunk_page_w = page_info[current_page].ww;
+ unshrunk_page_h = page_info[current_page].wh;
+ init_page();
+
+ /*
+ * Step 4: Set initial window size.
+ * This needs to be done before colors are assigned because if
+ * -s 0 is specified, then we need to compute the shrink factor
+ * (which in turn affects whether init_pix is called).
+ */
+
+#if TOOLKIT
+
+ /* The following code is lifted from Xterm */
+ if (resource.icon_geometry != NULL) {
+ int junk;
+
+ (void) XGeometry(DISP, XScreenNumberOfScreen(SCRN),
+ resource.icon_geometry, "", 0, 0, 0, 0, 0,
+ (int *) &temp_args2[0].value, (int *) &temp_args2[1].value,
+ &junk, &junk);
+ XtSetValues(top_level, temp_args2, XtNumber(temp_args2));
+ }
+ /* Set icon pixmap */
+ XtGetValues(top_level, &temp_args4, 1);
+ if (icon_pm == (Pixmap) 0) {
+ temp_args4.value = (XtArgVal) (XCreateBitmapFromData(DISP,
+ RootWindowOfScreen(SCRN), (_Xconst char *) xdvi_bits,
+ xdvi_width, xdvi_height));
+ XtSetValues(top_level, &temp_args4, 1);
+ }
+ XtVaSetValues(top_level, XtNinput, True, NULL);
+
+ {
+ XrmDatabase db;
+
+#if XtSpecificationRelease < 5
+
+ db = DISP->db;
+
+ XrmPutStringResource(&db,
+# if BUTTONS
+ "XDvi.form.translations",
+# else
+ "XDvi.vport.translations",
+# endif
+ base_translations);
+
+#else /* XtSpecificationRelease >= 5 */
+
+ db = XtScreenDatabase(SCRN);
+
+ XrmPutStringResource(&db,
+# if XAW
+# if BUTTONS
+ "XDvi.form.baseTranslations",
+# else
+ "XDvi.vport.baseTranslations",
+# endif
+# else /* MOTIF */
+# if BUTTONS
+ "XDvi.form.vport.drawing.baseTranslations",
+# else
+ "XDvi.vport.drawing.baseTranslations",
+# endif
+# endif /* MOTIF */
+ base_translations);
+
+ if (resource.main_translations != NULL)
+ XrmPutStringResource(&db,
+# if XAW
+# if BUTTONS
+ "XDvi.form.translations",
+# else
+ "XDvi.vport.translations",
+# endif
+# else /* MOTIF */
+# if BUTTONS
+ "XDvi.form.vport.drawing.translations",
+# else
+ "XDvi.vport.drawing.translations",
+# endif
+# endif /* MOTIF */
+ resource.main_translations);
+
+#endif /* XtSpecificationRelease */
+
+ /* Notwithstanding the ampersand, XrmPutStringResource() does
+ * not change db (X11R6.4 source). */
+ }
+
+#if BUTTONS
+
+ form_widget = XtCreateManagedWidget("form", FORM_WIDGET_CLASS,
+ top_level, form_args, XtNumber(form_args));
+#define form_or_top form_widget /* for calls later on */
+#define form_or_vport form_widget
+
+#else /* not BUTTONS */
+
+#define form_or_top top_level /* for calls later on */
+#define form_or_vport vport_widget
+
+#endif /* not BUTTONS */
+
+ vport_widget = XtCreateManagedWidget("vport", VPORT_WIDGET_CLASS,
+ form_or_top, vport_args, XtNumber(vport_args));
+
+#ifndef MOTIF
+
+ clip_widget = XtNameToWidget(vport_widget, "clip");
+
+#else /* MOTIF */
+
+ menubar = XmVaCreateSimpleMenuBar(vport_widget, "menubar",
+ XmNdepth, (XtArgVal) our_depth,
+ XmNvisual, (XtArgVal) our_visual,
+ XmNcolormap, (XtArgVal) our_colormap,
+ XmVaCASCADEBUTTON, XmCvtCTToXmString("File"), (KeySym) 0,
+ XmVaCASCADEBUTTON, XmCvtCTToXmString("Navigate"), (KeySym) 0,
+ XmVaCASCADEBUTTON, XmCvtCTToXmString("Scale"), (KeySym) 0,
+ NULL);
+ XmVaCreateSimplePulldownMenu(menubar,
+ "file_pulldown", 0, file_pulldown_callback,
+ XmNtearOffModel, (XtArgVal) XmTEAR_OFF_ENABLED,
+ XmNdepth, (XtArgVal) our_depth,
+ XmNvisual, (XtArgVal) our_visual,
+ XmNcolormap, (XtArgVal) our_colormap,
+ XmVaPUSHBUTTON, XmCvtCTToXmString("Open file"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaPUSHBUTTON, XmCvtCTToXmString("Reload"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaPUSHBUTTON, XmCvtCTToXmString("Print"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaSEPARATOR,
+ XmVaPUSHBUTTON, XmCvtCTToXmString("Quit"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ NULL);
+ XmVaCreateSimplePulldownMenu(menubar,
+ "navigate_pulldown", 1, navigate_pulldown_callback,
+ XmNtearOffModel, (XtArgVal) XmTEAR_OFF_ENABLED,
+ XmVaPUSHBUTTON, (XtArgVal) XmCvtCTToXmString("Page-10"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaPUSHBUTTON, (XtArgVal) XmCvtCTToXmString("Page-5"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaPUSHBUTTON, (XtArgVal) XmCvtCTToXmString("Prev"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaSEPARATOR,
+ XmVaPUSHBUTTON, (XtArgVal) XmCvtCTToXmString("Next"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaPUSHBUTTON, (XtArgVal) XmCvtCTToXmString("Page+5"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaPUSHBUTTON, (XtArgVal) XmCvtCTToXmString("Page+10"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ NULL);
+ scale_menu = XmVaCreateSimplePulldownMenu(menubar,
+ "scale_pulldown", 2, scale_pulldown_callback,
+ XmNradioBehavior, (XtArgVal) True,
+ XmNtearOffModel, (XtArgVal) XmTEAR_OFF_ENABLED,
+ XmVaRADIOBUTTON, (XtArgVal) XmCvtCTToXmString("Shrink1"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaRADIOBUTTON, (XtArgVal) XmCvtCTToXmString("Shrink2"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaRADIOBUTTON, (XtArgVal) XmCvtCTToXmString("Shrink3"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ XmVaRADIOBUTTON, (XtArgVal) XmCvtCTToXmString("Shrink4"),
+ (KeySym) 0, (String) 0, (XmString) 0,
+ NULL);
+ shrink_button[0] = XtNameToWidget(scale_menu, "button_0");
+ shrink_button[1] = XtNameToWidget(scale_menu, "button_1");
+ shrink_button[2] = XtNameToWidget(scale_menu, "button_2");
+ shrink_button[3] = XtNameToWidget(scale_menu, "button_3");
+
+ /* All of the pulldown menus have the same parent. */
+ XtAddCallback(XtParent(scale_menu), XtNpopdownCallback,
+ popdown_callback, (XtPointer) 0);
+
+ x_bar = XtNameToWidget(vport_widget, "HorScrollBar");
+ y_bar = XtNameToWidget(vport_widget, "VertScrollBar");
+
+#endif /* MOTIF */
+
+ draw_args[0].value = (XtArgVal) page_w;
+ draw_args[1].value = (XtArgVal) page_h;
+ draw_widget = XtCreateManagedWidget("drawing", DRAW_WIDGET_CLASS,
+ vport_widget, draw_args, XtNumber(draw_args));
+
+#ifdef MOTIF
+ XtVaSetValues(vport_widget, XmNworkWindow, draw_widget,
+ XmNmenuBar, menubar, NULL);
+ XtManageChild(menubar);
+ XtVaGetValues(vport_widget, XmNclipWindow, &clip_widget, NULL);
+#endif /* MOTIF */
+
+#if XtSpecificationRelease < 5
+ if (resource.main_translations != NULL) {
+ XtTranslations xlats;
+
+ xlats = XtParseTranslationTable(resource.main_translations);
+
+ for (;;) { /* not really a loop */
+ _Xconst char *p1;
+ _Xconst char *p2;
+
+ p1 = resource.main_translations;
+ while (*p1 == ' ' || *p1 == '\t') ++p1;
+ if (*p1 == '#') {
+ ++p1;
+ p2 = p1;
+ while (*p2 >= 'a' && *p2 <= 'z') ++p2;
+ if (p2 - p1 == 7 && memcmp(p1, "augment", 7) == 0) {
+ XtAugmentTranslations(form_or_vport, xlats);
+ break;
+ }
+ if (p2 - p1 == 8 && memcmp(p1, "override", 8) == 0) {
+ XtOverrideTranslations(form_or_vport, xlats);
+ break;
+ }
+ }
+ XtVaSetValues(form_or_vport, XtNtranslations, xlats, NULL);
+ break;
+ }
+ }
+#endif /* XtSpecificationRelease */
+
+ XtOverrideTranslations(
+#if !MOTIF
+ form_or_vport,
+#else
+ draw_widget,
+#endif
+ XtParseTranslationTable("\
+\"0\":digit(0)\n\
+\"1\":digit(1)\n\
+\"2\":digit(2)\n\
+\"3\":digit(3)\n\
+\"4\":digit(4)\n\
+\"5\":digit(5)\n\
+\"6\":digit(6)\n\
+\"7\":digit(7)\n\
+\"8\":digit(8)\n\
+\"9\":digit(9)\n\
+\"-\":minus()\n\
+<Motion>:motion()\n\
+<BtnUp>:release()"));
+
+ if (resource.wheel_unit != 0 && resource.wheel_translations != NULL) {
+#if XAW
+ XtAugmentTranslations(form_or_vport,
+ XtParseTranslationTable("<BtnDown>:wheel-actions()"));
+#else /* MOTIF */
+#if !BUTTONS
+ XtTranslations wheel_trans_table;
+#endif
+
+ wheel_trans_table
+ = XtParseTranslationTable("<BtnDown>:wheel-actions()");
+ XtAugmentTranslations(draw_widget, wheel_trans_table);
+#endif /* MOTIF */
+
+ compile_wheel_actions();
+ }
+
+ /* set background colors of the drawing and clip widgets */
+ {
+ static Arg back_args = {XtNbackground, (XtArgVal) 0};
+
+ back_args.value = back_Pixel;
+ XtSetValues(draw_widget, &back_args, 1);
+ XtSetValues(clip_widget, &back_args, 1);
+ }
+
+ /* determine default window size */
+#if BUTTONS
+ if (!resource.expert)
+ create_buttons();
+#else
+#define xtra_wid 0
+#endif
+ {
+ XtWidgetGeometry constraints;
+ XtWidgetGeometry reply;
+
+ XtGetValues(top_level, &temp_args3, 1); /* get border width */
+ screen_w = WidthOfScreen(SCRN) - 2 * bwidth - xtra_wid;
+ screen_h = HeightOfScreen(SCRN) - 2 * bwidth;
+ for (;;) { /* actually, at most two passes */
+ constraints.request_mode = reply.request_mode = 0;
+ constraints.width = page_w;
+ if (page_w > screen_w) {
+ constraints.request_mode = CWWidth;
+ constraints.width = screen_w;
+ }
+ constraints.height = page_h;
+ if (page_h > screen_h) {
+ constraints.request_mode |= CWHeight;
+ constraints.height = screen_h;
+ }
+ if (constraints.request_mode != 0
+ && constraints.request_mode != (CWWidth | CWHeight))
+ (void) XtQueryGeometry(vport_widget, &constraints, &reply);
+ if (!(reply.request_mode & CWWidth))
+ reply.width = constraints.width;
+ if (reply.width >= screen_w)
+ reply.width = screen_w;
+ if (!(reply.request_mode & CWHeight))
+ reply.height = constraints.height;
+ if (reply.height >= screen_h)
+ reply.height = screen_h;
+
+ /* now reply.{width,height} contain max. usable window size */
+
+ if (shrink_factor != 0)
+ break;
+
+ shrink_factor = ROUNDUP(unshrunk_page_w, reply.width - 2);
+ i = ROUNDUP(unshrunk_page_h, reply.height - 2);
+ if (i >= shrink_factor) shrink_factor = i;
+ if (shrink_factor > 1) bak_shrink = shrink_factor;
+ mane.shrinkfactor = shrink_factor;
+ init_page();
+ set_wh_args[0].value = (XtArgVal) page_w;
+ set_wh_args[1].value = (XtArgVal) page_h;
+ XtSetValues(draw_widget, set_wh_args, XtNumber(set_wh_args));
+ }
+ set_wh_args[0].value = (XtArgVal) (reply.width + xtra_wid);
+ set_wh_args[1].value = (XtArgVal) reply.height;
+ XtSetValues(top_level, set_wh_args, XtNumber(set_wh_args));
+#ifdef BUTTONS
+ set_wh_args[0].value -= xtra_wid;
+ XtSetValues(vport_widget, set_wh_args, XtNumber(set_wh_args));
+#endif /* BUTTONS */
+ }
+#ifdef MOTIF
+ set_shrink_factor(mane.shrinkfactor);
+#endif
+
+#else /* not TOOLKIT */
+
+ screen_w = WidthOfScreen(SCRN) - 2*bwidth;
+ screen_h = HeightOfScreen(SCRN) - 2*bwidth;
+
+ size_hints.flags = PMinSize;
+ size_hints.min_width = size_hints.min_height = 50;
+ size_hints.x = size_hints.y = 0;
+
+ /* compute largest possible window */
+ flag = 0;
+ if (geometry != NULL) {
+ flag = XParseGeometry(geometry, &size_hints.x, &size_hints.y,
+ &window_w, &window_h);
+ if (flag & (XValue | YValue))
+ size_hints.flags |= USPosition;
+ if (flag & (WidthValue | HeightValue))
+ size_hints.flags |= USSize;
+ }
+ if (!(flag & WidthValue)) window_w = screen_w;
+ if (!(flag & HeightValue)) window_h = screen_h;
+
+ if (shrink_factor == 0) {
+ /* compute best shrink factor based on window_w and window_h */
+ shrink_factor = ROUNDUP(unshrunk_page_w, window_w - 2);
+ i = ROUNDUP(unshrunk_page_h, window_h - 2);
+ if (i >= shrink_factor) shrink_factor = i;
+ if (shrink_factor > 1) bak_shrink = shrink_factor;
+ mane.shrinkfactor = shrink_factor;
+ init_page();
+ }
+
+ if (window_w < page_w) x_thick = BAR_THICK;
+ if (window_h < page_h + x_thick) y_thick = BAR_THICK;
+ if (!(flag & WidthValue)) {
+ window_w = page_w + y_thick;
+ if (window_w > screen_w) {
+ x_thick = BAR_THICK;
+ window_w = screen_w;
+ }
+ size_hints.flags |= PSize;
+ }
+ if (!(flag & HeightValue)) {
+ window_h = page_h + x_thick;
+ if (window_h > screen_h) window_h = screen_h;
+ size_hints.flags |= PSize;
+ }
+
+ if (flag & XNegative) size_hints.x += screen_w - window_w;
+ if (flag & YNegative) size_hints.y += screen_h - window_h;
+
+#endif /* not TOOLKIT */
+
+ /*
+ * Step 5: Realize the widgets (or windows).
+ */
+
+#if TOOLKIT
+
+#if BUTTONS && !MOTIF
+ if (!resource.expert)
+ set_button_panel_height(set_wh_args[1].value);
+#endif
+#if MOTIF
+ XtSetSensitive(draw_widget, TRUE);
+#endif
+ XtAddEventHandler(top_level, PropertyChangeMask, False,
+ handle_property_change, (XtPointer) NULL);
+ XtAddEventHandler(vport_widget, StructureNotifyMask, False,
+ handle_resize, (XtPointer) NULL);
+ XtAddEventHandler(draw_widget, ExposureMask, False, handle_expose,
+ (XtPointer) &mane);
+ XtRealizeWidget(top_level);
+
+#if XAW
+ XSetWMProtocols(DISP, XtWindow(top_level), &XA_WM_DELETE_WINDOW, 1);
+ XtAddEventHandler(top_level, NoEventMask, True, handle_messages, NULL);
+# if BUTTONS
+ if (!resource.expert)
+ XDefineCursor(DISP, XtWindow(panel_widget), panel_cursor);
+# endif
+#else /* MOTIF */
+ XtVaSetValues(top_level, XmNdeleteResponse, XmDO_NOTHING, NULL);
+ XmAddWMProtocolCallback(top_level, XA_WM_DELETE_WINDOW,
+ handle_wm_delete, NULL);
+ XmProcessTraversal(draw_widget, XmTRAVERSE_CURRENT);
+#endif
+
+ currwin.win = mane.win = XtWindow(draw_widget);
+
+ postpone_popups = False;
+ if (n_init_popups != 0) {
+ for (i = 0; i < n_init_popups; ++i)
+ do_popup(init_popups[i]);
+ free(init_popups);
+ init_popups = NULL;
+ n_init_popups = 0;
+ }
+
+ {
+ XWindowAttributes attrs;
+
+ (void) XGetWindowAttributes(DISP, mane.win, &attrs);
+ backing_store = attrs.backing_store;
+ }
+
+#else /* not TOOLKIT */
+
+ size_hints.width = window_w;
+ size_hints.height = window_h;
+#ifndef GREY
+ top_level = XCreateSimpleWindow(DISP, RootWindowOfScreen(SCRN),
+ size_hints.x, size_hints.y, window_w, window_h, bwidth,
+ brdr_Pixel, back_Pixel);
+#else
+ {
+ XSetWindowAttributes attr;
+
+ attr.border_pixel = brdr_Pixel;
+ attr.background_pixel = back_Pixel;
+ attr.colormap = our_colormap;
+ top_level = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
+ size_hints.x, size_hints.y, window_w, window_h, bwidth,
+ our_depth, InputOutput, our_visual,
+ CWBorderPixel | CWBackPixel | CWColormap, &attr);
+ }
+#endif
+ { /* See also set_titles() in dvi-init-c. */
+ char *title_name;
+ char *icon_name;
+ size_t baselen;
+ Boolean icon_name_malloced = False;
+
+ icon_name = rindex(dvi_name, '/');
+ if (icon_name != NULL) ++icon_name;
+ else icon_name = dvi_name;
+ baselen = strlen(icon_name);
+ if (baselen > 4 && memcmp(icon_name + baselen - 4, ".dvi", 4) == 0)
+ {
+ /* remove the .dvi */
+ char *p;
+
+ baselen -= 4;
+ p = xmalloc(baselen + 1);
+ memcpy(p, icon_name, baselen);
+ p[baselen] = '\0';
+ icon_name = p;
+ icon_name_malloced = True;
+ }
+
+ title_name = xmalloc(baselen + 8);
+ memcpy(title_name, "Xdvi: ", 7);
+ memcpy(title_name + 7, icon_name, baselen + 1);
+
+ XSetStandardProperties(DISP, top_level, title_name, icon_name,
+ (Pixmap) 0, argv, argc, &size_hints);
+
+ free(title_name);
+ if (icon_name_malloced)
+ free(icon_name);
+ }
+
+ wmhints.flags = InputHint | StateHint | IconPixmapHint;
+ wmhints.input = True; /* window manager must direct input */
+ wmhints.initial_state = iconic ? IconicState : NormalState;
+ wmhints.icon_pixmap = XCreateBitmapFromData(DISP,
+ RootWindowOfScreen(SCRN), (_Xconst char *) xdvi_bits,
+ xdvi_width, xdvi_height);
+ if (resource.icon_geometry != NULL) {
+ int junk;
+
+ wmhints.flags |= IconPositionHint;
+ (void) XGeometry(DISP, DefaultScreen(DISP), resource.icon_geometry,
+ "", 0, 0, 0, 0, 0, &wmhints.icon_x, &wmhints.icon_y,
+ &junk, &junk);
+ }
+ XSetWMHints(DISP, top_level, &wmhints);
+
+ XSelectInput(DISP, top_level,
+ KeyPressMask | StructureNotifyMask | PropertyChangeMask);
+ XMapWindow(DISP, top_level);
+ XFlush(DISP);
+
+ {
+ static KeySym list[2] = {XK_Caps_Lock, XK_Num_Lock};
+
+#define rebindkey(ks, str) XRebindKeysym(DISP, (KeySym) ks, \
+ (KeySym *) NULL, 0, (_Xconst ubyte *) str, 1); \
+ XRebindKeysym(DISP, (KeySym) ks, \
+ list, 1, (_Xconst ubyte *) str, 1); \
+ XRebindKeysym(DISP, (KeySym) ks, \
+ list + 1, 1, (_Xconst ubyte *) str, 1); \
+ XRebindKeysym(DISP, (KeySym) ks, \
+ list, 2, (_Xconst ubyte *) str, 1);
+
+ rebindkey(XK_Home, "^");
+ rebindkey(XK_Left, "l");
+ rebindkey(XK_Up, "u");
+ rebindkey(XK_Right, "r");
+ rebindkey(XK_Down, "d");
+ rebindkey(XK_Prior, "b");
+ rebindkey(XK_Next, "f");
+#ifdef XK_KP_Left
+ rebindkey(XK_KP_Home, "^");
+ rebindkey(XK_KP_Left, "l");
+ rebindkey(XK_KP_Up, "u");
+ rebindkey(XK_KP_Right, "r");
+ rebindkey(XK_KP_Down, "d");
+ rebindkey(XK_KP_Prior, "b");
+ rebindkey(XK_KP_Next, "f");
+ rebindkey(XK_KP_Delete, "\177");
+#endif /* def XK_KP_Left */
+ }
+#undef rebindkey
+
+#endif /* not TOOLKIT */
+
+ image = XCreateImage(DISP, our_visual, 1, XYBitmap, 0,
+ (char *) NULL, 0, 0, BMBITS, 0);
+ image->bitmap_unit = BMBITS;
+#ifdef WORDS_BIGENDIAN
+ image->bitmap_bit_order = MSBFirst;
+#else
+ image->bitmap_bit_order = LSBFirst;
+#endif
+ {
+ short endian = MSBFirst << 8 | LSBFirst;
+ image->byte_order = *((char *) &endian);
+ }
+
+ /* Store window id for use by src_client_check(). */
+
+ {
+ long data = XtWindow(top_level);
+
+ XChangeProperty(DISP, DefaultRootWindow(DISP),
+ ATOM_XDVI_WINDOWS, ATOM_XDVI_WINDOWS, 32, PropModeAppend,
+ (unsigned char *) &data, 1);
+ }
+ set_dvi_property();
+
+ /*
+ * Step 6: Assign colors and GCs.
+ * Because of the latter, this has to go after Step 5.
+ * In color mode, color changes affect foreGC, foreGC2,
+ * and ruleGC, but not copyGC or highGC.
+ */
+
+#if GREY
+ if (resource._gamma == 0.0)
+ resource._gamma = 1.0;
+#endif
+
+#define MakeGC(fcn, fg, bg) (values.function = fcn, \
+ values.foreground=fg, values.background=bg, \
+ XCreateGC(DISP, XtWindow(top_level), \
+ GCFunction | GCForeground | GCBackground, &values))
+
+#if !COLOR
+
+#if GREY
+ if (use_grey)
+ init_pix();
+ else
+#endif
+ {
+ XGCValues values;
+ Pixel set_bits = (Pixel) (fore_Pixel & ~back_Pixel);
+ Pixel clr_bits = (Pixel) (back_Pixel & ~fore_Pixel);
+ Boolean copy_tmp = resource.copy;
+
+ copyGC = MakeGC(GXcopy, fore_Pixel, back_Pixel);
+ if (copy_tmp || (set_bits && clr_bits)) {
+ ruleGC = copyGC;
+ if (!resource.thorough) copy_tmp = True;
+ }
+ if (copy_tmp) {
+ foreGC = ruleGC;
+ if (!resource.copy)
+ WARN(XmDIALOG_WARNING,
+ "Overstrike characters may be incorrect");
+ }
+ else {
+ if (set_bits) foreGC = MakeGC(GXor, set_bits, 0);
+ if (clr_bits || !set_bits)
+ *(foreGC ? &foreGC2 : &foreGC) =
+ MakeGC(GXandInverted, clr_bits, 0);
+ if (!ruleGC) ruleGC = foreGC;
+ }
+ }
+
+#endif /* !COLOR */
+
+ {
+ XGCValues values;
+
+#if COLOR
+ /* Not affected by color changes. */
+ copyGC = MakeGC(GXcopy, fore_Pixel, back_Pixel);
+#endif
+ highGC = MakeGC(GXcopy, hl_Pixel, back_Pixel);
+ }
+
+#if XAW
+ /*
+ * There's a bug in the Xaw toolkit, in which it uses the
+ * DefaultGCOfScreen to do vertical scrolling in the Text widget.
+ * This leads to a BadMatch error if our visual is not the default one.
+ * The following kludge works around this.
+ */
+
+ DefaultGCOfScreen(SCRN) = copyGC;
+#endif
+
+#ifndef VMS
+ ready_cursor = XCreateFontCursor(DISP, XC_cross);
+ redraw_cursor = XCreateFontCursor(DISP, XC_watch);
+#else
+ DECWCursorFont = XLoadFont(DISP, "DECW$CURSOR");
+ XSetFont(DISP, highGC, DECWCursorFont);
+ redraw_cursor = XCreateGlyphCursor(DISP, DECWCursorFont, DECWCursorFont,
+ decw$c_wait_cursor, decw$c_wait_cursor + 1,
+ &resource.fore_color, &resource.back_color);
+ MagnifyPixmap = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ mag_glass_bits, mag_glass_width, mag_glass_height);
+ ready_cursor = XCreatePixmapCursor(DISP, MagnifyPixmap, MagnifyPixmap,
+ &resource.back_color, &resource.fore_color,
+ mag_glass_x_hot, mag_glass_y_hot);
+#endif /* VMS */
+
+ {
+ XColor bg_Color;
+ Pixmap arrow_pixmap, arrow_mask;
+
+ bg_Color.pixel = back_Pixel;
+ XQueryColor(DISP, our_colormap, &bg_Color);
+ cr_Color.pixel = cr_Pixel;
+ XQueryColor(DISP, our_colormap, &cr_Color);
+#if !COLOR
+ XRecolorCursor(DISP, ready_cursor, &cr_Color, &bg_Color);
+ XRecolorCursor(DISP, redraw_cursor, &cr_Color, &bg_Color);
+#endif
+
+ arrow_pixmap = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ (_Xconst char *) drag_vert_bits,
+ drag_vert_width, drag_vert_height);
+ arrow_mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ (_Xconst char *) drag_vert_mask,
+ drag_vert_width, drag_vert_height);
+ drag_cursor[0] = XCreatePixmapCursor(DISP, arrow_pixmap, arrow_mask,
+ &cr_Color, &bg_Color, drag_vert_x_hot, drag_vert_y_hot);
+ XFreePixmap(DISP, arrow_pixmap);
+ XFreePixmap(DISP, arrow_mask);
+
+ arrow_pixmap = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ (_Xconst char *) drag_horiz_bits,
+ drag_horiz_width, drag_horiz_height);
+ arrow_mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ (_Xconst char *) drag_horiz_mask,
+ drag_horiz_width, drag_horiz_height);
+ drag_cursor[1] = XCreatePixmapCursor(DISP, arrow_pixmap, arrow_mask,
+ &cr_Color, &bg_Color, drag_horiz_x_hot, drag_horiz_y_hot);
+ XFreePixmap(DISP, arrow_pixmap);
+ XFreePixmap(DISP, arrow_mask);
+
+ arrow_pixmap = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ (_Xconst char *) drag_omni_bits,
+ drag_omni_width, drag_omni_height);
+ arrow_mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN),
+ (_Xconst char *) drag_omni_mask,
+ drag_omni_width, drag_omni_height);
+ drag_cursor[2] = XCreatePixmapCursor(DISP, arrow_pixmap, arrow_mask,
+ &cr_Color, &bg_Color, drag_omni_x_hot, drag_omni_y_hot);
+ XFreePixmap(DISP, arrow_pixmap);
+ XFreePixmap(DISP, arrow_mask);
+ }
+
+ if (resource.src_pos != NULL) {
+ source_forward_string = resource.src_pos;
+ ev_flags |= EV_SRC;
+ }
+
+ do_pages();
+ /* NOTREACHED */
+}
diff --git a/xdvi.h b/xdvi.h
@@ -0,0 +1,1386 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+NOTE:
+ xdvi is based on prior work, as noted in the modification history
+ in xdvi.c.
+
+\*========================================================================*/
+
+/*
+ * Written by Eric C. Cooper, CMU
+ */
+
+#ifndef XDVI_H
+#define XDVI_H
+
+/********************************
+ * The C environment *
+ *******************************/
+
+#ifdef __hpux
+/* On HP-UX 10.10 B and 20.10, compiling with _XOPEN_SOURCE + ..._EXTENDED
+ * leads to poll() not realizing that a file descriptor is writable in psgs.c.
+ */
+#define _HPUX_SOURCE 1
+#else
+#undef _XOPEN_SOURCE /* needed because of imake */
+#define _XOPEN_SOURCE 600
+#define _XOPEN_SOURCE_EXTENDED 1
+#define __EXTENSIONS__ 1 /* needed to get struct timeval on SunOS 5.5 */
+#define _SVID_SOURCE 1 /* needed to get S_IFLNK in glibc */
+#define _BSD_SOURCE 1 /* needed to get F_SETOWN in glibc-2.1.3 */
+#endif
+
+#include "config.h"
+
+/* Some O/S dependent kludges. */
+#ifdef _AIX
+#define _ALL_SOURCE 1
+#endif
+
+/* If xmkmf is broken and there's a symlink from /usr/include/X11 to the right
+ * place, then there will be no -I... argument on the cc command line for the
+ * X include files. Since gcc version 3 and higher sets __STDC__ to 0 when
+ * including system header files on some platforms, we may end up with
+ * NeedFunctionPrototypes set to 0 when it should be 1. So, let's force the
+ * issue.
+ */
+
+#if __STDC__ && !defined(FUNCPROTO)
+# define FUNCPROTO (-1)
+#endif
+
+#if STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+ /* the following works around the wchar_t problem */
+# include <X11/X.h>
+# if HAVE_X11_XOSDEFS_H
+# include <X11/Xosdefs.h>
+# endif
+# ifdef X_NOT_STDC_ENV
+# undef X_NOT_STDC_ENV
+# undef X_WCHAR
+# include <X11/Xlib.h>
+# define X_NOT_STDC_ENV
+# endif
+#endif
+
+#include <X11/Xlib.h> /* include Xfuncs.h, if available */
+#include <X11/Xutil.h> /* needed for XDestroyImage */
+#include <X11/Xos.h>
+
+#if XlibSpecificationRelease >= 5
+#include <X11/Xfuncs.h>
+#endif
+
+#undef TOOLKIT
+
+#if XAW || MOTIF
+
+#define TOOLKIT 1
+#include <X11/Intrinsic.h>
+#if (defined(VMS) && (XtSpecificationRelease <= 4)) || defined(lint)
+# include <X11/IntrinsicP.h>
+#endif
+#if MOTIF
+# include <Xm/Xm.h>
+# ifndef MOTIF_TIMERS /* see comment in events.c */
+# define MOTIF_TIMERS (XmVERSION >= 2)
+# endif
+#endif
+
+#else /* not TOOLKIT */
+
+#define XtNumber(arr) (sizeof(arr)/sizeof(arr[0]))
+#define XtWindow(win) (win)
+typedef unsigned long Pixel;
+typedef char Boolean;
+typedef unsigned int Dimension;
+#undef BUTTONS
+#undef EXTRA_APP_DEFAULTS
+
+#endif /* not TOOLKIT */
+
+#if EXTRA_APP_DEFAULTS && !SELFAUTO
+#define SELFAUTO 1
+#endif
+
+#if SELFAUTO && !defined(DEFAULT_CONFIG_PATH)
+#define DEFAULT_CONFIG_PATH \
+ ".:$SELFAUTOLOC:$SELFAUTODIR:$SELFAUTOPARENT:$SELFAUTODIR/share/texmf/web2c:$SELFAUTOPARENT/share/texmf/web2c:$SELFAUTODIR/texmf/web2c:$SELFAUTOPARENT/texmf/web2c:$TETEXDIR:$TEXMF/web2c"
+#endif
+
+#undef CFGFILE /* no cheating */
+
+#if defined(DEFAULT_CONFIG_PATH)
+#define CFGFILE 1
+#endif
+
+typedef char Bool3; /* Yes/No/Maybe */
+
+#define True 1
+#define False 0
+#define Maybe 2
+
+#ifdef VMS
+#include <string.h>
+#define index strchr
+#define rindex strrchr
+#define bzero(a, b) (void) memset ((void *) (a), 0, (size_t) (b))
+#define bcopy(a, b, c) (void) memmove ((void *) (b), (void *) (a), (size_t) (c))
+#endif
+
+#include <stdio.h>
+#include <setjmp.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if FREETYPE
+# include <ft2build.h>
+# include FT_FREETYPE_H
+#endif
+
+#ifndef NeedFunctionPrototypes
+#if __STDC__
+#define NeedFunctionPrototypes 1
+#else /* STDC */
+#define NeedFunctionPrototypes 0
+#endif /* STDC */
+#endif /* NeedFunctionPrototypes */
+
+#if NeedFunctionPrototypes
+#define ARGS(x) x
+#else
+#define ARGS(x) ()
+#endif
+
+#ifndef KPATHSEA
+
+/* These macros munge function declarations to make them work in both
+ cases. The P?H macros are used for declarations, the P?C for
+ definitions. See <ansidecl.h> from the GNU C library. P1H(void)
+ also works for definitions of routines which take no args. */
+
+#if NeedFunctionPrototypes /* Don't use __STDC__ here (gcc + SunOS 4) */
+
+#define P1H(p1) (p1)
+#define P2H(p1, p2) (p1, p2)
+
+#define P1C(t1,n1)(t1 n1)
+#define P2C(t1,n1, t2,n2)(t1 n1, t2 n2)
+#define P3C(t1,n1, t2,n2, t3,n3)(t1 n1, t2 n2, t3 n3)
+#define P4C(t1,n1, t2,n2, t3,n3, t4,n4)(t1 n1, t2 n2, t3 n3, t4 n4)
+
+#else /* not NeedFunctionPrototypes */
+
+#define P1H(p1) ()
+#define P2H(p1, p2) ()
+
+#define P1C(t1,n1) (n1) t1 n1;
+#define P2C(t1,n1, t2,n2) (n1,n2) t1 n1; t2 n2;
+#define P3C(t1,n1, t2,n2, t3,n3) (n1,n2,n3) t1 n1; t2 n2; t3 n3;
+#define P4C(t1,n1, t2,n2, t3,n3, t4,n4) (n1,n2,n3,n4) \
+ t1 n1; t2 n2; t3 n3; t4 n4;
+
+#endif /* not NeedFunctionPrototypes */
+
+#endif /* not KPATHSEA */
+
+#ifndef NeedWidePrototypes
+#define NeedWidePrototypes NeedFunctionPrototypes
+#endif
+
+#ifndef NeedVarargsPrototypes
+#define NeedVarargsPrototypes NeedFunctionPrototypes
+#endif
+
+#if NeedVarargsPrototypes
+#define VARGS(x) x
+#else
+#define VARGS(x) ()
+#endif
+
+#ifndef _XFUNCPROTOBEGIN
+#define _XFUNCPROTOBEGIN
+#define _XFUNCPROTOEND
+#endif
+
+#ifndef _Xconst
+#if __STDC__
+#define _Xconst const
+#else /* STDC */
+#define _Xconst
+#endif /* STDC */
+#endif /* _Xconst */
+
+#ifndef VOLATILE
+#if __STDC__ || (defined(__stdc__) && defined(__convex__))
+#define VOLATILE volatile
+#else
+#define VOLATILE /* nothing */
+#endif
+#endif
+
+#ifndef NORETURN
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)
+# define NORETURN __attribute__((__noreturn__))
+# else
+# define NORETURN /* nothing */
+# endif
+#endif
+
+#ifndef UNUSED
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+# define UNUSED __attribute__((__unused__))
+# else
+# define UNUSED /* nothing */
+# endif
+#endif
+
+#ifndef OPEN_MODE
+#ifndef VMS
+#define OPEN_MODE "r"
+#else /* VMS */
+#define OPEN_MODE "r", "ctx=stm"
+#endif /* VMS */
+#endif /* OPEN_MODE */
+
+#ifndef VMS
+#define OPEN_MODE_ARGS _Xconst char *
+#else
+#define OPEN_MODE_ARGS _Xconst char *, _Xconst char *
+#endif
+
+#define Printf (void) printf
+#define Puts (void) puts
+#define Fprintf (void) fprintf
+#define Sprintf (void) sprintf
+#define Fseek (void) fseek
+#define Fread (void) fread
+#define Fputs (void) fputs
+#define Putc (void) putc
+#define Putchar (void) putchar
+#define Fclose (void) fclose
+#define Fflush (void) fflush
+#define Strcat (void) strcat
+#define Strcpy (void) strcpy
+
+/********************************
+ * Types and data *
+ *******************************/
+
+#ifndef EXTERN
+#define EXTERN extern
+#define INIT(x)
+#endif
+
+#define MAXDIM 32767
+
+typedef unsigned char ubyte;
+
+#if NeedWidePrototypes
+typedef unsigned int wide_ubyte;
+typedef int wide_bool;
+#define WIDENINT (int)
+#else
+typedef ubyte wide_ubyte;
+typedef Boolean wide_bool;
+#define WIDENINT
+#endif
+
+#if defined(MAKETEXPK) && !defined(MKTEXPK)
+#define MKTEXPK 1
+#endif
+
+/*
+ * pixel_conv is currently used only for converting absolute positions
+ * to pixel values; although normally it should be
+ * ((int) ((x) / shrink_factor + (1 << 15) >> 16)),
+ * the rounding is achieved instead by moving the constant 1 << 15 to
+ * PAGE_OFFSET in dvi-draw.c.
+ */
+#define pixel_conv(x) ((int) ((x) / shrink_factor >> 16))
+#define pixel_round(x) ((int) ROUNDUP(x, shrink_factor << 16))
+#define spell_conv0(n, f) ((long) (n * f))
+#define spell_conv(n) spell_conv0(n, dimconv)
+
+#define BMUNIT unsigned BMTYPE
+#define BMBITS (8 * BMBYTES)
+
+#define ADD(a, b) ((BMUNIT *) (((char *) a) + b))
+#define SUB(a, b) ((BMUNIT *) (((char *) a) - b))
+
+extern BMUNIT bit_masks[BMBITS + 1];
+
+struct frame {
+ struct framedata {
+ long dvi_h, dvi_v, w, x, y, z;
+ int pxl_v;
+ } data;
+ struct frame *next, *prev;
+};
+
+#ifndef TEXXET
+typedef long (*set_char_proc) ARGS((wide_ubyte));
+#else
+typedef void (*set_char_proc) ARGS((wide_ubyte, wide_ubyte));
+#endif
+
+typedef void (*home_proc) ARGS((wide_bool));
+
+struct drawinf { /* this information is saved when using virtual fonts */
+ struct framedata data;
+ struct font *fontp;
+ set_char_proc set_char_p;
+ int tn_table_len;
+ struct font **tn_table;
+ struct tn *tn_head;
+ ubyte *pos, *end;
+ struct font *virtual;
+#ifdef TEXXET
+ int dir;
+#endif
+};
+
+EXTERN struct drawinf currinf;
+
+/* entries below with the characters 'dvi' in them are actually stored in
+ scaled pixel units */
+
+#define DVI_H currinf.data.dvi_h
+#define PXL_H pixel_conv(currinf.data.dvi_h)
+#define DVI_V currinf.data.dvi_v
+#define PXL_V currinf.data.pxl_v
+#define WW currinf.data.w
+#define XX currinf.data.x
+#define YY currinf.data.y
+#define ZZ currinf.data.z
+#define ROUNDUP(x,y) (((x)+(y)-1)/(y))
+
+EXTERN int current_page;
+EXTERN int total_pages;
+EXTERN int pageno_correct INIT(1);
+EXTERN long magnification;
+EXTERN double dimconv;
+EXTERN double tpic_conv;
+EXTERN int n_files_left INIT(32767); /* for LRU closing of fonts */
+EXTERN unsigned int page_w, page_h;
+
+#if defined(GS_PATH) && !defined(PS_GS)
+#define PS_GS 1
+#endif
+
+#if defined(PS_DPS) || defined(PS_NEWS) || defined(PS_GS)
+#define PS 1
+#else
+#define PS 0
+#endif
+
+EXTERN int scanned_page; /* last page prescanned */
+
+#if PS
+EXTERN int scanned_page_ps; /* last page scanned for PS specials */
+EXTERN int scanned_page_ps_bak; /* save the above if PS is turned off */
+#endif
+
+#if COLOR
+EXTERN int scanned_page_color; /* last page scanned for color spcls */
+#endif
+
+EXTERN int scanned_page_reset; /* number to reset the above to */
+
+/*
+ * The following is set when we're prescanning before opening up the windows,
+ * and we hit a PostScript header file. We can't start up gs until we get
+ * a window to associate the process to, so we have to prescan twice.
+ */
+#if PS_GS
+EXTERN Boolean gs_postpone_prescan INIT(False);
+#endif
+
+/*
+ * Per-page data in DVI file, indexed by page number - 1.
+ * Offset is initialized in prepare_pages().
+ * Page size is initialized while prescanning.
+ */
+struct per_page {
+ long offset;
+ unsigned int pw, ph; /* page size */
+ unsigned int ww, wh; /* window size */
+};
+
+EXTERN struct per_page *page_info;
+
+/*
+ * Set if the -paper option overrides papersize specials.
+ */
+EXTERN Boolean ignore_papersize_specials INIT(False);
+
+/*
+ * Mechanism for reducing repeated warning about specials, lost characters, etc.
+ */
+EXTERN Boolean warn_spec_now;
+
+/*
+ * If we're in the middle of a PSFIG special.
+ */
+EXTERN Boolean psfig_begun INIT(False);
+
+/*
+ * Page on which to draw box from forward source special searching.
+ */
+EXTERN int source_fwd_box_page INIT(-1); /* -1 means no box */
+
+/*
+ * Information on deferred source operation. See do_pages() for meaning.
+ */
+EXTERN _Xconst char *source_forward_string INIT(NULL);
+EXTERN int source_reverse_x, source_reverse_y;
+EXTERN int source_show_all;
+
+
+/*
+ * Bitmap structure for raster ops.
+ */
+struct bitmap {
+ unsigned short w, h; /* width and height in pixels */
+ short bytes_wide; /* scan-line width in bytes */
+ char *bits; /* pointer to the bits */
+};
+
+/*
+ * Per-character information.
+ * There is one of these for each character in a font (raster fonts only).
+ * All fields are filled in at font definition time,
+ * except for the bitmap, which is "faulted in"
+ * when the character is first referenced.
+ */
+struct glyph {
+ long addr; /* address of bitmap in font file */
+ long dvi_adv; /* DVI units to move reference point */
+ short x, y; /* x and y offset in pixels */
+ struct bitmap bitmap; /* bitmap for character */
+ short x2, y2; /* x and y offset in pixels (shrunken bitmap) */
+#if GREY
+# if COLOR
+ struct fgrec *fg; /* fgrec for which these pixmaps are valid */
+# endif
+ XImage *image2;
+ char *pixmap2;
+ char *pixmap2_t;
+#endif /* GREY */
+ struct bitmap bitmap2; /* shrunken bitmap for character */
+};
+
+/*
+ * Per-character information for virtual fonts
+ */
+struct macro {
+ ubyte *pos; /* address of first byte of macro */
+ ubyte *end; /* address of last+1 byte */
+ long dvi_adv; /* DVI units to move reference point */
+ Boolean free_me; /* if free(pos) should be called when */
+ /* freeing space */
+};
+
+/*
+ * The layout of a font information block.
+ * There is one of these for every loaded font or magnification thereof.
+ * Duplicates are eliminated: this is necessary because of possible recursion
+ * in virtual fonts.
+ *
+ * Also note the strange units. The design size is in 1/2^20 point
+ * units (also called micro-points), and the individual character widths
+ * are in the TFM file in 1/2^20 ems units, i.e., relative to the design size.
+ *
+ * We then change the sizes to SPELL units (unshrunk pixel / 2^16).
+ */
+
+#define NOMAGSTP (-29999)
+
+typedef void (*read_char_proc) ARGS((struct font *, wide_ubyte));
+
+struct font {
+ struct font *next; /* link to next font info block */
+ char *fontname; /* name of font */
+ float fsize; /* size information (dots per inch) */
+ int magstepval; /* magstep number * two, or NOMAGSTP */
+ FILE *file; /* open font file or NULL */
+ _Xconst char *filename; /* name of font file */
+ long checksum; /* checksum */
+ unsigned short timestamp; /* for LRU management of fonts */
+ ubyte flags; /* flags byte (see values below) */
+ ubyte maxchar; /* largest character code */
+ double dimconv; /* size conversion factor */
+ set_char_proc set_char_p; /* proc used to set char */
+ /* these fields are used by (loaded) non-virtual fonts */
+ read_char_proc read_char; /* function to read bitmap */
+ struct glyph *glyph;
+ /* these fields are used by (loaded) virtual fonts */
+ struct font **vf_table; /* list of fonts used by this vf */
+ struct tn *vf_chain; /* ditto, if TeXnumber >= VFTABLELEN */
+ struct font *first_font; /* first font defined */
+ struct macro *macro;
+#if FREETYPE
+ /* these fields are used by (loaded) FreeType fonts */
+ struct ftfont *ft; /* master record for font (all sizes) */
+ double spsize; /* scaled size of font in spell units */
+ FT_Size size;
+ struct font *next_size; /* next font from same face */
+#endif
+ /* I suppose the above could be put into a union, but we */
+ /* wouldn't save all that much space. */
+};
+
+#define FONT_IN_USE 1 /* used for housekeeping */
+#define FONT_LOADED 2 /* if font file has been read */
+#define FONT_VIRTUAL 4 /* if font is virtual */
+
+#define TNTABLELEN 30 /* length of TeXnumber array (dvi file) */
+#define VFTABLELEN 5 /* length of TeXnumber array (virtual fonts) */
+
+struct tn {
+ struct tn *next; /* link to next TeXnumber info block */
+ int TeXnumber; /* font number (in DVI file) */
+ struct font *fontp; /* pointer to the rest of the info */
+};
+
+EXTERN struct font *tn_table[TNTABLELEN];
+EXTERN struct font *font_head INIT(NULL);
+EXTERN struct tn *tn_head INIT(NULL);
+EXTERN ubyte maxchar;
+EXTERN unsigned short current_timestamp INIT(0);
+
+/*
+ * Command line flags.
+ */
+
+extern struct _resource {
+#if TOOLKIT && CFGFILE
+ _Xconst char *progname;
+#endif
+#if TOOLKIT
+ int shrinkfactor;
+ _Xconst char *main_translations;
+ _Xconst char *wheel_translations;
+ int dvips_hang;
+ int dvips_fail_hang;
+#endif
+ int wheel_unit;
+ int _density;
+#ifdef GREY
+ float _gamma;
+#endif
+ int _pixels_per_inch;
+ _Xconst char *sidemargin;
+ _Xconst char *topmargin;
+ _Xconst char *xoffset;
+ _Xconst char *yoffset;
+ _Xconst char *paper;
+ _Xconst char *_alt_font;
+#ifdef MKTEXPK
+ Boolean makepk;
+#endif
+ _Xconst char *mfmode;
+ _Xconst char *editor;
+ _Xconst char *src_pos;
+ Boolean src_fork;
+ Boolean _list_fonts;
+#if FREETYPE
+ Boolean freetype;
+#endif
+ Boolean reverse;
+ Boolean _warn_spec;
+ Boolean _hush_chars;
+ Boolean _hush_chk;
+ Boolean safer;
+#if defined(VMS) || !defined(TOOLKIT)
+ _Xconst char *fore_color;
+ _Xconst char *back_color;
+#endif
+ Pixel _fore_Pixel;
+ Pixel _back_Pixel;
+#ifdef TOOLKIT
+ Pixel _brdr_Pixel;
+ Pixel _hl_Pixel;
+ Pixel _cr_Pixel;
+#endif
+ _Xconst char *icon_geometry;
+ Boolean keep_flag;
+ Boolean copy;
+ Boolean thorough;
+#if PS
+ /* default is to use DPS, then NEWS, then GhostScript;
+ * we will figure out later on which one we will use */
+ Boolean _postscript;
+ Boolean allow_shell;
+#ifdef PS_DPS
+ Boolean useDPS;
+#endif
+#ifdef PS_NEWS
+ Boolean useNeWS;
+#endif
+#ifdef PS_GS
+ Boolean useGS;
+ Boolean gs_safer;
+ Boolean gs_alpha;
+ _Xconst char *gs_path;
+ _Xconst char *gs_palette;
+#endif
+#endif /* PS */
+ Boolean prescan;
+ _Xconst char *debug_arg;
+ Boolean version_flag;
+#if BUTTONS
+ Boolean expert;
+ _Xconst char *button_translations;
+ int shrinkbutton[9];
+ Dimension btn_side_spacing;
+ Dimension btn_top_spacing;
+ Dimension btn_between_spacing;
+ Dimension btn_between_extra;
+ Dimension btn_border_width;
+#endif
+ _Xconst char *mg_arg[5];
+#if COLOR
+ Boolean _use_color;
+#endif
+#ifdef GREY
+ Boolean _use_grey;
+ Bool3 install;
+#endif
+#if TOOLKIT
+ _Xconst char *dvips_path;
+#endif
+} resource;
+
+/* As a convenience, we define the field names without leading underscores
+ * to point to the field of the above record. Here are the global ones;
+ * the local ones are defined in each module. */
+
+#define density resource._density
+#define pixels_per_inch resource._pixels_per_inch
+#define alt_font resource._alt_font
+#define list_fonts resource._list_fonts
+#define warn_spec resource._warn_spec
+#define hush_chars resource._hush_chars
+#define hush_chk resource._hush_chk
+#if COLOR
+#define use_color resource._use_color
+#endif
+#ifdef GREY
+#define use_grey resource._use_grey
+#endif
+
+#ifndef TOOLKIT
+EXTERN Pixel brdr_Pixel;
+#endif
+
+#if GREY
+EXTERN Pixel plane_masks[4];
+#endif
+
+#if GREY || COLOR
+EXTERN XColor color_data[2];
+#define fore_color_data color_data[0]
+#define back_color_data color_data[1]
+#endif
+
+#if COLOR
+
+struct rgb {
+ unsigned short r, g, b;
+};
+
+struct pagecolor {
+ struct rgb bg;
+ unsigned int stacksize;
+ _Xconst struct rgb *colorstack;
+};
+
+/* Information on background color and initial color stack for each page. */
+EXTERN struct pagecolor *page_colors INIT(NULL);
+
+/* The initial color stack is gotten from the pagecolor record for a page. */
+EXTERN _Xconst struct rgb *color_bottom;
+EXTERN unsigned int color_bot_size; /* number of entries */
+
+/* Additions to the runtime color stack on a given page are stored in a linked
+ list. "struct colorframe" is defined in special.c. */
+EXTERN struct colorframe *rcs_top;
+
+/* Color states. */
+EXTERN struct rgb fg_initial; /* Initial fg (from command line) */
+EXTERN struct rgb bg_initial; /* Initial bg */
+
+/*
+ * For each (foreground, background) color pair, we keep information (depending
+ * on the color model). It is organized as a linked list of linked lists,
+ * with background color more significant.
+ */
+
+struct bgrec {
+ struct bgrec *next;
+ struct rgb color;
+ struct fgrec *fg_head;
+ Boolean pixel_good; /* if the pixel entry is valid */
+ Pixel pixel;
+};
+
+struct fgrec {
+ struct fgrec *next;
+ struct rgb color;
+ Boolean pixel_good; /* if the pixel entry is valid */
+ Pixel pixel;
+#if GREY
+ Boolean palette_good; /* if the palette entry is valid */
+ Pixel palette[16]; /* non-TrueColor only */
+#endif
+};
+
+EXTERN struct bgrec *bg_head INIT(NULL); /* head of list */
+EXTERN struct bgrec *bg_current INIT(NULL); /* current bg value */
+EXTERN struct fgrec *fg_current; /* current fg value */
+EXTERN struct fgrec *fg_active INIT(NULL); /* where the GCs are */
+
+/* List of allocated colors (to be deallocated upon document change) */
+EXTERN Pixel *color_list; /* list of colors */
+EXTERN unsigned int color_list_len INIT(0); /* current len of list*/
+EXTERN unsigned int color_list_max INIT(0); /* allocated size */
+
+/* Whether the color situation has been warned about. */
+EXTERN Boolean color_warned INIT(False);
+
+/* Cursor color (for XRecolorCursor). */
+extern XColor cr_Color;
+
+#endif /* COLOR */
+
+extern struct mg_size_rec {
+ int w;
+ int h;
+}
+ mg_size[5];
+
+EXTERN int debug INIT(0);
+
+#define DBG_BITMAP 1
+#define DBG_DVI 2
+#define DBG_PK 4
+#define DBG_BATCH 8
+#define DBG_EVENT 16
+#define DBG_OPEN 32
+#define DBG_PS 64
+#define DBG_CLIENT 128
+#define DBG_ALL (~DBG_BATCH)
+
+EXTERN int offset_x, offset_y;
+EXTERN unsigned int unshrunk_paper_w, unshrunk_paper_h;
+EXTERN unsigned int unshrunk_page_w, unshrunk_page_h;
+
+EXTERN char *dvi_name INIT(NULL); /* dvi file name */
+EXTERN FILE *dvi_file; /* user's file */
+EXTERN Boolean dvi_file_ready INIT(False);
+ /* done with font generation and prescanning */
+EXTERN time_t dvi_time; /* last modification time */
+EXTERN ino_t dvi_inode; /* used for source specials */
+EXTERN unsigned char *dvi_property; /* for setting in window */
+EXTERN size_t dvi_property_length;
+#if TOOLKIT
+EXTERN Boolean titles_are_stale INIT(True);
+ /* replace icon/window titles */
+#endif
+EXTERN _Xconst char *prog;
+EXTERN int bak_shrink; /* last shrink factor != 1 */
+EXTERN Dimension window_w, window_h;
+EXTERN XImage *image;
+EXTERN int backing_store;
+EXTERN int home_x, home_y;
+
+EXTERN Display *DISP;
+EXTERN Screen *SCRN;
+#if TOOLKIT
+extern XtActionsRec Actions[];
+extern Cardinal num_actions;
+#endif
+#if XAW
+EXTERN XtAccelerators accels_cr, accels_cr_click;
+#endif
+#ifdef GREY
+EXTERN Visual *our_visual;
+EXTERN unsigned int our_depth;
+EXTERN Colormap our_colormap;
+#else
+#define our_depth (unsigned int) DefaultDepthOfScreen(SCRN)
+#define our_visual DefaultVisualOfScreen(SCRN)
+#define our_colormap DefaultColormapOfScreen(SCRN)
+#endif
+EXTERN GC ruleGC;
+EXTERN GC foreGC, highGC;
+EXTERN GC foreGC2;
+EXTERN GC copyGC;
+EXTERN Boolean copy;
+
+EXTERN Cursor redraw_cursor, ready_cursor, drag_cursor[3];
+
+#if TOOLKIT
+struct xdvi_action {
+ struct xdvi_action *next;
+ XtActionProc proc;
+ Cardinal num_params;
+ String param;
+};
+
+struct wheel_acts {
+ struct wheel_acts *next;
+ Modifiers mask;
+ Modifiers value;
+ struct _LateBindings *late_bindings;
+ unsigned int button;
+ struct xdvi_action *action;
+};
+
+EXTERN struct wheel_acts *wheel_actions;
+#endif
+
+#if MOTIF && BUTTONS
+EXTERN XtTranslations wheel_trans_table INIT(NULL);
+#endif
+
+#ifdef GREY
+EXTERN Pixel *pixeltbl;
+EXTERN Pixel *pixeltbl_t;
+#endif /* GREY */
+
+/*
+ * Flag values and masks for event_flags
+ */
+
+#define EV_IDLE (1<<0) /* non-event */
+#define EV_CURSOR (1<<1) /* cursor needs to revert back to ready */
+#define EV_EXPOSE (1<<2) /* expose occurred somewhere */
+#define EV_MAG_MOVE (1<<3) /* magnifier moved */
+#define EV_MAG_GONE (1<<4) /* magnifier gone while being drawn */
+#define EV_ACK (1<<5) /* used internally */
+#define EV_SRC (1<<6) /* source special operation is pending */
+#define EV_NEWPAGE (1<<7) /* new page requested */
+#define EV_PS_TOGGLE (1<<8) /* PostScript toggled on or off */
+#define EV_NEWDOC (1<<9) /* new dvi file requested */
+#define EV_TERM (1<<10) /* quit */
+#define EV_MAXPLUS1 (1<<11)
+
+#define EV_GE_IDLE (EV_MAXPLUS1 - EV_IDLE)
+#define EV_GT_IDLE (EV_MAXPLUS1 - EV_CURSOR)
+#define EV_GE_CURSOR (EV_MAXPLUS1 - EV_CURSOR)
+#define EV_GE_EXPOSE (EV_MAXPLUS1 - EV_EXPOSE)
+#define EV_GE_MAG_MOVE (EV_MAXPLUS1 - EV_MAG_MOVE)
+#define EV_GE_MAG_GONE (EV_MAXPLUS1 - EV_MAG_GONE)
+#define EV_GE_ACK (EV_MAXPLUS1 - EV_ACK)
+#define EV_GE_NEWPAGE (EV_MAXPLUS1 - EV_NEWPAGE)
+#define EV_GE_PS_TOGGLE (EV_MAXPLUS1 - EV_PS_TOGGLE)
+#define EV_GE_NEWDOC (EV_MAXPLUS1 - EV_NEWDOC)
+#define EV_GE_TERM (EV_MAXPLUS1 - EV_TERM)
+
+#define EV_NOWAIT EV_GE_IDLE
+
+EXTERN unsigned int ev_flags INIT(EV_IDLE);
+EXTERN VOLATILE int event_counter INIT(0);
+EXTERN jmp_buf canit_env;
+
+struct xchild {
+ struct xchild *next; /* link to next in list */
+ pid_t pid; /* pid of process, or 0 */
+ Boolean killable; /* if can be killed with SIGKILL */
+ void (*proc) ARGS((int)); /* procedure to call */
+};
+
+struct xio {
+ struct xio *next; /* link to next in list */
+ int fd; /* file descriptor */
+ int xio_events; /* same as in struct pollfd (can't call
+ it events because poll.h on AIX
+ defines events to something else) */
+#if HAVE_POLL
+ struct pollfd *pfd;
+#endif
+ void (*read_proc) ARGS((void)); /* call to read */
+ void (*write_proc) ARGS((void)); /* call to write */
+};
+
+struct xtimer {
+ struct xtimer *next; /* link to next in chain */
+ struct timeval when; /* when to call the routine */
+ void (*proc) ARGS((struct xtimer *)); /* procedure to call */
+#if MOTIF_TIMERS
+ XtTimerCallbackProc xt_proc; /* additional data for Xm */
+ XtPointer closure;
+#endif
+};
+
+#if MOTIF_TIMERS
+# define TIMER_INIT(proc) {NULL, {0, 0}, proc, NULL, NULL}
+#else
+# define TIMER_INIT(proc) {NULL, {0, 0}, proc}
+#endif
+
+struct WindowRec {
+ Window win;
+ int shrinkfactor;
+ int base_x, base_y;
+ unsigned int width, height;
+ int min_x, max_x, min_y, max_y; /* for pending expose events */
+};
+
+extern struct WindowRec mane, alt, currwin;
+EXTERN int min_x, max_x, min_y, max_y;
+EXTERN Boolean drawing_mag INIT(False);
+
+#define shrink_factor currwin.shrinkfactor
+
+#if TOOLKIT
+EXTERN Widget top_level INIT(0);
+EXTERN Widget vport_widget, draw_widget, clip_widget;
+# if MOTIF
+EXTERN Widget shrink_button[4];
+EXTERN Widget x_bar, y_bar; /* horizontal and vert. scroll bars */
+# endif
+# if BUTTONS
+EXTERN Widget form_widget;
+EXTERN int xtra_wid INIT(0);
+extern _Xconst char default_button_config[]; /* defined in events.c */
+# if XAW
+EXTERN Widget panel_widget;
+EXTERN Cursor panel_cursor INIT(0);
+# endif
+# endif
+#else /* not TOOLKIT */
+EXTERN Window top_level INIT(0);
+
+#define BAR_WID 12 /* width of darkened area */
+#define BAR_THICK 15 /* gross amount removed */
+#endif /* not TOOLKIT */
+
+#if XAW
+#define WARN(t, s) (void) warning_popup(s, "OK", NULL)
+#define WARN1(t, s, s1) (void) warning_popup_long(s, "OK", NULL, s1)
+#define WARN2(t, s, s1, s2) (void) warning_popup_long(s, "OK", NULL, s1, s2)
+#elif MOTIF
+#define WARN(t, s) (void) warning_popup(s, t, NULL, NULL)
+#define WARN1(t, s, s1) (void) warning_popup_long(s, t, NULL, NULL, s1)
+#define WARN2(t, s, s1, s2) (void) warning_popup_long(s, t, NULL, NULL, s1, s2)
+#elif CC_K_AND_R
+#define WARN(t, s) (void) fputs(s "\n", stderr)
+#define WARN1(t, s, s1) (void) fprintf(stderr, s "\n", s1)
+#else
+#define WARN(t, s) (void) (fputs(s, stderr), putc('\n', stderr))
+#define WARN1(t, s, s1) (void) (fprintf(stderr, s, s1), putc('\n', stderr))
+#endif
+
+/*
+ * If a popup is popped up before the main window, then the main window is
+ * likely to cover it. So we have to postpone popping them up until after
+ * realizing the main window. It is not workable to pop them up immediately
+ * and then raise them later, due to unpredictable window manager behavior.
+ */
+
+#if TOOLKIT
+EXTERN Boolean postpone_popups INIT(True);
+EXTERN size_t n_init_popups INIT(0);
+EXTERN Widget *init_popups;
+EXTERN size_t alloc_init_popups INIT(0);
+#endif
+
+/*
+ * Structure to use for status popups.
+ */
+
+#if TOOLKIT
+struct status_popup {
+ Widget shell;
+ Widget label;
+ int expected_type;
+ Boolean popped;
+ Boolean spurious;
+};
+#endif
+
+EXTERN char *ffline INIT(NULL); /* an array used by filefind to store */
+ /* the file name being formed. */
+ /* It expands as needed. */
+ /* Also used elsewhere. */
+EXTERN size_t ffline_len INIT(0); /* current length of ffline[] */
+
+
+#if FREETYPE || PS
+
+/*
+ * AVL tree structures.
+ */
+
+#define AVL_COMMON \
+ _Xconst char *key; /* key */ \
+ int key_len; /* length of key */ \
+ int bal; /* AVL balancing information */ \
+ struct avl *left; \
+ struct avl *right
+
+struct avl { /* generic data structure */
+ AVL_COMMON;
+};
+
+ /* Data structure for Type 1 fonts -- contents of psfonts.map */
+struct avl_t1 {
+ AVL_COMMON;
+ _Xconst char *psname; /* PS name of font */
+ _Xconst char *fontfile; /* (short) name of pfa/pfb file */
+ _Xconst char *encname; /* (short) name of encoding file */
+ _Xconst char *addinfo; /* additional PS instructions */
+# if FREETYPE
+ Boolean bad; /* if later found to be unloadable */
+ struct ftfont *ft; /* pointer to FreeType record */
+# endif
+};
+
+
+# if FREETYPE
+
+struct ftfont { /* info for FreeType font (Type 1 or TrueType) */
+ FT_Face face; /* NULL means not loaded yet */
+ struct font *first_size;
+ struct avl_t1 *t1;
+ /* struct avl_tt *tt; */
+ struct FT_StreamRec_ stream;
+ struct avl_enc *enc; /* pointer to encoding record */
+ double expn; /* expansion factor */
+};
+
+# endif
+
+struct avl_enc {
+ AVL_COMMON;
+ Boolean valid;
+ _Xconst char *vec[256];
+};
+
+#endif /* FREETYPE || PS */
+
+
+/*
+ * Used by the geometry-scanning routines.
+ * It passes pointers to routines to be called at certain
+ * points in the dvi file, and other information.
+ */
+
+struct geom_info {
+ void (*geom_box) ARGS((struct geom_info *,
+ long, long, long, long));
+ void (*geom_special) ARGS((struct geom_info *, _Xconst char *));
+ jmp_buf done_env;
+ void *geom_data;
+};
+
+typedef void (*mouse_proc) ARGS((XEvent *));
+extern void null_mouse ARGS((XEvent *));
+
+EXTERN mouse_proc mouse_motion INIT(null_mouse);
+EXTERN mouse_proc mouse_release INIT(null_mouse);
+
+/* Used for source special lookup (forward search) and for window manager
+ delete protocol (toolkit only). */
+
+#if XAW
+EXTERN Atom atoms[5];
+#elif MOTIF
+EXTERN Atom atoms[4];
+#else
+EXTERN Atom atoms[3];
+#endif
+
+#define ATOM_XDVI_WINDOWS (atoms[0])
+#define ATOM_DVI_FILE (atoms[1])
+#define ATOM_SRC_GOTO (atoms[2])
+#if TOOLKIT
+#define XA_WM_DELETE_WINDOW (atoms[3])
+#endif
+#if XAW
+#define XA_WM_PROTOCOLS (atoms[4])
+#endif
+
+#ifdef SELFAUTO
+EXTERN _Xconst char *argv0; /* argv[0] */
+#endif
+
+#if PS
+
+extern struct psprocs {
+ void (*toggle) ARGS((void));
+ void (*destroy) ARGS((void));
+ void (*interrupt) ARGS((void));
+ void (*endpage) ARGS((void));
+ void (*drawbegin) ARGS((int, int, _Xconst char *));
+ void (*drawraw) ARGS((_Xconst char *));
+ void (*drawfile) ARGS((_Xconst char *, FILE *));
+ void (*drawend) ARGS((_Xconst char *));
+ void (*beginheader) ARGS((void));
+ void (*endheader) ARGS((void));
+ void (*newdoc) ARGS((void));
+} psp, no_ps_procs;
+
+#endif /* PS */
+
+/********************************
+ * Procedures *
+ *******************************/
+
+_XFUNCPROTOBEGIN
+
+extern int atopix ARGS((_Xconst char *, wide_bool));
+#if TOOLKIT
+extern Bool compile_action ARGS((_Xconst char *, struct xdvi_action **));
+#endif
+#if BUTTONS
+extern void create_buttons ARGS((void));
+#if XAW
+extern void set_button_panel_height ARGS((XtArgVal));
+#endif
+#endif /* BUTTONS */
+#if GREY
+extern void init_plane_masks ARGS((void));
+#endif
+#if COLOR
+extern Pixel alloc_color ARGS((_Xconst struct rgb *, Pixel));
+extern void do_color_change ARGS((void));
+#elif GREY
+extern void init_pix ARGS((void));
+#endif
+extern void expose ARGS((struct WindowRec *, int, int,
+ unsigned int, unsigned int));
+extern void home ARGS((wide_bool));
+extern void reconfig ARGS((void));
+#if TOOLKIT
+extern void handle_resize ARGS((Widget, XtPointer, XEvent *, Boolean *));
+extern void handle_expose ARGS((Widget, XtPointer, XEvent *, Boolean *));
+extern void handle_property_change ARGS((Widget, XtPointer, XEvent *,
+ Boolean *));
+#endif
+#if XAW
+extern void handle_messages ARGS((Widget, XtPointer, XEvent *, Boolean *));
+#elif MOTIF
+extern void handle_wm_delete ARGS((Widget, XtPointer, XtPointer));
+#endif
+extern void goto_page ARGS((int, home_proc));
+#if MOTIF
+extern void file_pulldown_callback ARGS((Widget, XtPointer, XtPointer));
+extern void navigate_pulldown_callback ARGS((Widget, XtPointer, XtPointer));
+extern void scale_pulldown_callback ARGS((Widget, XtPointer, XtPointer));
+extern void set_shrink_factor ARGS((int));
+extern void popdown_callback ARGS((Widget, XtPointer, XtPointer));
+#endif
+#if !TOOLKIT
+extern void showmessage ARGS((_Xconst char *));
+#endif
+extern void set_chld ARGS((struct xchild *));
+extern void clear_chld ARGS((struct xchild *));
+extern void set_io ARGS((struct xio *));
+extern void clear_io ARGS((struct xio *));
+extern void set_timer ARGS((struct xtimer *, int));
+extern void cancel_timer ARGS((struct xtimer *));
+extern unsigned int read_events ARGS((unsigned int));
+extern void enable_intr ARGS((void));
+extern void do_pages ARGS((void)) NORETURN;
+#if XAW
+extern void simple_popup ARGS((struct status_popup *, _Xconst char *,
+ XtCallbackProc));
+extern void simple_popdown ARGS((struct status_popup *));
+extern void do_popup ARGS((Widget));
+extern Widget warning_popup ARGS((_Xconst char *, _Xconst char *,
+ XtCallbackProc));
+extern Widget warning_popup_long VARGS((_Xconst char *, _Xconst char *,
+ XtCallbackProc, ...));
+extern void Act_print ARGS((Widget, XEvent *, String *, Cardinal *));
+extern void Act_open_dvi_file ARGS((Widget, XEvent *, String *,
+ Cardinal *));
+#elif MOTIF
+extern void simple_popup ARGS((struct status_popup *, _Xconst char *,
+ XtCallbackProc));
+extern void simple_popdown ARGS((struct status_popup *));
+extern void do_popup ARGS((Widget));
+extern Widget warning_popup ARGS((_Xconst char *, int, _Xconst char *,
+ XtCallbackProc));
+extern Widget warning_popup_long ARGS((_Xconst char *, int, _Xconst char *,
+ XtCallbackProc, ...));
+extern void Act_print ARGS((Widget, XEvent *, String *, Cardinal *));
+extern void Act_open_dvi_file ARGS((Widget, XEvent *, String *,
+ Cardinal *));
+#endif
+extern void reset_fonts ARGS((void));
+#if COLOR
+extern void reset_colors ARGS((void));
+extern void full_reset_colors ARGS((void));
+#endif
+extern void realloc_font ARGS((struct font *, wide_ubyte));
+extern void realloc_virtual_font ARGS((struct font *, wide_ubyte));
+extern Boolean load_font ARGS((struct font *));
+extern struct font *define_font ARGS((FILE *, wide_ubyte,
+ struct font *, struct font **, unsigned int,
+ struct tn **));
+extern void init_page ARGS((void));
+extern Boolean open_dvi_file ARGS((_Xconst char *));
+extern void form_dvi_property ARGS((ino_t));
+extern void init_dvi_file ARGS((void));
+extern void set_dvi_property ARGS((void));
+extern Boolean check_dvi_file ARGS((void));
+extern void reload_dvi_file ARGS((void));
+#ifndef TEXXET
+extern long set_char ARGS((wide_ubyte));
+extern long load_n_set_char ARGS((wide_ubyte));
+extern long set_vf_char ARGS((wide_ubyte));
+# if FREETYPE
+extern long set_ft_char ARGS((wide_ubyte));
+# endif
+#else
+extern void set_char ARGS((wide_ubyte, wide_ubyte));
+extern void load_n_set_char ARGS((wide_ubyte, wide_ubyte));
+extern void set_vf_char ARGS((wide_ubyte, wide_ubyte));
+# if FREETYPE
+extern long set_ft_char ARGS((wide_ubyte, wide_ubyte));
+# endif
+#endif
+extern void open_font_file ARGS((struct font *));
+extern void prescan ARGS((void));
+extern void draw_page ARGS((void));
+extern void source_reverse_search ARGS((int, int));
+extern void source_special_show ARGS((wide_bool));
+extern void source_forward_search ARGS((_Xconst char *));
+#if CFGFILE
+extern void readconfig ARGS((void));
+#endif
+#if FREETYPE || PS
+extern FILE *open_t1_font ARGS((struct avl_t1 *, _Xconst char **));
+extern void read_encoding ARGS((struct avl_enc *));
+#endif
+extern void init_font_open ARGS((void));
+extern Boolean font_open ARGS((struct font *, char **, int *));
+#if PS
+extern void ps_clear_cache ARGS((void));
+extern void ps_destroy ARGS((void));
+#endif
+extern void init_prescan ARGS((void));
+#if COLOR
+extern void scan_color_eop ARGS((void));
+extern void set_fg_color ARGS((_Xconst struct rgb *));
+#endif
+extern void applicationDoSpecial ARGS((char *));
+extern void scan_special ARGS((char *));
+extern void geom_do_special ARGS((struct geom_info *, char *, double));
+extern void xdvi_exit ARGS((int)) NORETURN;
+extern void oops VARGS((_Xconst char *, ...)) NORETURN;
+#ifndef KPATHSEA
+extern void *xmalloc ARGS((unsigned));
+extern void *xrealloc ARGS((void *, unsigned));
+extern char *xstrdup ARGS((_Xconst char *));
+extern char *xmemdup ARGS((_Xconst char *, size_t));
+#endif
+#if TOOLKIT && !HAVE_STRERROR && !defined strerror
+extern char *strerror ARGS((int));
+#endif
+extern void expandline ARGS((size_t));
+extern void alloc_bitmap ARGS((struct bitmap *));
+#ifndef KPATHSEA
+extern void xputenv ARGS((_Xconst char *, _Xconst char *));
+#endif
+extern int memicmp ARGS((_Xconst char *, _Xconst char *, size_t));
+extern FILE *xfopen ARGS((_Xconst char *, OPEN_MODE_ARGS));
+#if XAW
+extern int xopen ARGS((_Xconst char *, int));
+#endif
+extern int xpipe ARGS((int *));
+extern DIR *xopendir ARGS((_Xconst char *));
+extern _Xconst struct passwd *ff_getpw ARGS((_Xconst char **, _Xconst char *));
+extern unsigned long num ARGS((FILE *, int));
+extern long snum ARGS((FILE *, int));
+#if FREETYPE || PS
+extern struct avl *avladd ARGS((_Xconst char *, size_t, struct avl **,
+ size_t));
+#endif
+extern size_t property_get_data ARGS((Window, Atom, unsigned char **,
+ int (*x_get_property) (Display *, Window, Atom, long,
+ long, Bool, Atom, Atom *, int *, unsigned long *,
+ unsigned long *, unsigned char **)));
+#if PS
+extern int xdvi_temp_fd ARGS((char **));
+#endif
+extern void prep_fd ARGS((int, wide_bool));
+extern void read_PK_index ARGS((struct font *, wide_bool));
+extern void read_GF_index ARGS((struct font *, wide_bool));
+extern void read_VF_index ARGS((struct font *, wide_bool));
+#if FREETYPE
+extern Boolean load_ft_font ARGS((struct font *));
+#endif
+
+#if PS
+extern void ps_init_paths ARGS((void));
+extern void drawbegin_none ARGS((int, int, _Xconst char *));
+extern void draw_bbox ARGS((void));
+extern void NullProc ARGS((void));
+#ifdef PS_DPS
+extern Boolean initDPS ARGS((void));
+#endif
+#ifdef PS_NEWS
+extern Boolean initNeWS ARGS((void));
+#endif
+#ifdef PS_GS
+extern Boolean initGS ARGS((void));
+extern void gs_resume_prescan ARGS((void));
+#endif
+#endif /* PS */
+
+_XFUNCPROTOEND
+
+#define one(fp) ((unsigned char) getc(fp))
+#define sone(fp) ((long) one(fp))
+#define two(fp) num (fp, 2)
+#define stwo(fp) snum(fp, 2)
+#define four(fp) num (fp, 4)
+#define sfour(fp) snum(fp, 4)
+
+#endif /* XDVI_H */
diff --git a/xdvi.icon b/xdvi.icon
@@ -0,0 +1,27 @@
+#define xdvi_width 48
+#define xdvi_height 48
+static _Xconst unsigned char xdvi_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x00, 0x00, 0x01, 0x00, 0x00, 0xa2, 0xe0, 0x44, 0x38, 0x95, 0x13,
+ 0x9e, 0x17, 0x45, 0x45, 0x55, 0xf4, 0x82, 0xf0, 0x28, 0x3d, 0xd5, 0x13,
+ 0x82, 0x10, 0x28, 0x05, 0x55, 0x10, 0x82, 0xe0, 0x10, 0x39, 0x8a, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x1f, 0x00,
+ 0x79, 0x18, 0x18, 0x13, 0x16, 0x00, 0x69, 0x10, 0x18, 0x0e, 0x16, 0x00,
+ 0xcf, 0x20, 0x1c, 0x0e, 0xd6, 0x00, 0xe9, 0xc3, 0x7b, 0x84, 0x3f, 0x01,
+ 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0xcc,
+ 0x08, 0x00, 0x00, 0x00, 0x30, 0x52, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x52,
+ 0x0a, 0xc0, 0xff, 0x03, 0x30, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0xc0, 0xff, 0x03, 0x10, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf0, 0x17,
+ 0x0b, 0x0c, 0x3c, 0xc0, 0x93, 0x20, 0x0c, 0x0e, 0x43, 0x20, 0x96, 0x40,
+ 0x0c, 0x8e, 0x81, 0x10, 0x96, 0xbe, 0x0a, 0x8d, 0x81, 0x19, 0x90, 0x82,
+ 0x8a, 0x8c, 0x81, 0x0d, 0x90, 0x42, 0x48, 0x8c, 0x81, 0xed, 0x91, 0x3e,
+ 0x6a, 0x0c, 0xc3, 0x1d, 0x96, 0x12, 0x38, 0x0c, 0xbc, 0x0d, 0x1c, 0x02,
+ 0xf8, 0x3f, 0x80, 0x0d, 0x1c, 0x3e, 0x0b, 0x0c, 0x80, 0x0c, 0x1c, 0x00,
+ 0x0b, 0x0c, 0xc3, 0x18, 0x1c, 0x00, 0x0a, 0x0c, 0x63, 0x10, 0x16, 0x00,
+ 0x89, 0x3f, 0x1e, 0xe0, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x1f, 0xae, 0x0f, 0x00, 0x80, 0x84, 0x0a, 0xae,
+ 0x87, 0x64, 0x86, 0x84, 0x08, 0x42, 0x42, 0x45, 0xe2, 0x1c, 0x07, 0x42};
diff --git a/xdvi.lsm b/xdvi.lsm
@@ -0,0 +1,21 @@
+Cut this out, fill it in, send it to 'lsm@execpc.com' with the subject 'add'.
+
+Begin3
+Title: xdvi
+Version: 21
+Entered-date: 05FEB99
+Description: xdvi is a program for previewing .dvi files, which are
+ produced by the mathematical typesetting system, TeX.
+Keywords: xdvi, dvi, TeX, LaTeX
+Author: Many people contributed to this software. See the README file.
+Maintained-by: vojta@math.berkeley.edu (Paul Vojta)
+Primary-site: ftp.x.org /contrib/applications
+ 196k xdvi-22.tar.Z
+Alternate-site: ctan.tug.org /tex-archive/dviware/xdvi
+ 196k xdvi-22.tar.gz
+Original-site: math.berkeley.edu /pub/Software/TeX
+ 196k xdvi-latest.tar.Z
+Platforms: Linux or Unix (or possibly VMS); X11; TeX fonts; ghostscript
+ or Display PostScript (optional)
+Copying-policy: X Consortium copyright (free from charge)
+End
diff --git a/xdvizilla b/xdvizilla
@@ -0,0 +1,123 @@
+#! /bin/sh
+#
+# This is a kludge to fix helper apps in mozilla. See mozilla bugs #57420
+# and also #78919.
+#
+# It's also useful for tar files with Netscape 4.x
+#
+# Copyright (c) 2002-2003 Paul Vojta
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO
+# THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+NO_RM=
+TMP_DIR=
+progname=xdvizilla
+
+do_cleanup()
+{
+ [ -z "$NO_RM" ] && rm -f "$ARG"
+ [ -n "$TMP_DIR" ] && rm -rf "$TMP_DIR"
+}
+
+do_abort()
+{
+ xmessage -nearmouse "$progname: $1"
+ do_cleanup
+ exit 1
+}
+
+setup_dir()
+{
+ if [ -z "$TMP_DIR" ]; then
+ # Create a temporary directory only read/writable by user
+ TMP_DIR=${TMP-/tmp}/$progname.$$
+ (umask 077; mkdir "$TMP_DIR") || \
+ do_abort "Could not create directory \`$TMP_DIR'"
+ trap 'do_cleanup' 1 2 3 7 13 15
+ fi
+}
+
+if [ $# -gt 1 -a "x$1" = "x-no-rm" ]; then
+ NO_RM=y
+ shift
+fi
+
+if [ $# -ne 1 ]; then
+ xmessage -nearmouse "Usage: $progname [-no-rm] <file>"
+ exit 1
+fi
+
+DIR=`dirname "$0"`
+
+if [ "$DIR" = . ]; then
+ DIR=
+elif [ -f "$DIR"/xdvi -a -x "$DIR"/xdvi ]; then
+ DIR="$DIR"/
+else
+ DIR=
+fi
+
+ARG=$1
+FILE=$1
+FILETYPE=`file "$FILE"`
+UNCOMP=
+
+case "$FILETYPE" in
+
+ *"gzip compressed data"*)
+ UNCOMP=gunzip
+ ;;
+
+ *"compressed data"* | *"compress'd data"*)
+ UNCOMP=uncompress
+ ;;
+
+ *": empty")
+ do_abort "$1 is an empty file
+(this is a bug in Mozilla)"
+ ;;
+
+esac
+
+if [ -n "$UNCOMP" ]; then
+ setup_dir
+ FILE=$TMP_DIR/uncomp
+ $UNCOMP -c "$1" > $FILE
+ FILETYPE=`file "$FILE"`
+fi
+
+case "$FILETYPE" in
+
+ *" tar archive" | *" tar archive "*)
+ setup_dir
+ cat "$FILE" | (cd "$TMP_DIR"; tar xf -)
+ DVINAME=`tar tf "$FILE" | grep '\.dvi$' | head -1`
+ [ -n "$DVINAME" ] || \
+ do_abort "Tar file does not contain a dvi file."
+ FILE=$TMP_DIR/$DVINAME
+ ;;
+
+esac
+
+"$DIR"xdvi -safer "$FILE"
+
+do_cleanup
+
+exit 0
diff --git a/xdvizilla.1 b/xdvizilla.1
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1990-2002 Paul Vojta
+.\"
+.\" Permission is hereby granted, free of charge, to any person obtaining a copy
+.\" of this software and associated documentation files (the "Software"), to
+.\" deal in the Software without restriction, including without limitation the
+.\" rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+.\" sell copies of the Software, and to permit persons to whom the Software is
+.\" furnished to do so, subject to the following conditions:
+.\"
+.\" The above copyright notice and this permission notice shall be included in
+.\" all copies or substantial portions of the Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+.\" PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+.\" IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+.\" CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+.\"
+.TH XDVIZILLA 1 "11 October 2002" "X Version 11"
+.SH NAME
+xdvizilla \- Helper application for running xdvi
+.SH SYNOPSIS
+.B xdvizilla
+[\fB\-no\-rm\fP]
+.I file
+.SH DESCRIPTION
+Presently (October 2002), Mozilla has some bugs with helper applications:
+it passes gzipped
+.RB ( .gz )
+files directly to the helper application without uncompressing, and it
+passes compressed
+.RB ( .Z )
+files as empty files.
+.PP
+To work around these problems,
+.B xdvizilla
+was written to look at files and decompress them correctly (depending on
+their file types).
+.PP
+In addition, some sites produced tarred
+.I dvi
+files (including the
+.I dvi
+file as well as some included figures), and
+.B xdvizilla
+correctly handles those files as well.
+.SH OPTIONS
+Only one option is supported:
+.TP
+.B \-no\-rm
+Normally
+.B xdvizilla
+will remove
+.I file
+before finishing. This option inhibits this behavior.
+.SH INSTALLATION
+In addition to installing
+.B xdvizilla
+in a directory on the default search path, it is necessary to set it up
+as a helper application within the browser.
+.PP
+For
+.BR "Netscape 4.x" ,
+add the following lines to the
+.B mailcap
+file:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+application/x-dvi; xdvi -safer %s
+application/x-dvi-tar; xdvizilla -no-rm %s
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+For
+.BR "Netscape 6.x" ,
+.BR "Netscape 7.x" ,
+or
+.BR "Mozilla 1.x" ,
+add the following lines to the
+.B mailcap
+file:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+application/x-dvi; xdvizilla %s
+application/x-dvi-tar; xdvizilla %s
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+In addition, it would be useful to check that the following line is included
+in the
+.B mime.types
+file:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+type=application/x-dvi exts="dvi" desc="TeX dvi file"
+.sp 1n
+.ft
+.fi
+.RE
+.SH SEE ALSO
+.BR X (1),
+.BR xdvi (1).
+.SH AUTHOR
+Paul Vojta, U.C. Berkeley.