w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

automatic.cc
Go to the documentation of this file.
1 /* automatic.{cc,hh} -- code for automatic mode and interfacing with kpathsea
2  *
3  * Copyright (c) 2003-2019 Eddie Kohler
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version. This program is distributed in the hope that it will be
9  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11  * Public License for more details.
12  */
13 
14 #include <config.h>
15 #include "automatic.hh"
16 #include "kpseinterface.h"
17 #include "util.hh"
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #if HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #if HAVE_SYS_TIME_H
29 # include <sys/time.h>
30 #endif
31 #if HAVE_SYS_WAIT_H
32 # include <sys/wait.h>
33 #endif
34 #include <lcdf/error.hh>
35 #include <lcdf/straccum.hh>
36 #if HAVE_FCNTL_H
37 # include <fcntl.h>
38 #endif
39 #include <algorithm>
40 
41 #ifdef WIN32
42 # include <io.h>
43 # include <direct.h>
44 # define mkdir(dir, access) _mkdir(dir)
45 # define COPY_CMD "copy"
46 # define CMD_SEP "&"
47 #else
48 # define COPY_CMD "cp"
49 # define CMD_SEP ";"
50 #endif
51 
52 /* kpathsea may already have defined this */
53 #ifndef DEV_NULL
54 # ifdef WIN32
55 # define DEV_NULL "NUL"
56 # else
57 # define DEV_NULL "/dev/null"
58 # endif
59 #endif
60 
61 #if HAVE_AUTO_T1DOTLESSJ
62 enum { T1DOTLESSJ_EXIT_J_NODOT = 2 };
63 #endif
64 
67 static String vendor;
69 #define DEFAULT_VENDOR "lcdftools"
70 #define DEFAULT_TYPEFACE "unknown"
71 
72 static const struct {
73  const char *name;
74  const char *envvar;
75  const char *texdir;
76 } odir_info[] = {
77  { "encoding", "ENCODINGDESTDIR", "#fonts/enc/dvips/@#dvips/@" },
78  { "TFM", "TFMDESTDIR", "fonts/tfm/%" },
79  { "PL", "PLDESTDIR", "fonts/pl/%" },
80  { "VF", "VFDESTDIR", "fonts/vf/%" },
81  { "VPL", "VPLDESTDIR", "fonts/vpl/%" },
82  { "Type 1", "T1DESTDIR", "fonts/type1/%" },
83  { "DVIPS map", "DVIPS directory", "#fonts/map/dvips/@#dvips/@" },
84  { "DVIPS updmap", "DVIPS directory", "dvips" },
85  { "TrueType", "TTFDESTDIR", "fonts/truetype/%" },
86  { "OpenType", "OPENTYPEDESTDIR", "fonts/opentype/%" },
87  { "Type 42", "T42DESTDIR", "fonts/type42/%" }
88 };
89 
90 #if HAVE_KPATHSEA
91 static String odir_kpathsea[NUMODIR];
92 
93 static bool writable_texdir_tried = false;
94 static String writable_texdir; // always ends with directory separator
95 static int tds_1_1 = -1;
96 
97 static bool mktexupd_tried = false;
98 static String mktexupd;
99 
100 static String
101 kpsei_string(char* x)
102 {
103  String s(x);
104  free((void*)x);
105  return s;
106 }
107 
108 static void
109 look_for_writable_texdir(const char *path_variable, bool create)
110 {
111  String path = kpsei_string(kpsei_path_expand(path_variable));
112  while (path && !writable_texdir) {
113  const char* colon = std::find(path.begin(), path.end(), kpsei_env_sep_char);
114  String texdir = path.substring(path.begin(), colon);
115  path = path.substring(colon + 1, path.end());
116  if (access(texdir.c_str(), W_OK) >= 0)
117  writable_texdir = texdir;
118  else if (create && errno != EACCES && mkdir(texdir.c_str(), 0777) >= 0)
119  // create file if it doesn't exist already
120  writable_texdir = texdir;
121  }
122  if (writable_texdir && writable_texdir.back() != '/')
123  writable_texdir += "/";
124 }
125 
126 static void
127 find_writable_texdir(ErrorHandler *errh, const char *)
128 {
129 #if defined(W32TEX)
130 // W32TeX does not have TEXMFVAR
131  char *p = kpsei_var_value("TEXMFVAR");
132  if (p == NULL) // W32TeX
133  look_for_writable_texdir("$TEXMFLOCAL", true);
134  else { // TeXLive
135  free (p);
136  look_for_writable_texdir("$TEXMFVAR", true);
137  }
138 #else
139  look_for_writable_texdir("$TEXMFVAR", true);
140 #endif
141  if (!writable_texdir)
142  look_for_writable_texdir("$VARTEXMF", false);
143  if (!writable_texdir)
144  look_for_writable_texdir("$TEXMF", false);
145  if (!writable_texdir) {
146  errh->warning("no writable directory found in $TEXMFVAR or $TEXMF");
147  errh->message("(You probably need to set your TEXMF environment variable; see\n\
148 the manual for more information. The current TEXMF path is\n\
149 %<%s%>.)", kpsei_string(kpsei_path_expand("$TEXMF")).c_str());
150  }
151  writable_texdir_tried = true;
152 }
153 
154 static String
155 get_vendor()
156 {
157  return (vendor ? vendor : String(DEFAULT_VENDOR));
158 }
159 
160 static String
161 get_typeface()
162 {
164 }
165 #endif
166 
167 bool
169 {
170  bool had = (bool) vendor;
171  vendor = s;
172  return !had;
173 }
174 
175 bool
176 set_typeface(const String &s, bool override)
177 {
178  bool had = (bool) typeface;
179  if (!had || override)
180  typeface = s;
181  return !had;
182 }
183 
184 String
186 {
187  assert(o >= 0 && o < NUMODIR);
188 
189  if (!odir[o] && automatic && odir_info[o].envvar)
190  odir[o] = getenv(odir_info[o].envvar);
191 
192 #if HAVE_KPATHSEA
193  if (!odir[o] && automatic && !writable_texdir_tried)
194  find_writable_texdir(errh, odir_info[o].name);
195 
196  if (!odir[o] && automatic && writable_texdir) {
197  String suffix = odir_info[o].texdir;
198 
199  // May need to behave differently on TDS 1.1 rather than TDS 1.0.
200  if (suffix[0] == '#') {
201  // check type of TDS
202  if (tds_1_1 < 0) {
203  // using a procedure suggested by Olaf Weber
204  String encfonts = kpsei_string(kpsei_path_expand("$TEXMFMAIN/fonts/enc"));
205  if (!encfonts)
206  encfonts = kpsei_string(kpsei_path_expand("$TEXMFDIST/fonts/enc"));
207  tds_1_1 = (encfonts != String());
208  }
209  if (tds_1_1 == 0)
210  suffix = suffix.substring(std::find(suffix.begin() + 1, suffix.end(), '#') + 1, suffix.end());
211  else
212  suffix = suffix.substring(suffix.begin() + 1, std::find(suffix.begin() + 1, suffix.end(), '#'));
213  }
214 
215  String dir = writable_texdir + suffix;
216 
217  if (dir.back() == '%')
218  dir = dir.substring(0, -1) + get_vendor() + "/" + get_typeface();
219  else if (dir.back() == '@')
220  dir = dir.substring(0, -1) + get_vendor();
221 
222  // create parent directories as appropriate
223  int slash = writable_texdir.length() - 1;
224  while (access(dir.c_str(), F_OK) < 0 && slash < dir.length()) {
225  if ((slash = dir.find_left('/', slash + 1)) < 0)
226  slash = dir.length();
227  String subdir = dir.substring(0, slash);
228  if (access(subdir.c_str(), F_OK) < 0
229  && !no_create
230  && mkdir(subdir.c_str(), 0777) < 0)
231  goto kpathsea_done;
232  }
233 
234  // that's our answer
235  odir[o] = dir;
236  odir_kpathsea[o] = dir;
237  }
238  kpathsea_done:
239 #endif
240 
241  if (!odir[o]) {
242  if (automatic) {
243  errh->warning("%s not specified, placing %s files in %<.%>", odir_info[o].envvar, odir_info[o].name);
244 #if !HAVE_KPATHSEA
245  static int kpathsea_warning = 0;
246  if (++kpathsea_warning == 1)
247  errh->message("(This version of otftotfm lacks $TEXMF directory support.)");
248 #endif
249  }
250  odir[o] = ".";
251  }
252 
253  while (odir[o].length() && odir[o].back() == '/')
254  odir[o] = odir[o].substring(0, -1);
255 
256  if (verbose)
257  errh->message("placing %s files in %<%s%>", odir_info[o].name, odir[o].c_str());
258  return odir[o];
259 }
260 
261 void
262 setodir(int o, const String &value)
263 {
264  assert(o >= 0 && o < NUMODIR);
265  odir[o] = value;
266 }
267 
268 const char *
269 odirname(int o)
270 {
271  if (o == NUMODIR) {
272  return "default";
273  } else {
274  assert(o >= 0 && o < NUMODIR);
275  return odir_info[o].name;
276  }
277 }
278 
279 #if HAVE_KPATHSEA
280 static bool
281 file_in_kpathsea_odir(int o, const String &file)
282 {
283  return odir_kpathsea[o]
284  && file.length() > odir[o].length()
285  && memcmp(file.data(), odir[o].data(), odir[o].length()) == 0
286  && file[odir[o].length()] == '/';
287 }
288 #endif
289 
290 void
292 {
293  assert(o >= 0 && o < NUMODIR);
294 #if HAVE_KPATHSEA
295  if (file.find_left('/') < 0)
296  file = odir[o] + "/" + file;
297 
298  // exit if this directory was not found via kpathsea, or the file is not
299  // in the kpathsea directory
300  if (!file_in_kpathsea_odir(o, file))
301  return;
302 
303  assert(writable_texdir && writable_texdir.length() <= odir[o].length()
304  && memcmp(file.data(), writable_texdir.data(), writable_texdir.length()) == 0);
305 
306  // divide the filename into portions
307  // file == writable_texdir + directory + file
308  file = file.substring(writable_texdir.length());
309  while (file && file[0] == '/')
310  file = file.substring(1);
311  int last_slash = file.find_right('/');
312  String directory = (last_slash >= 0 ? file.substring(0, last_slash) : String());
313  file = file.substring(last_slash >= 0 ? last_slash + 1 : 0);
314  if (!file) // no filename to update
315  return;
316 
317  // return if nocreate
318  if (no_create) {
319  errh->message("would update %sls-R for %s/%s", writable_texdir.c_str(), directory.c_str(), file.c_str());
320  return;
321  } else if (verbose)
322  errh->message("updating %sls-R for %s/%s", writable_texdir.c_str(), directory.c_str(), file.c_str());
323 
324  // try to update ls-R ourselves, rather than running mktexupd --
325  // mktexupd's runtime is painful: a half second to update a file
326  String ls_r = writable_texdir + "ls-R";
327  bool success = false;
328  if (access(ls_r.c_str(), R_OK) >= 0) // make sure it already exists
329  if (FILE *f = fopen(ls_r.c_str(), "ab")) {
330  fprintf(f, "./%s:\n%s\n", directory.c_str(), file.c_str());
331  success = true;
332  fclose(f);
333  }
334 
335  // otherwise, run mktexupd
336  if (!success && writable_texdir.find_left('\'') < 0 && directory.find_left('\'') < 0 && file.find_left('\'') < 0) {
337  // look for mktexupd script
338  if (!mktexupd_tried) {
339 #ifdef _WIN32
340  mktexupd = "mktexupd.exe";
341 #else
342  mktexupd = kpsei_string(kpsei_find_file("mktexupd", KPSEI_FMT_WEB2C));
343 #endif
344  mktexupd_tried = true;
345  }
346 
347  // run script
348  if (mktexupd) {
349  String command = mktexupd + " " + shell_quote(writable_texdir + directory) + " " + shell_quote(file);
350  int retval = system(command.c_str());
351  if (retval == 127)
352  errh->error("could not run %<%s%>", command.c_str());
353  else if (retval < 0)
354  errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
355  else if (retval != 0)
356  errh->error("%<%s%> failed", command.c_str());
357  }
358  }
359 #else
360  (void) file, (void) errh;
361 #endif
362 }
363 
364 bool
366 {
367  bool had = (bool) map_file;
368  map_file = s;
369  return !had;
370 }
371 
372 String
373 installed_type1(const String &otf_filename, const String &ps_fontname, bool allow_generate, ErrorHandler *errh)
374 {
375  (void) otf_filename, (void) allow_generate, (void) errh;
376 
377  if (!ps_fontname)
378  return String();
379 
380 #if HAVE_KPATHSEA
381 # if HAVE_AUTO_CFFTOT1
382  if (!(force && allow_generate && otf_filename && otf_filename != "-" && getodir(O_TYPE1, errh))) {
383 # endif
384  // look for .pfb and .pfa
385  String file, path;
386  if ((file = ps_fontname + ".pfb", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))
387  || (file = ps_fontname + ".pfa", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))) {
388  if (path == "./" + file || path == file) {
389  if (verbose)
390  errh->message("ignoring Type 1 file %s found with kpathsea in %<.%>", path.c_str());
391  } else {
392  if (verbose)
393  errh->message("Type 1 file %s found with kpathsea at %s", file.c_str(), path.c_str());
394  return path;
395  }
396  }
397 # if HAVE_AUTO_CFFTOT1
398  }
399 # endif
400 #endif
401 
402 #if HAVE_AUTO_CFFTOT1
403  // if not found, and can generate on the fly, run cfftot1
404  if (allow_generate && otf_filename && otf_filename != "-" && getodir(O_TYPE1, errh)) {
405  String pfb_filename = odir[O_TYPE1] + "/" + ps_fontname + ".pfb";
406  if (pfb_filename.find_left('\'') >= 0 || otf_filename.find_left('\'') >= 0)
407  return String();
408  String command = "cfftot1 " + shell_quote(otf_filename) + " -n " + shell_quote(ps_fontname) + " " + shell_quote(pfb_filename);
409  int retval = mysystem(command.c_str(), errh);
410  if (retval == 127)
411  errh->error("could not run %<%s%>", command.c_str());
412  else if (retval < 0)
413  errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
414  else if (retval != 0)
415  errh->error("%<%s%> failed", command.c_str());
416  if (retval == 0) {
417  update_odir(O_TYPE1, pfb_filename, errh);
418  return pfb_filename;
419  }
420  }
421 #endif
422 
423  return String();
424 }
425 
426 String
427 installed_type1_dotlessj(const String &otf_filename, const String &ps_fontname, bool allow_generate, ErrorHandler *errh)
428 {
429  (void) otf_filename, (void) allow_generate, (void) errh;
430 
431  if (!ps_fontname)
432  return String();
433  if (verbose)
434  errh->message("searching for dotless-j font for %s", ps_fontname.c_str());
435 
436  String j_ps_fontname = ps_fontname + "LCDFJ";
437 
438 #if HAVE_KPATHSEA
439 # if HAVE_AUTO_T1DOTLESSJ
440  if (!(force && allow_generate && getodir(O_TYPE1, errh))) {
441 # endif
442  // look for existing .pfb or .pfa
443  String file, path;
444  if ((file = j_ps_fontname + ".pfb", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))
445  || (file = j_ps_fontname + ".pfa", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE1)))) {
446  // ignore versions in the current directory
447  if (path == "./" + file || path == file) {
448  if (verbose)
449  errh->message("ignoring Type 1 file %s found with kpathsea in %<.%>", path.c_str());
450  } else {
451  if (verbose)
452  errh->message("Type 1 file %s found with kpathsea at %s", file.c_str(), path.c_str());
453  return path;
454  }
455  }
456 # if HAVE_AUTO_T1DOTLESSJ
457  }
458 # endif
459 #endif
460 
461 #if HAVE_AUTO_T1DOTLESSJ
462  // if not found, and can generate on the fly, try running t1dotlessj
463  if (allow_generate && getodir(O_TYPE1, errh)) {
464  if (String base_filename = installed_type1(otf_filename, ps_fontname, allow_generate, errh)) {
465  String pfb_filename = odir[O_TYPE1] + "/" + j_ps_fontname + ".pfb";
466  if (pfb_filename.find_left('\'') >= 0 || base_filename.find_left('\'') >= 0)
467  return String();
468  String command = "t1dotlessj " + shell_quote(base_filename) + " -n " + shell_quote(j_ps_fontname) + " " + shell_quote(pfb_filename);
469  int retval = mysystem(command.c_str(), errh);
470  if (retval == 127)
471  errh->warning("could not run %<%s%>", command.c_str());
472  else if (retval < 0)
473  errh->warning("could not run %<%s%>: %s", command.c_str(), strerror(errno));
474  else if (WEXITSTATUS(retval) == T1DOTLESSJ_EXIT_J_NODOT)
475  return String("\0", 1);
476  else if (retval != 0)
477  errh->warning("%<%s%> failed (%d)", command.c_str(), retval);
478  if (retval == 0) {
479  update_odir(O_TYPE1, pfb_filename, errh);
480  return pfb_filename;
481  } else
482  errh->warning("output font will not contain a dotless-j character");
483  }
484  }
485 #endif
486 
487  return String();
488 }
489 
490 String
491 installed_truetype(const String &ttf_filename, bool allow_generate, ErrorHandler *errh)
492 {
493  String file = pathname_filename(ttf_filename);
494 
495 #if HAVE_KPATHSEA
496  if (!(force && allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TRUETYPE, errh))) {
497  if (String path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TRUETYPE))) {
498  if (path == "./" + file || path == file) {
499  if (verbose)
500  errh->message("ignoring TrueType file %s found with kpathsea in %<.%>", path.c_str());
501  } else {
502  if (verbose)
503  errh->message("TrueType file %s found with kpathsea at %s", file.c_str(), path.c_str());
504  return path;
505  }
506  }
507  }
508 #endif
509 
510  // perhaps generate type 42 in the future, for now just copy
511  if (allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TRUETYPE, errh)) {
512  String installed_ttf_filename = odir[O_TRUETYPE] + "/" + file;
513  if (installed_ttf_filename.find_left('\'') >= 0 || installed_ttf_filename.find_left('\"') >= 0)
514  return String();
515 
516  int retval;
517  if (!same_filename(ttf_filename, installed_ttf_filename)) {
518  String command = COPY_CMD " " + shell_quote(ttf_filename) + " " + shell_quote(installed_ttf_filename);
519  retval = mysystem(command.c_str(), errh);
520  if (retval == 127)
521  errh->error("could not run %<%s%>", command.c_str());
522  else if (retval < 0)
523  errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
524  else if (retval != 0)
525  errh->error("%<%s%> failed", command.c_str());
526  } else {
527  if (verbose)
528  errh->message("TrueType file %s already located in output directory", installed_ttf_filename.c_str());
529  retval = 0;
530  }
531 
532  if (retval == 0) {
533  update_odir(O_TRUETYPE, installed_ttf_filename, errh);
534  return installed_ttf_filename;
535  }
536  }
537 
538  return String();
539 }
540 
541 String
542 installed_type42(const String &ttf_filename, const String &ps_fontname, bool allow_generate, ErrorHandler *errh)
543 {
544  (void) allow_generate, (void) ttf_filename, (void) errh;
545 
546  if (!ps_fontname)
547  return String();
548 
549 #if HAVE_KPATHSEA
550 # if HAVE_AUTO_TTFTOTYPE42
551  if (!(force && allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TYPE42, errh))) {
552 # endif
553  // look for .pfb and .pfa
554  String file, path;
555  if ((file = ps_fontname + ".t42", path = kpsei_string(kpsei_find_file(file.c_str(), KPSEI_FMT_TYPE42)))) {
556  if (path == "./" + file || path == file) {
557  if (verbose)
558  errh->message("ignoring Type 42 file %s found with kpathsea in %<.%>", path.c_str());
559  } else {
560  if (verbose)
561  errh->message("Type 42 file %s found with kpathsea at %s", file.c_str(), path.c_str());
562  return path;
563  }
564  }
565 # if HAVE_AUTO_TTFTOTYPE42
566  }
567 # endif
568 #endif
569 
570 #if HAVE_AUTO_TTFTOTYPE42
571  // if not found, and can generate on the fly, run ttftotype42
572  if (allow_generate && ttf_filename && ttf_filename != "-" && getodir(O_TYPE42, errh)) {
573  String t42_filename = odir[O_TYPE42] + "/" + ps_fontname + ".t42";
574  if (t42_filename.find_left('\'') >= 0 || ttf_filename.find_left('\'') >= 0)
575  return String();
576  String command = "ttftotype42 " + shell_quote(ttf_filename) + " " + shell_quote(t42_filename);
577  int retval = mysystem(command.c_str(), errh);
578  if (retval == 127)
579  errh->error("could not run %<%s%>", command.c_str());
580  else if (retval < 0)
581  errh->error("could not run %<%s%>: %s", command.c_str(), strerror(errno));
582  else if (retval != 0)
583  errh->error("%<%s%> failed", command.c_str());
584  if (retval == 0) {
585  update_odir(O_TYPE42, t42_filename, errh);
586  return t42_filename;
587  }
588  }
589 #endif
590 
591  return String();
592 }
593 
594 int
596 {
597 #if HAVE_KPATHSEA
598  if (automatic && !map_file && getodir(O_MAP, errh))
599  map_file = odir[O_MAP] + "/" + get_vendor() + ".map";
600 #endif
601 
602  if (map_file == "" || map_file == "-")
603  fputs(mapline.c_str(), stdout);
604  else {
605  // report no_create/verbose
606  if (no_create) {
607  errh->message("would update %s for %s", map_file.c_str(), String(fontname).c_str());
608  return 0;
609  } else if (verbose)
610  errh->message("updating %s for %s", map_file.c_str(), String(fontname).c_str());
611 
612  int fd = open(map_file.c_str(), O_RDWR | O_CREAT, 0666);
613  if (fd < 0)
614  return errh->lerror(map_file, "%s", strerror(errno));
615  FILE *f = fdopen(fd, "r+");
616  // NB: also change encoding logic if you change this code
617 
618 #if defined(F_SETLKW) && defined(HAVE_FTRUNCATE)
619  {
620  struct flock lock;
621  lock.l_type = F_WRLCK;
622  lock.l_whence = SEEK_SET;
623  lock.l_start = 0;
624  lock.l_len = 0;
625  int result;
626  while ((result = fcntl(fd, F_SETLKW, &lock)) < 0 && errno == EINTR)
627  /* try again */;
628  if (result < 0) {
629  result = errno;
630  fclose(f);
631  return errh->error("locking %s: %s", map_file.c_str(), strerror(result));
632  }
633  }
634 #endif
635 
636  // read old data from map file
637  StringAccum sa;
638  int amt;
639  do {
640  if (char *x = sa.reserve(8192)) {
641  amt = fread(x, 1, 8192, f);
642  sa.adjust_length(amt);
643  } else
644  amt = 0;
645  } while (amt != 0);
646  if (!feof(f))
647  return errh->error("%s: %s", map_file.c_str(), strerror(errno));
648  String text = sa.take_string();
649 
650  // add comment if necessary
651  bool created = (!text);
652  if (created)
653  text = "% Automatically maintained by otftotfm or other programs. Do not edit.\n\n";
654  if (text.back() != '\n')
655  text += "\n";
656 
657  // append old encodings
658  int fl = 0;
659  int nl = text.find_left('\n') + 1;
660  bool changed = created;
661  while (fl < text.length()) {
662  if (fl + fontname.length() + 1 < nl
663  && memcmp(text.data() + fl, fontname.data(), fontname.length()) == 0
664  && text[fl + fontname.length()] == ' ') {
665  // found the old name
666  if (text.substring(fl, nl - fl) == mapline) {
667  // duplicate of old name, don't change it
668  fclose(f);
669  if (verbose)
670  errh->message("%s unchanged", map_file.c_str());
671  return 0;
672  } else {
673  text = text.substring(0, fl) + text.substring(nl);
674  nl = fl;
675  changed = true;
676  }
677  }
678  fl = nl;
679  nl = text.find_left('\n', fl) + 1;
680  }
681 
682  if (!mapline && !changed) {
683  // special case: empty mapline, unchanged file
684  if (verbose)
685  errh->message("%s unchanged", map_file.c_str());
686  } else {
687  // add our text
688  text += mapline;
689 
690  // rewind file
691 #if HAVE_FTRUNCATE
692  rewind(f);
693  if (ftruncate(fd, 0) < 0)
694 #endif
695  {
696  fclose(f);
697  f = fopen(map_file.c_str(), "wb");
698  fd = fileno(f);
699  }
700 
701  // write data
702  ignore_result(fwrite(text.data(), 1, text.length(), f));
703  }
704 
705  fclose(f);
706 
707  // inform about the new file if necessary
708  if (created)
710 
711 #if HAVE_KPATHSEA && !WIN32
712  // run 'updmap' if present
713  String updmap_prog = output_flags & G_UPDMAP_USER ? "updmap-user" : "updmap-sys";
714  String updmap_dir, updmap_file;
715  if (automatic && (output_flags & G_UPDMAP))
716  updmap_dir = getodir(O_MAP_PARENT, errh);
717  if (updmap_dir
718  && (updmap_file = updmap_dir + "/" + updmap_prog)
719  && access(updmap_file.c_str(), X_OK) >= 0) {
720  // want to run `updmap` from its directory, can't use system()
721  if (verbose)
722  errh->message("running %s", updmap_file.c_str());
723 
724  pid_t child = fork();
725  if (child < 0)
726  errh->fatal("%s during fork", strerror(errno));
727  else if (child == 0) {
728  // change to updmap directory, run it
729  if (chdir(updmap_dir.c_str()) < 0)
730  errh->fatal("%s: %s during chdir", updmap_dir.c_str(), strerror(errno));
731  if (execl(output_flags & G_UPDMAP_USER ? "./updmap-user" : "./updmap-sys",
732  updmap_file.c_str(),
733  (const char*) 0) < 0)
734  errh->fatal("%s: %s during exec", updmap_file.c_str(), strerror(errno));
735  exit(1); // should never get here
736  }
737 
738 # if HAVE_WAITPID
739  // wait for updmap to finish
740  int status;
741  while (1) {
742  pid_t answer = waitpid(child, &status, 0);
743  if (answer >= 0)
744  break;
745  else if (errno != EINTR)
746  errh->fatal("%s during wait", strerror(errno));
747  }
748  if (!WIFEXITED(status))
749  errh->warning("%s exited abnormally", updmap_file.c_str());
750  else if (WEXITSTATUS(status) != 0)
751  errh->warning("%s exited with status %d", updmap_file.c_str(), WEXITSTATUS(status));
752 # else
753 # error "need waitpid() support: report this bug to the maintainer"
754 # endif
755  goto ran_updmap;
756  }
757 
758 # if HAVE_AUTO_UPDMAP
759  // run system updmap
760  if (output_flags & G_UPDMAP) {
762  int slash = filename.find_right('/');
763  if (slash >= 0)
764  filename = filename.substring(slash + 1);
765  String redirect = verbose ? " 1>&2" : " >" DEV_NULL " 2>&1";
766  String command = updmap_prog + " --nomkmap --enable Map " + shell_quote(filename) + redirect
767  + CMD_SEP " " + updmap_prog + redirect;
768  int retval = mysystem(command.c_str(), errh);
769  if (retval == 127)
770  errh->warning("could not run %<%s%>", command.c_str());
771  else if (retval < 0)
772  errh->warning("could not run %<%s%>: %s", command.c_str(), strerror(errno));
773  else if (retval != 0)
774  errh->warning("%<%s%> exited with status %d;\nrun it manually to check for errors", command.c_str(), WEXITSTATUS(retval));
775  goto ran_updmap;
776  }
777 # endif
778 
779  if (verbose)
780  errh->message("not running updmap");
781 
782  ran_updmap: ;
783 #endif
784  }
785 
786  return 0;
787 }
788 
789 String
791 {
792  if (!encfile || encfile == "-")
793  return encfile;
794 
795  if (!literal) {
796  int slash = encfile.find_right('/');
797  int dot = encfile.find_left('.', slash >= 0 ? slash : 0);
798  if (dot < 0)
799  if (String file = locate_encoding(encfile + ".enc", errh, true))
800  return file;
801  }
802 
803 #if HAVE_KPATHSEA
804  if (String file = kpsei_string(kpsei_find_file(encfile.c_str(), KPSEI_FMT_ENCODING))) {
805  if (verbose)
806  errh->message("encoding file %s found with kpathsea at %s", encfile.c_str(), file.c_str());
807  return file;
808  } else if (verbose)
809  errh->message("encoding file %s not found with kpathsea", encfile.c_str());
810 #endif
811 
812  if (access(encfile.c_str(), R_OK) >= 0)
813  return encfile;
814  else
815  return String();
816 }
int mkdir(const char *, mode_t)
const char * fontname
Definition: afm2pl.c:186
int nl
Definition: afm2tfm.c:885
#define text(a)
Definition: aptex-macros.h:925
#define DEFAULT_TYPEFACE
Definition: automatic.cc:70
const char * odirname(int o)
Definition: automatic.cc:269
static String vendor
Definition: automatic.cc:67
String installed_type1_dotlessj(const String &otf_filename, const String &ps_fontname, bool allow_generate, ErrorHandler *errh)
Definition: automatic.cc:427
int update_autofont_map(const String &fontname, String mapline, ErrorHandler *errh)
Definition: automatic.cc:595
bool set_map_file(const String &s)
Definition: automatic.cc:365
String locate_encoding(String encfile, ErrorHandler *errh, bool literal)
Definition: automatic.cc:790
bool set_typeface(const String &s, bool override)
Definition: automatic.cc:176
String installed_truetype(const String &ttf_filename, bool allow_generate, ErrorHandler *errh)
Definition: automatic.cc:491
void update_odir(int o, String file, ErrorHandler *errh)
Definition: automatic.cc:291
static const struct @1500 odir_info[]
#define COPY_CMD
Definition: automatic.cc:48
String getodir(int o, ErrorHandler *errh)
Definition: automatic.cc:185
static String typeface
Definition: automatic.cc:66
#define DEFAULT_VENDOR
Definition: automatic.cc:69
String installed_type42(const String &ttf_filename, const String &ps_fontname, bool allow_generate, ErrorHandler *errh)
Definition: automatic.cc:542
static String map_file
Definition: automatic.cc:68
#define CMD_SEP
Definition: automatic.cc:49
#define DEV_NULL
Definition: automatic.cc:57
const char * name
Definition: automatic.cc:73
const char * envvar
Definition: automatic.cc:74
bool set_vendor(const String &s)
Definition: automatic.cc:168
void setodir(int o, const String &value)
Definition: automatic.cc:262
String installed_type1(const String &otf_filename, const String &ps_fontname, bool allow_generate, ErrorHandler *errh)
Definition: automatic.cc:373
const char * texdir
Definition: automatic.cc:75
static String odir[NUMODIR]
Definition: automatic.cc:65
bool no_create
Definition: otftotfm.cc:299
@ O_TRUETYPE
Definition: automatic.hh:8
@ O_MAP
Definition: automatic.hh:7
@ O_TYPE1
Definition: automatic.hh:7
@ O_TYPE42
Definition: automatic.hh:8
@ NUMODIR
Definition: automatic.hh:8
@ O_MAP_PARENT
Definition: automatic.hh:7
bool automatic
Definition: otftotfm.cc:297
#define bool
Definition: autosp.c:101
Error reporting class.
Definition: error.hh:86
int error(const char *fmt,...)
Print an error message (level el_error).
Definition: error.cc:818
int warning(const char *fmt,...)
Print a warning message (level el_warning).
Definition: error.cc:808
void message(const char *fmt,...)
Print an informational message (level el_info).
Definition: error.cc:799
void fatal(const char *fmt,...)
Print a fatal error message (level el_fatal).
Definition: error.cc:828
int lerror(const String &landmark, const char *fmt,...)
Print an error message with a landmark annotation.
Definition: error.cc:869
Efficiently build up Strings from pieces.
Definition: straccum.hh:21
void adjust_length(int delta)
Adjust the StringAccum's length.
Definition: straccum.hh:416
String take_string()
Return a String object with this StringAccum's contents.
Definition: straccum.cc:197
char * reserve(int n)
Reserve space for at least n characters.
Definition: straccum.hh:391
#define free(a)
Definition: decNumber.cpp:310
#define R_OK
Definition: defs.h:31
#define F_OK
Definition: defs.h:34
#define fopen
Definition: xxstdio.h:21
#define fread
Definition: xxstdio.h:25
Flexible error handling classes.
int fcntl(int fd, int action,...)
Definition: fcntl.c:202
static void
Definition: fpif.c:118
mpz_t * f
Definition: gen-fib.c:34
#define s
Definition: afcover.h:80
#define colon
Definition: globals.h:58
#define dot
Definition: globals.h:56
char * mapline
Definition: gsftopk.c:414
#define memcmp(s1, s2, n)
Definition: gsftopk.c:66
assert(pcxLoadImage24((char *)((void *) 0), fp, pinfo, hdr))
void mktexupd(char *s)
Definition: mktexupd.c:27
int kpsei_env_sep_char
Definition: kpseinterface.c:29
char * kpsei_find_file(const char *name, int format)
Definition: kpseinterface.c:56
char * kpsei_path_expand(const char *path)
Definition: kpseinterface.c:50
@ KPSEI_FMT_TRUETYPE
Definition: kpseinterface.h:11
@ KPSEI_FMT_WEB2C
Definition: kpseinterface.h:10
@ KPSEI_FMT_TYPE1
Definition: kpseinterface.h:10
@ KPSEI_FMT_TYPE42
Definition: kpseinterface.h:12
@ KPSEI_FMT_ENCODING
Definition: kpseinterface.h:10
#define SEEK_SET
Definition: jmemansi.c:26
char String
Definition: tttypes.h:35
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p
Definition: afcover.h:72
void exit()
char * getenv()
int errno
#define WEXITSTATUS(val)
Definition: dpxfile.c:58
#define WIFEXITED(val)
Definition: dpxfile.c:61
#define X_OK
Definition: c-unistd.h:46
#define W_OK
Definition: c-unistd.h:47
#define fclose
Definition: debug.h:100
static int find(DIR *dp, char *name)
Definition: dirent.c:25
#define access
Definition: win32lib.h:59
#define O_CREAT
Definition: win32lib.h:170
#define fileno
Definition: win32lib.h:72
#define open
Definition: win32lib.h:86
#define system(p)
Definition: win32lib.h:269
#define chdir
Definition: win32lib.h:61
#define O_RDWR
Definition: win32lib.h:167
#define fputs
Definition: mendex.h:67
#define fprintf
Definition: mendex.h:64
char * encfile
Definition: ps2pk.c:207
static char * strerror(int errnum)
Definition: error.c:56
#define length(c)
Definition: ctangleboot.c:65
Code related to b fwrite(a, sizeof(char), b, stdout) @d C_printf(c
int pid_t
Definition: types.h:81
pid_t fork()
int execl()
float x
Definition: cordic.py:15
UnlocalizedNumberFormatter create(const UnicodeString &skeletonString, UParseError *perror, UErrorCode &status)
union value value
Definition: obx.h:44
String shell_quote(const String &str)
Definition: util.cc:104
int mysystem(const char *command, ErrorHandler *errh)
Definition: util.cc:153
String pathname_filename(const String &path)
Definition: util.cc:77
bool same_filename(const String &a, const String &b)
Definition: util.cc:98
void ignore_result(T result)
Definition: util.hh:33
@ G_UPDMAP
Definition: util.hh:14
@ G_UPDMAP_USER
Definition: util.hh:14
static String otf_filename
Definition: otftotfm.cc:1391
unsigned output_flags
Definition: otftotfm.cc:295
boolean changed
Definition: parse_ofm.c:90
char * filename[256]
Definition: pbmtopk.c:46
const char * suffix
Definition: pkg_icu.cpp:27
static int force
Definition: pnmtopng.c:115
#define dir
#define status
static ErrorHandler * errh
Definition: main.cc:71
FILE * fdopen(int, const char *)
static UMutex lock
Definition: serv.cpp:336
Click's StringAccum class, used to construct Strings efficiently from pieces.
A string of characters.
Definition: t1part.c:49
const char * c_str() const
Null-terminate the string.
Definition: string.hh:256
const char * data() const
Return a pointer to the string's data.
Definition: string.hh:161
char back() const
Return the last character in the string.
Definition: string.hh:245
String substring(const char *begin, const char *end) const
Return a substring of the current string starting at begin and ending before end.
Definition: string.hh:371
int length() const
Return the string's length.
Definition: string.hh:153
int find_left(char c, int start=0) const
Search for a character in a string.
Definition: string.cc:495
Definition: job.h:44
Definition: dir.c:365
Definition: filedef.h:30
Definition: tpic.c:45
short length
Definition: plain2.h:55
pointer path
Definition: t1imager.h:36
#define FILE
Definition: t1stdio.h:34
#define feof(f)
Definition: t1stdio.h:109
char * file
Definition: t4ht.c:931
back
Definition: tex4ht.c:3533
#define verbose
Definition: jpeg.c:35
Definition: obx.h:51
static void redirect(word *p)
Definition: gc.c:876