wdvi

network DVI viewer
Log | Files | Refs

commit 5c1fcbcc49bd74e772e2474a248f40a26eb7c08f
Author: Kyle Milz <milz@black.my.domain>
Date:   Thu,  1 Aug 2019 22:13:22 -0700

xdvi-22.86

Diffstat:
AFAQ | 357+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AINSTALL | 543+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AImakefile | 332+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMAKE-VMS.COM | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile.in | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME.VMS | 483+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AVMS-C.OPT | 2++
AXDVI.RNH | 692+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aacconfig.h | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aaclocal.m4 | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.hin | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.xdvi | 45+++++++++++++++++++++++++++++++++++++++++++++
Aconfigure | 4834+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfigure.in | 388+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Advi-draw.c | 3048+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Advi-init.c | 1030+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Advi.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aevents.c | 5064+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afilefind.c | 2867+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afilefind.h | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afilf-app.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Afont-open.c | 2470+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aft.c | 474+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Agf.c | 328+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainstall-sh | 250+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amksedscript | 236+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apk.c | 363+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apopups.c | 4540+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apsdps.c | 832+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apsgs.c | 916+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apsheader.txt | 297+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apsnews.c | 923+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aspecial.c | 2284+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asqueeze.c | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil.c | 1058+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aversion.h | 1+
Avf.c | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axautocnf.pat | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axautocnf.txt | 16++++++++++++++++
Axdvi-man.sed | 3244+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axdvi.c | 3632+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axdvi.h | 1386+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axdvi.icon | 27+++++++++++++++++++++++++++
Axdvi.lsm | 21+++++++++++++++++++++
Axdvizilla | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Axdvizilla.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 = &pr; + 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 = &not_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 = &not_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 == &not_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 == &not_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 = &not_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 = &not_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.