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