1 /*
2  * Copyright (c) 2013-2014 the xdvik development team
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
20  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 
24 #include "xdvi-config.h"
25 
26 #include <locale.h>
27 
28 #include <X11/Intrinsic.h>
29 
30 #include "kpathsea/proginit.h"
31 #include "kpathsea/expand.h"
32 
33 #include "xdvi.h"
34 #include "util.h"
35 #include "x_util.h"
36 #include "sfSelFile.h"
37 #include "my-snprintf.h"
38 #include "dvi-init.h"
39 #include "filehist.h"
40 #include "mag.h"
41 #include "message-window.h"
42 #ifdef HAVE_LIBPAPER
43 #include <paper.h>
44 #endif
45 
46 #if FREETYPE
47 # include <ft2build.h>
48 # include FT_FREETYPE_H
49 #endif
50 
51 #define STRINGIFY(x) #x
52 #define TOSTRING(x) STRINGIFY(x)
53 #ifndef XDVI_KPSE_PROG_NAME
54 #define XDVI_KPSE_PROG_NAME xdvi
55 #endif
56 static const char *xdvi_kpse_prog_name = TOSTRING(XDVI_KPSE_PROG_NAME);
57 #undef STRINGIFY
58 #undef TOSTRING
59 
60 #ifdef	PTEX
61 #include <ft2build.h>
62 #include FT_FREETYPE_H
63 #if	HAVE_FONTCONFIG
64 #include <fontconfig/fontconfig.h>
65 #endif	/* HAVE_FONTCONFIG */
66 #endif	/* PTEX */
67 
68 static char XtRBool3[] = "Bool3";	/* resource for Bool3 */
69 
70 /* get these before setting `application_resources' */
71 static XtResource xdvirc_resources[] = {
72     {"noInitFile", "NoInitFile", XtRBoolean, sizeof(Boolean),
73      XtOffsetOf(struct x_resources, no_init_file), XtRString, "false"},
74 };
75 
76 
77 static XrmOptionDescRec options[] = {
78     {"-q",		".noInitFile",		XrmoptionNoArg,		(XPointer)"on"	},
79     {"+q",		".noInitFile",		XrmoptionNoArg,		(XPointer)"off"	},
80     {"-geometry",       ".geometry",	        XrmoptionSepArg,	(XPointer)NULL	},
81 #ifdef MOTIF
82     /* to make `-font' and `-fn' options work, make them an alias for `fontList' */
83     { "-font",		"*fontList",		XrmoptionSepArg,	(XPointer)NULL	},
84     { "-fn",		"*fontList",		XrmoptionSepArg,	(XPointer)NULL	},
85 #endif
86     {"-s",		".shrinkFactor",	XrmoptionSepArg,	(XPointer)NULL	},
87 #ifndef	VMS
88     {"-S",		".densityPercent",	XrmoptionSepArg,	(XPointer)NULL	},
89 #endif
90     {"-density",	".densityPercent",	XrmoptionSepArg,	(XPointer)NULL	},
91     {"-noomega",	".omega",		XrmoptionNoArg,		(XPointer)"off"	},
92     {"+noomega",	".omega",		XrmoptionNoArg,		(XPointer)"on"	},
93 #if COLOR
94     {"-nocolor",	".color",		XrmoptionNoArg,		(XPointer)"off"	},
95     {"+nocolor",	".color",		XrmoptionNoArg,		(XPointer)"on"	},
96 #endif
97 #ifdef GREY
98     {"-nogrey",		".grey",		XrmoptionNoArg,		(XPointer)"off"	},
99     {"+nogrey",		".grey",		XrmoptionNoArg,		(XPointer)"on"	},
100     {"-gamma",		".gamma",		XrmoptionSepArg,	(XPointer)NULL	},
101     {"-nomatchinverted",".matchInverted",	XrmoptionNoArg,	(XPointer)"off"	},
102     {"+nomatchinverted",".matchInverted",	XrmoptionNoArg,	(XPointer)"on"	},
103     /*     {"-invertedfactor", ".invertedFactor",	XrmoptionSepArg,	(XPointer)NULL	}, */
104     {"-install",	".install",		XrmoptionNoArg,		(XPointer)"on"	},
105     {"-noinstall",	".install",		XrmoptionNoArg,		(XPointer)"off"	},
106 #endif
107     {"-rulecolor",	".ruleColor",		XrmoptionSepArg,	(XPointer)NULL	},
108     {"-p",		".pixelsPerInch",	XrmoptionSepArg,	(XPointer)NULL	},
109     {"-margins",	".Margin",		XrmoptionSepArg,	(XPointer)NULL	},
110     {"-sidemargin",	".sideMargin",		XrmoptionSepArg,	(XPointer)NULL	},
111     {"-topmargin",	".topMargin",		XrmoptionSepArg,	(XPointer)NULL	},
112     {"-offsets",	".Offset",		XrmoptionSepArg,	(XPointer)NULL	},
113     {"-xoffset",	".xOffset",		XrmoptionSepArg,	(XPointer)NULL	},
114     {"-yoffset",	".yOffset",		XrmoptionSepArg,	(XPointer)NULL	},
115     {"-paper",		".paper",		XrmoptionSepArg,	(XPointer)NULL	},
116     {"-altfont",	".altFont",		XrmoptionSepArg,	(XPointer)NULL	},
117 #ifdef MKTEXPK
118     {"-nomakepk",	".makePk",		XrmoptionNoArg,		(XPointer)"off"	},
119     {"+nomakepk",	".makePk",		XrmoptionNoArg,		(XPointer)"on"	},
120 #endif
121     {"-mfmode",		".mfMode",		XrmoptionSepArg,	(XPointer)NULL	},
122     {"-editor",		".editor",		XrmoptionSepArg,	(XPointer)NULL	},
123 #if FREETYPE
124     {"-notype1fonts",	".type1",		XrmoptionNoArg,		(XPointer)"off"	},
125     {"+notype1fonts",	".type1",		XrmoptionNoArg,		(XPointer)"on"	},
126 #endif
127 #if HAVE_XI21
128     {"-noxi2scrolling",	".xi2Scrolling",	XrmoptionNoArg,		(XPointer)"off"},
129     {"+noxi2scrolling",	".xi2Scrolling",	XrmoptionNoArg,		(XPointer)"on"},
130 #endif
131     {"-sourceposition",	".sourcePosition",	XrmoptionSepArg,	(XPointer)NULL	},
132     {"-findstring",	".findString",		XrmoptionSepArg,	(XPointer)NULL	},
133     {"-text-encoding",	".textEncoding",	XrmoptionSepArg,	(XPointer)NULL	},
134     {"-unique",		".unique",		XrmoptionNoArg,		(XPointer)"on"	},
135     {"+unique",		".unique",		XrmoptionNoArg,		(XPointer)"off"	},
136     {"-nofork",		".fork",		XrmoptionNoArg,		(XPointer)"off" },
137     {"+nofork",		".fork",		XrmoptionNoArg,		(XPointer)"on"  },
138 #ifdef RGB_ANTI_ALIASING
139     {"-subpixels",	".subPixels",		XrmoptionSepArg,	(XPointer)NULL	},
140 #endif
141     {"-l",		".listFonts",		XrmoptionNoArg,		(XPointer)"on"	},
142     {"+l",		".listFonts",		XrmoptionNoArg,		(XPointer)"off"	},
143     {"-watchfile",	".watchFile",		XrmoptionSepArg,	(XPointer)NULL	},
144     {"-expertmode",	".expertMode",		XrmoptionSepArg,	(XPointer)NULL	},
145     {"-expert",		".expert",		XrmoptionNoArg,		(XPointer)"on"	},
146     {"+expert",		".expert",		XrmoptionNoArg,		(XPointer)"off"	},
147     {"+statusline",	".statusline",		XrmoptionNoArg,		(XPointer)"off"	},
148     {"-statusline",	".statusline",		XrmoptionNoArg,		(XPointer)"on"	},
149     {"+useTeXpages",	".useTeXPages",		XrmoptionNoArg,		(XPointer)"off"	},
150     {"-useTeXpages",	".useTeXPages",		XrmoptionNoArg,		(XPointer)"on"	},
151     {"-mgs",		".magnifierSize1",	XrmoptionSepArg,	(XPointer)NULL	},
152     {"-mgs1",		".magnifierSize1",	XrmoptionSepArg,	(XPointer)NULL	},
153     {"-mgs2",		".magnifierSize2",	XrmoptionSepArg,	(XPointer)NULL	},
154     {"-mgs3",		".magnifierSize3",	XrmoptionSepArg,	(XPointer)NULL	},
155     {"-mgs4",		".magnifierSize4",	XrmoptionSepArg,	(XPointer)NULL	},
156     {"-mgs5",		".magnifierSize5",	XrmoptionSepArg,	(XPointer)NULL	},
157     {"-warnspecials",	".warnSpecials",	XrmoptionNoArg,		(XPointer)"on"	},
158     {"+warnspecials",	".warnSpecials",	XrmoptionNoArg,		(XPointer)"off"	},
159     {"-hush",		".Hush",		XrmoptionNoArg,		(XPointer)"on"	},
160     {"+hush",		".Hush",		XrmoptionNoArg,		(XPointer)"off"	},
161     {"-hushchars",	".hushLostChars",	XrmoptionNoArg,		(XPointer)"on"	},
162     {"+hushchars",	".hushLostChars",	XrmoptionNoArg,		(XPointer)"off"	},
163     {"-hushchecksums",	".hushChecksums",	XrmoptionNoArg,		(XPointer)"on"	},
164     {"+hushchecksums",	".hushChecksums",	XrmoptionNoArg,		(XPointer)"off"	},
165     {"-hushstdout",	".hushStdout",		XrmoptionNoArg,		(XPointer)"on"	},
166     {"+hushstdout",	".hushStdout",		XrmoptionNoArg,		(XPointer)"off"	},
167     {"-hushbell",	".hushBell",		XrmoptionNoArg,		(XPointer)"on"	},
168     {"+hushbell",	".hushBell",		XrmoptionNoArg,		(XPointer)"off"	},
169     {"-safer",		".safer",		XrmoptionNoArg,		(XPointer)"on"	},
170     {"+safer",		".safer",		XrmoptionNoArg,		(XPointer)"off"	},
171     {"-fg",		".foreground",		XrmoptionSepArg,	(XPointer)NULL	},
172     {"-foreground",	".foreground",		XrmoptionSepArg,	(XPointer)NULL	},
173     {"-bg",		".background",		XrmoptionSepArg,	(XPointer)NULL	},
174     {"-background",	".background",		XrmoptionSepArg,	(XPointer)NULL	},
175     {"-hl",		".highlight",		XrmoptionSepArg,	(XPointer)NULL	},
176     {"-cr",		".cursorColor",		XrmoptionSepArg,	(XPointer)NULL	},
177     {"-icongeometry",	".iconGeometry",	XrmoptionSepArg,	(XPointer)NULL	},
178     {"-keep",		".keepPosition",	XrmoptionNoArg,		(XPointer)"on"	},
179     {"+keep",		".keepPosition",	XrmoptionNoArg,		(XPointer)"off"	},
180     {"-copy",		".copy",		XrmoptionNoArg,		(XPointer)"on"	},
181     {"+copy",		".copy",		XrmoptionNoArg,		(XPointer)"off"	},
182     {"-thorough",	".thorough",		XrmoptionNoArg,		(XPointer)"on"	},
183     {"+thorough",	".thorough",		XrmoptionNoArg,		(XPointer)"off"	},
184     {"-fullscreen",	".fullscreen",		XrmoptionNoArg,		(XPointer)"on"	},
185     {"+fullscreen",	".fullscreen",		XrmoptionNoArg,		(XPointer)"off"	},
186     {"-pause",		".pause",		XrmoptionNoArg,		(XPointer)"on"	},
187     {"+pause",		".pause",		XrmoptionNoArg,		(XPointer)"off"	},
188     {"-pausespecial",	".pauseSpecial",	XrmoptionSepArg,	(XPointer)NULL	},
189     {"-wheelunit",	".wheelUnit",		XrmoptionSepArg,	(XPointer)NULL	},
190     {"-mousemode",	".mouseMode",		XrmoptionSepArg,	(XPointer)NULL	},
191 #ifdef PS
192     {"-postscript",	".postscript",		XrmoptionSepArg,	(XPointer)NULL	},
193     {"-allowshell",	".allowShell",		XrmoptionNoArg,		(XPointer)"on"	},
194     {"+allowshell",	".allowShell",		XrmoptionNoArg,		(XPointer)"off"	},
195 # ifdef	PS_DPS
196     {"-nodps",		".dps",			XrmoptionNoArg,		(XPointer)"off"	},
197     {"+nodps",		".dps",			XrmoptionNoArg,		(XPointer)"on"	},
198 # endif
199 # ifdef	PS_NEWS
200     {"-nonews",		".news",		XrmoptionNoArg,		(XPointer)"off"	},
201     {"+nonews",		".news",		XrmoptionNoArg,		(XPointer)"on"	},
202 # endif
203 # ifdef	PS_GS
204     {"-noghostscript",	".ghostscript",		XrmoptionNoArg,		(XPointer)"off"	},
205     {"+noghostscript",	".ghostscript",		XrmoptionNoArg,		(XPointer)"on"	},
206     {"-nogssafer",	".gsSafer",		XrmoptionNoArg,		(XPointer)"off"	},
207     {"+nogssafer",	".gsSafer",		XrmoptionNoArg,		(XPointer)"on"	},
208     {"-gsalpha",	".gsAlpha",		XrmoptionNoArg,		(XPointer)"on"	},
209     {"+gsalpha",	".gsAlpha",		XrmoptionNoArg,		(XPointer)"off"	},
210     {"-interpreter",	".interpreter",		XrmoptionSepArg,	(XPointer)NULL	},
211     {"-gspalette",	".palette",		XrmoptionSepArg,	(XPointer)NULL	},
212 # endif
213 # ifdef	MAGICK
214     {"-magick",		".ImageMagick",		XrmoptionNoArg,		(XPointer)"on"  },
215     {"+magick",		".ImageMagick",		XrmoptionNoArg,		(XPointer)"off" },
216     {"-magick_cache",	".MagickCache",		XrmoptionSepArg,	(XPointer)NULL	},
217 # endif
218 #endif /* PS */
219     {"-noscan",		".prescan",		XrmoptionNoArg,		(XPointer)"off"	},
220     {"+noscan",		".prescan",		XrmoptionNoArg,		(XPointer)"on"	},
221     {"-notempfile",	".tempFile",		XrmoptionNoArg,		(XPointer)"off"	},
222     {"+notempfile",	".tempFile",		XrmoptionNoArg,		(XPointer)"on"	},
223     {"-dvipspath",	".dvipsPath",		XrmoptionSepArg,	(XPointer)NULL	},
224     {"-ps2pdfpath",	".ps2pdfPath",		XrmoptionSepArg,	(XPointer)NULL	},
225     {"-debug",		".debugLevel",		XrmoptionSepArg,	(XPointer)NULL	},
226     {"-linkstyle",	".linkStyle",		XrmoptionSepArg,	(XPointer)NULL	},
227     {"-linkcolor",	".linkColor",		XrmoptionSepArg,	(XPointer)NULL	},
228     {"-visitedlinkcolor",".visitedLinkColor",	XrmoptionSepArg,	(XPointer)NULL	},
229     {"-browser",	".wwwBrowser",		XrmoptionSepArg,	(XPointer)NULL	},
230     {"-anchorposition",	".anchorPosition",	XrmoptionSepArg,	(XPointer)NULL	},
231 };
232 
233 /*
234  * Data for options processing.
235  */
236 static const char SILENT[] = " ";	/* flag value for usage() */
237 static const char SUBST[] = "x";	/* another flag value */
238 static const char USAGESTR_END_MARKER[] = "__USAGE_END_MARKER__"; /* end marker */
239 
240 /* Here, list usage values for options that have `XrmoptionSepArg' set.
241    TODO: what does the `^' stand for?
242 */
243 static const char *usagestr[] = {
244     /* geometry		*/ SILENT,
245 #ifdef MOTIF
246     /* font		*/ SILENT,
247     /* f		*/ SILENT,
248 #endif
249     /* shrinkFactor	*/ "shrink",
250 #ifndef	VMS
251     /* S		*/ "density",
252     /* density		*/ SILENT,
253 #else
254     /* density		*/ "density",
255 #endif
256 #ifdef	GREY
257     /* gamma		*/ "float",
258 #endif
259     /* rulecolor	*/ "color",
260     /* p		*/ "pixels",
261     /* margins		*/ "dimen",
262     /* sidemargin	*/ "dimen",
263     /* topmargin	*/ "dimen",
264     /* offsets		*/ "dimen",
265     /* xoffset		*/ "dimen",
266     /* yoffset		*/ "dimen",
267     /* paper		*/ "papertype",
268     /* altfont		*/ "font",
269     /* mfmode		*/ "mode-def",
270     /* editor		*/ "editor",
271     /* sourceposition	*/ "linenumber[ ]*filename",
272     /* findstring	*/ "string",
273     /* textencoding	*/ "charset",
274 #ifdef RGB_ANTI_ALIASING
275     /* subpixels	*/ "{rgb,bgr}[ i1 i2 i3]",
276 #endif
277     /* rv		*/ "^-l", "-rv",
278     /* watchfile	*/ "secs",
279     /* expertmode	*/ "flag",
280     /* mgs		*/ SUBST,
281     /* mgs1		*/ SILENT,
282     /* mgs2		*/ SILENT,
283     /* mgs3		*/ SILENT,
284     /* mgs4		*/ SILENT,
285     /* mgs5		*/ SILENT,
286     /* fg		*/ "color",
287     /* foreground	*/ SILENT,
288     /* bg		*/ "color",
289     /* background	*/ SILENT,
290     /* hl		*/ "color",
291     /* cr		*/ "color",
292 #ifndef VMS
293     /* display		*/ "^-cr", "-display <host:display>",
294 #else
295     /* display		*/ "^-cr", "-display <host::display>",
296 #endif
297     /* geometry		*/ "^-cr", "-geometry <geometry>",
298     /* icongeometry	*/ "geometry",
299     /* iconic		*/ "^-icongeometry", "-iconic",
300     /* font		*/ "^-icongeometry", "-font <font>",
301     /* pausespecial	*/ "string",
302     /* wheelunit	*/ "pixels",
303     /* mousemode	*/ "0|1|2",
304 #ifdef PS
305     /* postscript	*/ "0|1|2",
306 # ifdef PS_GS
307     /* interpreter	*/ "path",
308     /* gspalette	*/ "monochrome|grayscale|color",
309 # endif
310 # ifdef MAGICK
311     /* magick_cache	*/ "size[k|K|m|M|g|G]",
312 # endif
313 #endif
314     /* dvipspath	*/ "path",
315     /* ps2pdfpath	*/ "path",
316     /* debug		*/ "bitmask|string[,string ...]",
317     /* linkstyle	*/ "0|1|2|3",
318     /* linkcolor	*/ "color",
319     /* visitedlinkcolor	*/ "color",
320     /* browser		*/ "WWWbrowser",
321     /* anchorposition	*/ "anchor",
322     /* [end marker]	*/ USAGESTR_END_MARKER
323 };
324 
325 static const char *SUBST_VAL[] = { "-mgs[n] <size>" };
326 
327 static int
compare_strings(const void * s,const void * t)328 compare_strings(const void *s, const void *t)
329 {
330     const char *const *ss = (const char *const *)s;
331     const char *const *tt = (const char *const *)t;
332 
333     return memicmp(*ss, *tt, strlen(*tt) + 1); /* also check for final 0 */
334 }
335 
336 static void
usage(int exitval)337 usage(int exitval)
338 {
339     XrmOptionDescRec *opt;
340     const char **usageptr = usagestr;
341     const char **sv = SUBST_VAL;
342     const char *str1;
343     const char *str2;
344     const char *sorted_options[XtNumber(options)];
345     char buf[256];
346     char *s;
347     int col, n;
348     size_t nopt = 0, k;
349 
350     for (opt = options; opt < options + XtNumber(options); ++opt) {
351 	str1 = opt->option;
352 	if (*str1 != '-')
353 	    continue;
354 
355 	ASSERT(*usageptr != USAGESTR_END_MARKER, "Too few elements in usageptr[]");
356 
357 	str2 = NULL;
358 	if (opt->argKind != XrmoptionNoArg) {
359 	    str2 = *usageptr++;
360 	    if (str2 == SILENT)
361 		continue;
362 	    if (str2 == SUBST) {
363 		str1 = *sv++;
364 		str2 = NULL;
365 	    }
366 	}
367 #if 0
368 	fprintf(stderr, "str1: %s, str2: %s\n", str1, str2);
369 #endif
370 	for (;;) {
371 	    if (str2 == NULL)
372 		sprintf(buf, "[%.80s]", str1);
373 	    else
374 		sprintf(buf, "[%.80s <%.80s>]", str1, str2);
375 
376 	    /* 	    fprintf(stderr, "number of options: %d; len of usagestr: %d\n", */
377 	    /* 		    XtNumber(options), XtNumber(usagestr)); */
378 	    ASSERT(nopt < XtNumber(options), "index out of range");
379 	    /* 	    fprintf(stderr, "sorted: %d=%s\n", nopt, buf); */
380 	    sorted_options[nopt++] = xstrdup(buf);
381 
382 	    if (**usageptr != '^' || strcmp(*usageptr + 1, opt->option) != 0)
383 		break;
384 	    ++usageptr;
385 	    str1 = *usageptr++;
386 	    str2 = NULL;
387 	}
388     }
389 
390     ASSERT(*usageptr == USAGESTR_END_MARKER, "Too many elements in usageptr[]");
391 
392     /*     fprintf(stderr, "elems in sorted options: %d\n", nopt); */
393     qsort((void*)sorted_options,
394 	  nopt,
395 	  sizeof(sorted_options[0]),
396 	  compare_strings);
397 
398     s = xstrdup("Usage: ");
399     s = xstrcat(s, XDVI_PROGNAME); /* use `xdvi' here, not `xdvik' or `xdvi-xaw.bin' or ... */
400     s = xstrcat(s, " [+[<page>]] [-h | --help] [-v | --version] [-license]");
401 
402     col = strlen(s);
403     fputs(s, stdout);
404 
405     for (k = 0; k < nopt; ++k) {
406 	n = strlen(sorted_options[k]);
407 	if (col + n < 80)
408 	    putc(' ', stdout);
409 	else {
410 	    fputs("\n\t", stdout);
411 	    col = 8 - 1;
412 	}
413 	fputs(sorted_options[k], stdout);
414 	col += n + 1;
415     }
416 
417     /* put this in an extra line, to emphasize that it must come last */
418     fputs("\n\t[dvi_file]\n", stdout);
419 
420     xdvi_exit(exitval);
421 }
422 
423 
424 static void
display_bug_reporting_info(void)425 display_bug_reporting_info(void)
426 {
427     printf("Please send bug reports, feature requests etc. to one of:\n"
428 	   "   http://sourceforge.net/tracker/?group_id=23164&atid=377580\n"
429 	   "   tex-k@tug.org (http://tug.org/mailman/listinfo/tex-k)\n\n"
430 	   "\n");
431 }
432 
433 static void
display_licensing_info(void)434 display_licensing_info(void)
435 {
436     fputs("Licenses: X Consortium license, GNU Library General Public\n"
437 	  "License, GNU General Public License (use option `-license'\n"
438 	  "for more details). There is NO WARRANTY of anything.\n\n", stdout);
439 }
440 
441 static void
display_long_licensing_info(void)442 display_long_licensing_info(void)
443 {
444     fputs("The major parts of Xdvik are licensed under the X Consortium license.\n"
445 	  "Parts (encoding.c) are licensed under the GNU General Public License.\n"
446 	  "Xdvik uses the following libraries:\n"
447 	  "- The kpathsea library, licensed in part under the GNU General Public\n"
448 	  "  License, in part under the GNU Library General Public License.\n"
449 	  "- FreeType2, licensed under the GNU General Public License.\n"
450 	  "There is NO WARRANTY of anything.\n\n", stdout);
451 }
452 
453 static char *
is_good_dvi_file(const char * filename,Boolean from_history)454 is_good_dvi_file(const char *filename, Boolean from_history)
455 {
456     static char canonical_path[MAXPATHLEN + 1];
457     Boolean tried_dvi_extension = False;
458     /* following allocates real_filename */
459     char *real_filename = find_dvi_file(filename, &tried_dvi_extension, from_history);
460     char *ret;
461     FILE *f = NULL;
462     dviErrFlagT errflag;
463 
464     if (real_filename == NULL)
465 	return NULL;
466 
467     if ((ret = REALPATH(real_filename, canonical_path)) == NULL) {
468 	/* REALPATH failed, use real_filename */
469 	strncpy(canonical_path, real_filename, MAXPATHLEN);
470 	canonical_path[MAXPATHLEN] = '\0';
471 	ret = canonical_path;
472     }
473     free(real_filename);
474 
475     /* check for correct DVI files */
476     if ((f = XFOPEN(ret, OPEN_MODE)) != NULL) {
477 	TRACE_EVENTS((stderr, "watching: new file opened successfully."));
478 	if (process_preamble(f, &errflag)
479 	    && find_postamble(f, &errflag)
480 	    && read_postamble(f, &errflag, False
481 #if DELAYED_MKTEXPK
482 			      , False
483 #endif
484 			      )) {
485 	    fclose(f);
486 	    return ret;
487 	}
488 	fclose(f);
489 	if (!from_history)
490 	    XDVI_FATAL((stderr, "%s: %s.", filename, get_dvi_error(errflag)));
491 	return NULL;
492     }
493     else {
494 	if (!from_history)
495 	    XDVI_FATAL((stderr, "Could not open `%s': %s.", filename, strerror(errno)));
496 	return NULL;
497     }
498 }
499 
500 
501 static char *
get_filename_from_history(int * pageno)502 get_filename_from_history(int *pageno)
503 {
504     size_t i;
505     /* loop through history, trying to get a good file */
506     for (i = 0; i < file_history_size(); i++) {
507 	char *ret, *test;
508 
509 	if ((test = file_history_get_elem(i, pageno)) == NULL)
510 	    return NULL;
511 	TRACE_FILES((stderr, "HISTORY %lu: |%s|", (unsigned long)i, test));
512 	if ((ret = is_good_dvi_file(test, True)) != NULL) {
513 	    TRACE_FILES((stderr, "SUCCESS: |%s|", test));
514 	    return ret;
515 	}
516     }
517     return NULL;
518 }
519 
520 static void
warn_about_prerelease_versions(void)521 warn_about_prerelease_versions(void)
522 {
523     int unstable_version = 0;
524     if (strstr(XDVI_VERSION_INFO, "-cvs") != NULL)
525 	unstable_version = 1;
526     else if (strstr(XDVI_VERSION_INFO, "-beta") != NULL)
527 	unstable_version = 2;
528 
529     if (unstable_version > 0) {
530 	printf("\n**********************************************************************\n");
531 	printf("%s version %s,\n%s version.\n\n", XDVIK_PROGNAME, XDVI_VERSION_INFO,
532 	       unstable_version == 1 ? "an unstable development" : "a beta testing");
533 	printf("Want a stable version instead?\n"
534 	       " -> please visit one of:\n"
535 	       "    http://xdvi.sourceforge.net/cvs-upgrade.html\n"
536 	       "    http://sourceforge.net/project/showfiles.php?group_id=23164\n\n"
537 	       "Found a bug?\n"
538 	       " -> please report it to:\n"
539 	       "    http://sourceforge.net/tracker/?group_id=23164&atid=377580\n\n"
540 	       "Thanks for your support!\n");
541 	printf("**********************************************************************\n");
542     }
543 }
544 
545 /*
546   Initialize internal data (most of them global ...) according to the values
547   of resources/command-line arguments, warning user about illegal values
548   etc.
549 */
550 static void
init_check_resources(void)551 init_check_resources(void)
552 {
553     size_t i;
554 
555     if (resource.mfmode != NULL) {
556 	char *p;
557 
558 	p = strrchr(resource.mfmode, ':');
559 	if (p != NULL) {
560 	    unsigned int len;
561 	    char *p1;
562 
563 	    ++p;
564 	    len = p - resource.mfmode;
565 	    p1 = xmalloc(len);
566 	    memcpy(p1, resource.mfmode, len - 1);
567 	    p1[len - 1] = '\0';
568 	    resource.mfmode = p1;
569 	    resource.pixels_per_inch = atoi(p);
570 	}
571     }
572     if (currwin.shrinkfactor < 0) {
573 	XDVI_ERROR((stderr, "Invalid shrink factor: %d.", currwin.shrinkfactor));
574 	usage(EXIT_FAILURE);
575     }
576     if (resource.density <= 0) {
577 	XDVI_ERROR((stderr, "Invalid shrink density: %d.", resource.density));
578 	usage(EXIT_FAILURE);
579     }
580     if (resource.pixels_per_inch <= 0) {
581 	XDVI_ERROR((stderr, "Invalid dpi value: %d.", resource.pixels_per_inch));
582 	usage(EXIT_FAILURE);
583     }
584     if (resource.link_style < 0 || resource.link_style > 3) {
585 	XDVI_ERROR((stderr, "Unrecognized value %d for resource \"linkstyle\" (valid range is 0 - 3); assuming 3.",
586 		    resource.link_style));
587 	resource.link_style = 3;
588     }
589     if (currwin.shrinkfactor > 1) {
590 	mane.shrinkfactor = currwin.shrinkfactor;	/* otherwise it's 1 */
591     }
592 
593 #ifdef RGB_ANTI_ALIASING
594 #warning Note: RGB Anti-aliasing enabled
595     /* subpixel rendering */
596     resource.subpixel_order = SUBPIXEL_NONE;
597     if (resource.sub_pixels != NULL) {
598 	int sum;
599 
600 	if (memicmp(resource.sub_pixels, "rgb", 3) == 0)
601 	    resource.subpixel_order = SUBPIXEL_RGB;
602 	else if (memicmp(resource.sub_pixels, "bgr", 3) == 0)
603 	    resource.subpixel_order = SUBPIXEL_BGR;
604 	else if (memicmp(resource.sub_pixels, "none", 3) == 0)
605 	    resource.subpixel_order = SUBPIXEL_NONE;
606 	else {
607 	    XDVI_ERROR((stderr,
608 			"Unrecognized value \"%s\" for resource subpixels\n"
609 			"(possible values are: \"rgb\" or \"bgr\").",
610 			resource.sub_pixels));
611 	    xdvi_exit(EXIT_FAILURE);
612 	}
613 	/* get the energy distribution */
614 	if (resource.subpixel_order == SUBPIXEL_RGB || resource.subpixel_order == SUBPIXEL_BGR) {
615 	    const char *ptr = resource.sub_pixels + 3;
616 	    while (isspace(*ptr))
617 		ptr++;
618 	    fprintf(stderr, "ptr: |%s|\n", ptr);
619 	    resource.subpixel_energy[0] = 33.333;
620 	    resource.subpixel_energy[1] = 33.333;
621 	    resource.subpixel_energy[2] = 0.0;
622 	    if (*ptr != '\0') {
623 		if (sscanf(ptr, "%f %f %f",
624 			   &(resource.subpixel_energy[0]),
625 			   &(resource.subpixel_energy[1]),
626 			   &(resource.subpixel_energy[2]))
627 		    != 3) {
628 		    XDVI_ERROR((stderr,
629 				"Illegal color mask `%s' for resource subpixels (should be: `n n n')\n",
630 				ptr));
631 		}
632 	    }
633 
634 	    sum = (int)(resource.subpixel_energy[0] +
635 			2 * resource.subpixel_energy[1] +
636 			2 * resource.subpixel_energy[2]);
637 	    if (sum < 99 || sum > 100) {
638 		XDVI_WARNING((stderr, "energy values %f + 2 * %f + 2 * %f don't sum up to 100%%!\n",
639 			      resource.subpixel_energy[0], resource.subpixel_energy[1], resource.subpixel_energy[2]));
640 		exit(1);
641 	    }
642 
643 	    resource.subpixel_energy[0] /= 100.0;
644 	    resource.subpixel_energy[1] /= 100.0;
645 	    resource.subpixel_energy[2] /= 100.0;
646 	    fprintf(stderr, "subpixel order: %s = %d; [%f %f %f]\n",
647 		    resource.sub_pixels, resource.subpixel_order,
648 		    resource.subpixel_energy[0], resource.subpixel_energy[1], resource.subpixel_energy[2]);
649 	}
650     }
651 #endif
652 
653     /* margins */
654     if (resource.sidemargin)
655 	resource.sidemargin_int = atopix(resource.sidemargin, False);
656     if (resource.topmargin)
657 	resource.topmargin_int = atopix(resource.topmargin, False);
658     resource.xoffset_int = resource.xoffset ? atopix(resource.xoffset, True)
659 	: resource.pixels_per_inch;
660     resource.yoffset_int = resource.yoffset ? atopix(resource.yoffset, True)
661 	: resource.pixels_per_inch;
662 
663     /* paper type */
664     if (!set_paper_type(resource.paper)) {
665 	char *helpmsg = xstrdup("Possible paper types are:\n    ");
666 #ifdef HAVE_LIBPAPER
667 	const struct paper *pp;
668 
669 	for (pp = paperfirst(); pp; pp = papernext(pp)) {
670 		helpmsg = xstrcat(helpmsg, papername(pp));
671 		helpmsg = xstrcat(helpmsg, " ");
672 	}
673 #else
674 	const char **p;
675 	const char **paper_types = get_paper_types();
676 	for (p = paper_types; p < paper_types + get_paper_types_size(); p += 2) {
677 	    if (**p == '\0') { /* next line of list */
678 		helpmsg = xstrcat(helpmsg, "\n    ");
679 	    }
680 	    else {
681 		helpmsg = xstrcat(helpmsg, *p);
682 		helpmsg = xstrcat(helpmsg, " ");
683 	    }
684 	}
685 #endif
686 	helpmsg = xstrcat(helpmsg,
687 			  "\n(the names ending with `r' are `rotated' or `landscape' variants).\n"
688 			  "Alternatively, you can specify the dimensions as `WIDTHxHEIGHT', followed "
689 			  "by a dimension unit (one of: pt pc in bp cm mm dd cc sp).");
690 	/* also dump it to stderr ... */
691 	fprintf(stderr,
692 		"Unrecognized value `%s' for paper type option; using %s instead.\n%s\n",
693 		resource.paper, DEFAULT_PAPER, helpmsg);
694 
695 	popup_message(globals.widgets.top_level,
696 		      MSG_WARN, helpmsg,
697 		      "Unrecognized value `%s' for paper type option; using a4 instead.", resource.paper);
698 	set_paper_type(DEFAULT_PAPER);
699     }
700 
701     /* magnifier sizes */
702     for (i = 0; i < get_magglass_items(); ++i) {
703 	if (resource.mg_arg[i] != NULL) {
704 	    char *s;
705 
706 	    int n = atoi(resource.mg_arg[i]);
707 	    set_magglass_widht(i, n);
708 	    set_magglass_height(i, n);
709 	    s = strchr(resource.mg_arg[i], 'x');
710 	    if (s != NULL) {
711 		set_magglass_height(i, atoi(s + 1));
712 		if (get_magglass_height(i) <= 0)
713 		    set_magglass_widht(i, 0);
714 	    }
715 	}
716     }
717 
718 #ifdef PS
719     if (resource.safer) {
720 	resource.allow_shell = False;
721 # ifdef PS_GS
722 	resource.gs_safer = True;
723 # endif /* PS_GS */
724     }
725 # ifdef	PS_GS
726     {
727 	const char *CGMcgm = "CGMcgm";
728 	const char *cgmp;
729 
730 	cgmp = strchr(CGMcgm, resource.gs_palette[0]);
731 	if (cgmp == NULL)
732 	    XDVI_FATAL((stderr, "Invalid value %s for gs palette option", resource.gs_palette));
733 	if (cgmp >= CGMcgm + 3) {
734 	    static char gsp[] = "x";
735 
736 	    gsp[0] = *(cgmp - 3);
737 	    resource.gs_palette = gsp;
738 	}
739     }
740 # endif /* PS_GS */
741 #endif /* PS */
742 
743     /* The old `-expert' flag overrides resource.expert_mode, `+expert' (or not
744        setting it) just uses expert_mode.
745     */
746     if (resource.expert)
747 	resource.expert_mode = XPRT_SHOW_NONE;
748     /*      fprintf(stderr, "++++++++ initializing resource.expert_mode: %d\n", resource.expert_mode); */
749     update_expert_mode();
750 
751     if (resource.hush) {
752 	resource.hush_chars = resource.hush_chk = resource.hush_stdout = resource.hush_bell = True;
753     }
754 }
755 
756 /*
757   a custom error handler that makes it easier to catch X errors in the debugger
758   (by setting a breakpoint to this function, plus using the -sync option).
759   Also, Motif sometimes gives non-fatal errors that we want to ignore ...
760 */
761 static int
x_error_handler(Display * display,XErrorEvent * error)762 x_error_handler(Display *display, XErrorEvent *error)
763 {
764     char buf[1024], req_buf[1024];
765 
766     if (error->request_code < 128) {
767 	char num[LENGTH_OF_INT];
768 	sprintf(num, "%d", error->request_code);
769 	XGetErrorDatabaseText(display, "XRequest", num, "", req_buf, 1024);
770     }
771     else {
772 	req_buf[0] = '\0';
773     }
774 
775     XGetErrorText(display, error->error_code, buf, sizeof buf);
776     /*     XtCloseDisplay(DISP); */
777     if (error->error_code == BadWindow
778 	|| error->error_code == BadPixmap
779 	|| error->error_code == BadCursor
780 	|| error->error_code == BadFont
781 	|| error->error_code == BadDrawable
782 	|| error->error_code == BadColor
783 	|| error->error_code == BadGC
784 	|| error->error_code == BadIDChoice
785 	|| error->error_code == BadValue
786 	|| error->error_code == BadAtom) {
787 	XDVI_WARNING((stderr, "X protocol error: %s\n    X Request %d (%s), Value=0x%x.",
788 		      buf, error->request_code, req_buf, (unsigned int)error->resourceid));
789     }
790     else {
791 	XDVI_WARNING((stderr, "X protocol error: %s\n    X Request %d (%s).",
792 		      buf, error->request_code, req_buf));
793     }
794     return 0;
795 }
796 
797 static void
display_version_info(void)798 display_version_info(void)
799 {
800     printf("%s version %s ", XDVIK_PROGNAME, XDVI_VERSION);
801 #ifdef JPVERSION
802     printf("%s ", JPVERSION);
803 #endif
804 #ifdef MOTIF
805     printf("(%s, runtime version %d.%d)\n",
806 	   /* 	   XmVERSION, XmREVISION, XmUPDATE_LEVEL, */
807 	   XmVERSION_STRING,
808 	   xmUseVersion / 1000, xmUseVersion % 1000);
809 #else
810     printf("%s\n", XDVI_GUI);
811 #endif
812     printf("Libraries: %s", kpathsea_version_string);
813 #ifdef HAVE_LIBPAPER
814     printf(", libpaper");
815 #endif
816 #if FREETYPE
817     printf(", freetype version %d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
818 #endif
819 #ifdef PTEX
820 #if HAVE_FONTCONFIG
821     printf(", fontconfig version %d.%d.%d", FC_MAJOR, FC_MINOR, FC_REVISION);
822 #endif /* HAVE_FONTCONFIG */
823 #endif /* !PTEX */
824     printf("\n");
825 }
826 
827 
828 static void
check_early_arguments(int argc,char ** argv)829 check_early_arguments(int argc, char **argv)
830 {
831     /* This checks arguments that need to work before the X machinery is
832      * started (e.g. if no display is available, or for information that is
833      * needed before the X defaults are evaluated), so the `options' structure
834      * can't be used for them.
835      *
836      * We need to loop through all arguments in case xdvi is aliased,
837      * or called via a shell script (like in teTeX) that adds things
838      * like `-name' at the beginning of the arglist.
839      */
840     int i;
841     Boolean install_err_handler = True;
842 
843     for (i = 1; i < argc; i++) {
844 	if (strcmp(argv[i], "-help") == 0
845 	    || strcmp(argv[i], "-h") == 0
846 	    || strcmp(argv[i], "+help") == 0
847 	    || strcmp(argv[i], "--help") == 0) {
848 	    printf("%s version %s\n", XDVIK_PROGNAME, XDVI_VERSION_INFO);
849 	    printf("A DVI file previewer for the X window system.\n\n");
850 	    display_licensing_info();
851 	    display_bug_reporting_info();
852 	    usage(0);
853 	}
854 	else if (strcmp(argv[i], "-license") == 0) {
855 	    display_long_licensing_info();
856 	    xdvi_exit(EXIT_SUCCESS);
857 	}
858 	else if (strcmp(argv[i], "--version") == 0
859 		 || strcmp(argv[i], "-version") == 0
860 		 || strcmp(argv[i], "-v") == 0) {
861 	    display_version_info();
862 	    xdvi_exit(EXIT_SUCCESS);
863 	}
864 	else if (strcmp(argv[i], "--default-xerr-handler") == 0) { /* hook to disable custom handler */
865 	    install_err_handler = False;
866 	}
867     }
868 
869     if (install_err_handler) {
870 	(void)XSetErrorHandler(x_error_handler);
871     }
872 }
873 
874 /* initialize global variables with default values. */
875 static void
init_globals(void)876 init_globals(void) {
877     globals.program_name = NULL;
878     globals.dvi_name = NULL;
879     globals.cwd = xgetcwd();
880     globals.orig_locale = NULL;
881     globals.debug = 0L;
882     globals.pageno_correct = 1;
883 
884     globals.curr_paper = NULL;
885     globals.curr_editor = NULL;
886     globals.curr_browser = NULL;
887 
888     globals.ev.flags = EV_IDLE;
889     globals.ev.ctr = 0;
890 
891     globals.pausing.num = 0;
892     globals.pausing.num_save = NULL;
893     globals.pausing.flag = False;
894 
895     globals.win_expose.min_x = 0;
896     globals.win_expose.max_x = 0;
897     globals.win_expose.min_y = 0;
898     globals.win_expose.max_y = 0;
899 
900     globals.gc.rule = NULL;
901     globals.gc.fore = NULL;
902     globals.gc.inverted = NULL;
903     globals.gc.high = NULL;
904     globals.gc.linkcolor = NULL;
905     globals.gc.visited_linkcolor = NULL;
906     globals.gc.fore2 = NULL;
907     globals.gc.fore2_bak = NULL;
908     globals.gc.fore2_bak1 = NULL;
909     globals.gc.copy = NULL;
910     globals.gc.ruler = NULL;
911 
912     globals.gc.do_copy = False;
913 
914     globals.cursor.flags = 0;
915 
916     globals.src.fwd_box_page = -1; /* -1 means no box */
917     globals.src.fwd_string = NULL;
918 
919     globals.widgets.top_level = 0;
920     globals.widgets.draw_widget = 0;
921     globals.widgets.draw_background = 0;
922     globals.widgets.clip_widget = 0;
923     globals.widgets.x_bar = 0;
924     globals.widgets.y_bar = 0;
925 #ifdef MOTIF
926     globals.widgets.main_window = 0;
927     globals.widgets.main_row = 0;
928     globals.widgets.tool_bar = 0;
929     globals.widgets.top_row = 0;
930     globals.widgets.menu_bar = 0;
931 #else
932     globals.widgets.vport_widget = 0;
933     globals.widgets.form_widget = 0;
934     globals.widgets.paned = 0;
935 #endif
936 
937     globals.page.w = 0;
938     globals.page.h = 0;
939     globals.page.unshrunk_w = 0;
940     globals.page.unshrunk_h = 0;
941 
942     globals.dvi_file.dirname = NULL;
943     globals.dvi_file.dirlen = 0;
944     globals.dvi_file.bak_fp = NULL;
945     globals.dvi_file.time = 0;
946 
947 #if defined(LESSTIF_VERSION)
948     globals.broken_motif_event_handling = True;
949 #elif defined(MOTIF) /* was: && XmVersion <= 1002 - better use runtime information:*/
950     if (xmUseVersion <= 1002)
951 	globals.broken_motif_event_handling = True;
952     else
953 	globals.broken_motif_event_handling = False;
954 #else
955     globals.broken_motif_event_handling = False;
956 #endif
957 
958 }
959 
960 
961 #ifdef GREY
962 /*
963  * Convert string to yes/no/maybe.  Adapted from the X toolkit.
964  */
965 
966 static Boolean
XdviCvtStringToBool3(Display * dpy,XrmValuePtr args,Cardinal * num_args,XrmValuePtr fromVal,XrmValuePtr toVal,XtPointer * closure_ret)967 XdviCvtStringToBool3(Display *dpy,
968 		     XrmValuePtr args, Cardinal *num_args,
969 		     XrmValuePtr fromVal, XrmValuePtr toVal,
970 		     XtPointer *closure_ret)
971 {
972     String str = (String) fromVal->addr;
973     static Bool3 value;
974 
975     UNUSED(args);
976     UNUSED(num_args);
977     UNUSED(closure_ret);
978 
979     if (memicmp(str, "true", 5) == 0
980 	|| memicmp(str, "yes", 4) == 0
981 	|| memicmp(str, "on", 3) == 0 || memicmp(str, "1", 2) == 0)
982 	value = True;
983 
984     else if (memicmp(str, "false", 6) == 0
985 	     || memicmp(str, "no", 3) == 0
986 	     || memicmp(str, "off", 4) == 0 || memicmp(str, "0", 2) == 0)
987 	value = False;
988 
989     else if (memicmp(str, "maybe", 6) == 0)
990 	value = Maybe;
991 
992     else {
993 	XtDisplayStringConversionWarning(dpy, str, XtRBoolean);
994 	return False;
995     }
996 
997     if (toVal->addr != NULL) {
998 	if (toVal->size < sizeof(Bool3)) {
999 	    toVal->size = sizeof(Bool3);
1000 	    return False;
1001 	}
1002 	*(Bool3 *) (toVal->addr) = value;
1003     }
1004     else
1005 	toVal->addr = (XPointer) & value;
1006 
1007     toVal->size = sizeof(Bool3);
1008     return True;
1009 }
1010 #endif
1011 
1012 /*
1013 ************************************************************
1014 ************************************************************
1015 main routine
1016 ************************************************************
1017 ************************************************************
1018 */
1019 
1020 int
main(int argc,char ** argv)1021 main(int argc, char **argv)
1022 {
1023     int i;
1024     static struct startup_info info;
1025     const char *file_name = NULL;
1026     const char *file_name2 = NULL;
1027 
1028     /* Hack to have command-line options override ~/.xdvirc stuff:
1029      * Parse and merge them again from argv_bak, a copy of the command-line options,
1030      * via XrmParseCommand(). I think the only alternative would be to merge in all
1031      * resources manually instead of using XtInitialize(), similar to what's done in gv,
1032      * but that looks like too much trouble.
1033      */
1034 #define COMMANDLINE_OVERRIDE_HACK 1
1035 
1036 #if COMMANDLINE_OVERRIDE_HACK
1037     int argc_bak;
1038     char **argv_bak;
1039 #endif
1040 
1041     setup_signal_handlers(True); /* catch USR1 early */
1042 
1043     info.file_idx = 0;
1044     info.page_arg = NULL;
1045 
1046     /* BEGIN_TIMER_LOOP; */
1047 
1048     init_globals();
1049 
1050     /*
1051      *      Step 1:  Process command-line options and resources.
1052      */
1053 
1054     globals.program_name = xstrdup(argv[0]);
1055     {   /* get filename from program_name if it contains a path */
1056 	char sep;
1057 	char *ptr;
1058 #ifdef	VMS
1059 	sep = ']';
1060 #else
1061 	sep = '/';
1062 #endif
1063 	if ((ptr = strrchr(globals.program_name, sep)) != NULL) {
1064 	    globals.program_name = ++ptr;
1065 	}
1066 #ifdef	VMS
1067 	if ((ptr = strchr(globals.program_name, '.')) != NULL)
1068 	    *ptr = '\0';
1069 #endif
1070     }
1071 
1072 #if COMMANDLINE_OVERRIDE_HACK
1073     /* create a copy of argv[] */
1074     argc_bak = argc;
1075     argv_bak = xmalloc((1 + argc_bak) * sizeof *argv_bak);
1076     for (i = 0; i < argc_bak; i++) {
1077 	argv_bak[i] = xstrdup(argv[i]);
1078     }
1079     argv_bak[i] = NULL;
1080 #endif
1081 
1082     /*
1083       Arguments that need to be checked early, like `help', `version' and `sync'.
1084       The former don't even require an X connection.
1085     */
1086     check_early_arguments(argc, argv);
1087 
1088     warn_about_prerelease_versions();
1089 
1090     /* We need to set up SIGALRM before calling XtAppAddTimeOut() (inside sfSelFile, or
1091        called from XtInitialize() in Motif), otherwise we'll die with the error message
1092        `Alarm clock'. However, we mustn't install SIGPOLL before the forking is done
1093        below, otherwise xdvi may hang forever waiting for input. So the signal handler setup
1094        is split in 2 parts: setup_sigalarm(), and setup_signal_handlers() below.
1095     */
1096     setup_sigalarm();
1097 
1098     /* get the debug value (if any) from the environment
1099        (it's too early to get it from the command line) */
1100     globals.debug = parse_debugging_option(getenv("XDVIDEBUG"));
1101 
1102     /* to make input of non-latin characters work */
1103     XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL);
1104 
1105     globals.widgets.top_level = XtInitialize(globals.program_name, "XDvi", options, XtNumber(options),
1106 					     &argc, argv);
1107 
1108     globals.app = XtWidgetToApplicationContext(globals.widgets.top_level);
1109 
1110     XtAppAddActions(globals.app, get_actions(), get_num_actions());
1111 
1112     /*     create_magnifier(); */
1113 
1114     if ((globals.orig_locale = setlocale(LC_ALL, "")) != NULL)
1115 	globals.orig_locale = xstrdup(globals.orig_locale); /* note: never free'd */
1116     else /* fallback */
1117 	globals.orig_locale = xstrdup(setlocale(LC_ALL, NULL));
1118 
1119     /* Override LC_NUMERIC, otherwise sscanf(), strtod() etc. won't work for floats
1120        inside specials for locales like LANG=de_DE which uses `,' instead of `.' as
1121        decimal separator. (Strangely, using
1122        LC_CTYPE | LC_COLLATE
1123        doesn't work?)
1124        Regression:
1125        xdvik/regression/special-pics/pictest.dvi
1126     */
1127     setlocale(LC_NUMERIC, "C");
1128 
1129     /* at this point, all known options will have been consumed; so the
1130        only ones remaining should be: +pageno, and the dvi name. Exit with
1131        usage message if this is not the case. The convention is that the last
1132        argument is always treated as filename (even if it starts with '-'),
1133        so we throw an error if there's more than one unknown argument at the end.
1134     */
1135     for (i = 1; i < argc; i++) { /* skip argv[0] */
1136 	if (*(argv[i]) == '+') {
1137 	    if (info.page_arg != NULL) {
1138 		XDVI_ERROR((stderr, "Unrecognized option `%s'.", argv[i]));
1139 		usage(EXIT_FAILURE);
1140 	    }
1141 	    else {
1142 		info.page_arg = argv[i] + 1;
1143 	    }
1144 	}
1145 	else if (file_name == NULL) {
1146 	    file_name = xstrdup(argv[i]); /* leaks, but never mind ... */
1147 	}
1148 	else {
1149 	    /* we had already seen a filename */
1150 	    XDVI_ERROR((stderr, "Unrecognized option `%s'.", argv[i - 1])); /* safe because we started at argv[1] */
1151 	    usage(EXIT_FAILURE);
1152 	}
1153     }
1154 
1155     DISP = XtDisplay(globals.widgets.top_level);
1156     SCRN = XtScreen(globals.widgets.top_level);
1157 
1158 #ifdef GREY
1159     XtSetTypeConverter(XtRString, XtRBool3, XdviCvtStringToBool3,
1160 		       NULL, 0, XtCacheNone, NULL);
1161 #endif
1162 
1163 #ifdef MOTIF
1164     /* we'll take care of that ourselves */
1165     XtVaSetValues(globals.widgets.top_level, XmNdeleteResponse, XmDO_NOTHING, NULL);
1166 
1167     {
1168 	/* Hack to work around #884290 (drag&drop freezes file selector, see comment
1169 	   in xm_filesel.c): Disable drag&drop altogether (we don't need it).
1170 	   Could also be done via Xdefaults as follows:
1171 	   XDvi*dragInitiatorProtocolStyle: XmDRAG_NONE
1172 	   XDvi*dragReceiverProtocolStyle:  XmDRAG_NONE
1173 	*/
1174 	Widget display = XmGetXmDisplay(DISP);
1175 	XtVaSetValues(display,
1176 		      XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
1177 		      XmNdragReceiverProtocolStyle,  XmDRAG_NONE,
1178 		      NULL);
1179     }
1180 #else
1181     G_accels_cr = XtParseAcceleratorTable("<Key>Return:set()notify()unset()\n"
1182 					  "<Key>q:set()notify()unset()\n"
1183 					  "<Key>Escape: set()notify()unset()");
1184 #endif
1185 
1186     /* get the no_init_file resource first: This needs to be done
1187      * before the call to XtGetApplicationResources() below, which populates
1188      * the `resource' struct with the actual application resources (which
1189      * may be merged from ~/.xdvirc). */
1190     XtGetApplicationResources(globals.widgets.top_level, (XtPointer)&resource,
1191 			      xdvirc_resources, XtNumber(xdvirc_resources),
1192 			      (ArgList)NULL, 0);
1193 
1194     if (!resource.no_init_file) { /* Read user preferences from ~/.xdvirc. */
1195 	read_user_preferences(globals.widgets.top_level, ".xdvirc");
1196     }
1197 
1198 #if COMMANDLINE_OVERRIDE_HACK /* see above */
1199     {
1200 	XrmDatabase cmdline_db = XrmGetDatabase(DISP);
1201 	XrmParseCommand(&cmdline_db, options, XtNumber(options),
1202 			"xdvi", &argc_bak, argv_bak);
1203 
1204 	for (i = 0; i < argc_bak; i++) {
1205 	    free(argv_bak[i]);
1206 	}
1207 	free(argv_bak);
1208 	argc_bak = 0;
1209     }
1210 #endif /* COMMANDLINE_OVERRIDE_HACK */
1211 
1212     load_app_resources(False);
1213 
1214     /* musn't do this, 0 is 'fit to window' (bug #1454648) */
1215     /*     if (resource.shrinkfactor == 0) /\* protect against division by 0 *\/ */
1216     /* 	resource.shrinkfactor = 1; */
1217     currwin.shrinkfactor = resource.shrinkfactor;
1218     globals.curr_use_color = resource.use_color;
1219     globals.curr_gamma = resource.gamma;
1220     globals.curr_paper = xstrdup(resource.paper); /* never free()d */
1221     globals.curr_editor = NULL;
1222     globals.curr_browser = NULL;
1223     globals.curr_mode = NO_MODE_ACTIVE;
1224 
1225     /* Initialize `globals.debug' as early as possible.  Note: earlier
1226      * calls to TRACE_* or tests for `if (globals.debug)' will only work if the
1227      * XDVIDEBUG environment variable is set!
1228      */
1229     globals.debug |= parse_debugging_option(resource.debug_arg);
1230     kpathsea_debug = globals.debug / DBG_STAT;
1231 
1232     if (globals.debug)
1233 	fprintf(stderr, "KPATHSEA_DEBUG = %d\n", kpathsea_debug);
1234 
1235     kpse_init_prog("XDVI", resource.pixels_per_inch, resource.mfmode, resource.alt_font);
1236 
1237     TRACE_FILES((stderr, "Initializing kpathsearch with program name '%s'",
1238 		 xdvi_kpse_prog_name));
1239     kpse_set_program_name(argv[0], xdvi_kpse_prog_name);
1240 
1241     if (globals.debug & DBG_EXPAND) {
1242 	const char *texmfcnf = kpse_path_expand("$TEXMFCNF");
1243 	const char *texmfmain = kpse_path_expand("$TEXMFMAIN");
1244 	fprintf(stderr, "\n%s:%d: KPATHSEA variables:\n", __FILE__, __LINE__);
1245 	fprintf(stderr, "%s:%d: SELFAUTOLOC=\"%s\"\n", __FILE__, __LINE__, getenv("SELFAUTOLOC"));
1246 	fprintf(stderr, "%s:%d: SELFAUTODIR=\"%s\"\n", __FILE__, __LINE__, getenv("SELFAUTODIR"));
1247 	fprintf(stderr, "%s:%d: SELFAUTOPARENT=\"%s\"\n", __FILE__, __LINE__, getenv("SELFAUTOPARENT"));
1248  	fprintf(stderr, "%s:%d: TEXMFCNF=\"%s\"\n", __FILE__, __LINE__, texmfcnf);
1249  	fprintf(stderr, "%s:%d: TEXMFMAIN=\"%s\"\n\n", __FILE__, __LINE__, texmfmain);
1250     }
1251 
1252     if (resource.regression) {
1253 	/* currently it just turns on everything; what we'd like here is
1254 	   output that's usable for automatic diffs (e.g. independent
1255 	   of window manager state) */
1256 	globals.debug = DBG_ALL;
1257     }
1258 
1259     /* Check early for whether to pass off to a different xdvi process
1260      * (-sourceposition argument for reverse source special lookup).
1261      */
1262     property_initialize();
1263 
1264 #if 0 /*  def RGB_ANTI_ALIASING */
1265     /* error checking and setting of resources according to command line arguments */
1266     if (resource.sub_pixels != NULL && memicmp(resource.sub_pixels, "unknown", 4) == 0) {
1267 #ifdef __GNUC__
1268 #warning TODO: implement callbacks
1269 #endif
1270 	choice_dialog_sized(globals.widgets.top_level,
1271 			    MSG_QUESTION,
1272 			    SIZE_MEDIUM,
1273 			    NULL,
1274 #ifndef MOTIF
1275 			    NULL, /* TODO: xaw ret_action_str */
1276 #endif
1277 			    NULL, NULL, /* pre callback */
1278 			    "Enable", NULL, NULL,
1279 			    "Disable", NULL, NULL,
1280 			    "This version of xdvi can optimize the anti-aliased font display "
1281 			    "when running on an LCD monitor, such as a notebook screen or a TFT flat screen."
1282 			    "\n\n"
1283 			    "If you are using such a monitor, click `Enable' to enable optimized display; otherwise click `Disable'."
1284 			    "\n\n"
1285 			    "You can change this setting later via the Menu `Options -> Anti-Aliasing'.");
1286 	/* enter event loop */
1287 	do_pages();
1288     }
1289     else {
1290 #endif
1291 	init_check_resources();
1292 
1293 	TRACE_FILES((stderr, "file history: |%s|", resource.file_history));
1294 	file_history_init();
1295 
1296 #if !DELAYED_MKTEXPK
1297     /* Notify users that fonts might be created. This is just a hack
1298        and no replacement for true asynchronous font creation since it
1299        doesn't give details (is just invoked if startup takes somewhat
1300        longer) and freezes during font creation.
1301     */
1302 /* 	register_font_popup(); */
1303 #endif
1304 
1305 	if (file_name == NULL) { /* no filename argument */
1306 
1307 	    if (resource.no_file_arg_use_history) {
1308 		static char buf[LENGTH_OF_INT]; /* so that we can pass its address */
1309 		int pageno;
1310 		if ((file_name = get_filename_from_history(&pageno)) != NULL) {
1311 		    SNPRINTF(buf, LENGTH_OF_INT, "%d", pageno + 1); /* pageno is 0-based */
1312 		    info.page_arg = buf;
1313 		}
1314 	    }
1315 
1316 	    TRACE_FILES((stderr, "got from history: |%s|", file_name));
1317 
1318 	    if (file_name != NULL) {
1319 		run_dvi_file(file_name, &info);
1320 	    }
1321 	    else { /* get filename from file selector */
1322 		/* static so that we can pass its address */
1323 		static struct filesel_callback cb = {
1324 		    NULL, NULL, "Xdvi: Open file", "Open file:", "OK", "Cancel",
1325 		    NULL, "*.dvi", True, True, NULL, NULL
1326 		};
1327 		cb.func_ptr = run_dvi_file;
1328 		cb.data = &info;
1329 		cb.browse_fname = xt_strdup(globals.cwd);
1330 
1331 		if (cb.shell == NULL)
1332 		    cb.shell = XsraSelFile(globals.widgets.top_level, &cb);
1333 		XsraSelFilePopup(&cb);
1334 		/* enter event loop */
1335 		do_pages();
1336 	    }
1337 	}
1338 	else if ((file_name2 = is_good_dvi_file(file_name, False)) != NULL) {
1339 	    run_dvi_file(file_name2, &info);
1340 	}
1341 #if 0 /*  def RGB_ANTI_ALIASING */
1342     }
1343 #endif
1344     /* notreached */
1345     return 0;
1346 }
1347