]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/GlobalParams.cc
Merge with Xpdf 2.02 and make it build
[evince.git] / pdf / xpdf / GlobalParams.cc
1 //========================================================================
2 //
3 // GlobalParams.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <string.h>
16 #include <ctype.h>
17 #if HAVE_PAPER_H
18 #include <paper.h>
19 #endif
20 #include "gmem.h"
21 #include "GString.h"
22 #include "GList.h"
23 #include "GHash.h"
24 #include "gfile.h"
25 #include "Error.h"
26 #include "NameToCharCode.h"
27 #include "CharCodeToUnicode.h"
28 #include "UnicodeMap.h"
29 #include "CMap.h"
30 #include "BuiltinFontTables.h"
31 #include "FontEncodingTables.h"
32 #include "GlobalParams.h"
33
34 #if MULTITHREADED
35 #  define globalParamsLock gLockMutex(&mutex)
36 #  define globalParamsUnlock gUnlockMutex(&mutex)
37 #else
38 #  define globalParamsLock
39 #  define globalParamsUnlock
40 #endif
41
42 #include "NameToUnicodeTable.h"
43 #include "UnicodeMapTables.h"
44 #include "DisplayFontTable.h"
45 #include "UTF8.h"
46
47 //------------------------------------------------------------------------
48
49 GlobalParams *globalParams = NULL;
50
51 //------------------------------------------------------------------------
52 // DisplayFontParam
53 //------------------------------------------------------------------------
54
55 DisplayFontParam::DisplayFontParam(GString *nameA,
56                                    DisplayFontParamKind kindA) {
57   name = nameA;
58   kind = kindA;
59   switch (kind) {
60   case displayFontX:
61     x.xlfd = NULL;
62     x.encoding = NULL;
63     break;
64   case displayFontT1:
65     t1.fileName = NULL;
66     break;
67   case displayFontTT:
68     tt.fileName = NULL;
69     break;
70   }
71 }
72
73 DisplayFontParam::DisplayFontParam(char *nameA, char *xlfdA, char *encodingA) {
74   name = new GString(nameA);
75   kind = displayFontX;
76   x.xlfd = new GString(xlfdA);
77   x.encoding = new GString(encodingA);
78 }
79
80 DisplayFontParam::~DisplayFontParam() {
81   delete name;
82   switch (kind) {
83   case displayFontX:
84     if (x.xlfd) {
85       delete x.xlfd;
86     }
87     if (x.encoding) {
88       delete x.encoding;
89     }
90     break;
91   case displayFontT1:
92     if (t1.fileName) {
93       delete t1.fileName;
94     }
95     break;
96   case displayFontTT:
97     if (tt.fileName) {
98       delete tt.fileName;
99     }
100     break;
101   }
102 }
103
104 //------------------------------------------------------------------------
105 // PSFontParam
106 //------------------------------------------------------------------------
107
108 PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA,
109                          GString *psFontNameA, GString *encodingA) {
110   pdfFontName = pdfFontNameA;
111   wMode = wModeA;
112   psFontName = psFontNameA;
113   encoding = encodingA;
114 }
115
116 PSFontParam::~PSFontParam() {
117   delete pdfFontName;
118   delete psFontName;
119   if (encoding) {
120     delete encoding;
121   }
122 }
123
124 //------------------------------------------------------------------------
125 // parsing
126 //------------------------------------------------------------------------
127
128 GlobalParams::GlobalParams(char *cfgFileName) {
129   UnicodeMap *map;
130   DisplayFontParam *dfp;
131   GString *fileName;
132   FILE *f;
133   int i;
134
135 #if MULTITHREADED
136   gInitMutex(&mutex);
137 #endif
138
139   initBuiltinFontTables();
140
141   // scan the encoding in reverse because we want the lowest-numbered
142   // index for each char name ('space' is encoded twice)
143   macRomanReverseMap = new NameToCharCode();
144   for (i = 255; i >= 0; --i) {
145     if (macRomanEncoding[i]) {
146       macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i);
147     }
148   }
149
150   nameToUnicode = new NameToCharCode();
151   cidToUnicodes = new GHash(gTrue);
152   residentUnicodeMaps = new GHash();
153   unicodeMaps = new GHash(gTrue);
154   cMapDirs = new GHash(gTrue);
155   toUnicodeDirs = new GList();
156   displayFonts = new GHash();
157   displayCIDFonts = new GHash();
158   displayNamedCIDFonts = new GHash();
159 #if HAVE_PAPER_H
160   char *paperName;
161   const struct paper *paperType;
162   paperinit();
163   if ((paperName = systempapername())) {
164     paperType = paperinfo(paperName);
165     psPaperWidth = (int)paperpswidth(paperType);
166     psPaperHeight = (int)paperpsheight(paperType);
167   } else {
168     error(-1, "No paper information available - using defaults");
169     psPaperWidth = defPaperWidth;
170     psPaperHeight = defPaperHeight;
171   }
172   paperdone();
173 #else
174   psPaperWidth = defPaperWidth;
175   psPaperHeight = defPaperHeight;
176 #endif
177   psDuplex = gFalse;
178   psLevel = psLevel2;
179   psFile = NULL;
180   psFonts = new GHash();
181   psNamedFonts16 = new GList();
182   psFonts16 = new GList();
183   psEmbedType1 = gTrue;
184   psEmbedTrueType = gTrue;
185   psEmbedCIDPostScript = gTrue;
186   psEmbedCIDTrueType = gTrue;
187   psOPI = gFalse;
188   psASCIIHex = gFalse;
189   textEncoding = new GString("Latin1");
190 #if defined(WIN32)
191   textEOL = eolDOS;
192 #elif defined(MACOS)
193   textEOL = eolMac;
194 #else
195   textEOL = eolUnix;
196 #endif
197   textKeepTinyChars = gFalse;
198   fontDirs = new GList();
199   initialZoom = new GString("1");
200   t1libControl = fontRastAALow;
201   freetypeControl = fontRastAALow;
202   urlCommand = NULL;
203   movieCommand = NULL;
204   mapNumericCharNames = gTrue;
205   printCommands = gFalse;
206   errQuiet = gFalse;
207
208   cidToUnicodeCache = new CIDToUnicodeCache();
209   unicodeMapCache = new UnicodeMapCache();
210   cMapCache = new CMapCache();
211
212   // set up the initial nameToUnicode table
213   for (i = 0; nameToUnicodeTab[i].name; ++i) {
214     nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u);
215   }
216
217   // set up the residentUnicodeMaps table
218   map = new UnicodeMap("Latin1", gFalse,
219                        latin1UnicodeMapRanges, latin1UnicodeMapLen);
220   residentUnicodeMaps->add(map->getEncodingName(), map);
221   map = new UnicodeMap("ASCII7", gFalse,
222                        ascii7UnicodeMapRanges, ascii7UnicodeMapLen);
223   residentUnicodeMaps->add(map->getEncodingName(), map);
224   map = new UnicodeMap("Symbol", gFalse,
225                        symbolUnicodeMapRanges, symbolUnicodeMapLen);
226   residentUnicodeMaps->add(map->getEncodingName(), map);
227   map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges,
228                        zapfDingbatsUnicodeMapLen);
229   residentUnicodeMaps->add(map->getEncodingName(), map);
230   map = new UnicodeMap("UTF-8", gTrue, &mapUTF8);
231   residentUnicodeMaps->add(map->getEncodingName(), map);
232   map = new UnicodeMap("UCS-2", gTrue, &mapUCS2);
233   residentUnicodeMaps->add(map->getEncodingName(), map);
234
235   // default displayFonts table
236   for (i = 0; displayFontTab[i].name; ++i) {
237     dfp = new DisplayFontParam(displayFontTab[i].name,
238                                displayFontTab[i].xlfd,
239                                displayFontTab[i].encoding);
240     displayFonts->add(dfp->name, dfp);
241   }
242
243   // look for a user config file, then a system-wide config file
244   f = NULL;
245   fileName = NULL;
246   if (cfgFileName && cfgFileName[0]) {
247     fileName = new GString(cfgFileName);
248     if (!(f = fopen(fileName->getCString(), "r"))) {
249       delete fileName;
250     }
251   }
252   if (!f) {
253     fileName = appendToPath(getHomeDir(), xpdfUserConfigFile);
254     if (!(f = fopen(fileName->getCString(), "r"))) {
255       delete fileName;
256     }
257   }
258   if (!f) {
259 #if defined(WIN32) && !defined(__CYGWIN32__)
260     char buf[512];
261     i = GetModuleFileName(NULL, buf, sizeof(buf));
262     if (i <= 0 || i >= sizeof(buf)) {
263       // error or path too long for buffer - just use the current dir
264       buf[0] = '\0';
265     }
266     fileName = grabPath(buf);
267     appendToPath(fileName, xpdfSysConfigFile);
268 #else
269     fileName = new GString(xpdfSysConfigFile);
270 #endif
271     if (!(f = fopen(fileName->getCString(), "r"))) {
272       delete fileName;
273     }
274   }
275   if (f) {
276     parseFile(fileName, f);
277     delete fileName;
278     fclose(f);
279   }
280 }
281
282 void GlobalParams::parseFile(GString *fileName, FILE *f) {
283   int line;
284   GList *tokens;
285   GString *cmd, *incFile;
286   char *p1, *p2;
287   char buf[512];
288   FILE *f2;
289
290   line = 1;
291   while (getLine(buf, sizeof(buf) - 1, f)) {
292
293     // break the line into tokens
294     tokens = new GList();
295     p1 = buf;
296     while (*p1) {
297       for (; *p1 && isspace(*p1); ++p1) ;
298       if (!*p1) {
299         break;
300       }
301       if (*p1 == '"' || *p1 == '\'') {
302         for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ;
303         ++p1;
304       } else {
305         for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ;
306       }
307       tokens->append(new GString(p1, p2 - p1));
308       p1 = *p2 ? p2 + 1 : p2;
309     }
310
311     if (tokens->getLength() > 0 &&
312         ((GString *)tokens->get(0))->getChar(0) != '#') {
313       cmd = (GString *)tokens->get(0);
314       if (!cmd->cmp("include")) {
315         if (tokens->getLength() == 2) {
316           incFile = (GString *)tokens->get(1);
317           if ((f2 = fopen(incFile->getCString(), "r"))) {
318             parseFile(incFile, f2);
319             fclose(f2);
320           } else {
321             error(-1, "Couldn't find included config file: '%s' (%s:%d)",
322                   incFile->getCString(), fileName->getCString(), line);
323           }
324         } else {
325           error(-1, "Bad 'include' config file command (%s:%d)",
326                 fileName->getCString(), line);
327         }
328       } else if (!cmd->cmp("nameToUnicode")) {
329         parseNameToUnicode(tokens, fileName, line);
330       } else if (!cmd->cmp("cidToUnicode")) {
331         parseCIDToUnicode(tokens, fileName, line);
332       } else if (!cmd->cmp("unicodeMap")) {
333         parseUnicodeMap(tokens, fileName, line);
334       } else if (!cmd->cmp("cMapDir")) {
335         parseCMapDir(tokens, fileName, line);
336       } else if (!cmd->cmp("toUnicodeDir")) {
337         parseToUnicodeDir(tokens, fileName, line);
338       } else if (!cmd->cmp("displayFontX")) {
339         parseDisplayFont(tokens, displayFonts, displayFontX, fileName, line);
340       } else if (!cmd->cmp("displayFontT1")) {
341         parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line);
342       } else if (!cmd->cmp("displayFontTT")) {
343         parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line);
344       } else if (!cmd->cmp("displayNamedCIDFontX")) {
345         parseDisplayFont(tokens, displayNamedCIDFonts,
346                          displayFontX, fileName, line);
347       } else if (!cmd->cmp("displayCIDFontX")) {
348         parseDisplayFont(tokens, displayCIDFonts,
349                          displayFontX, fileName, line);
350       } else if (!cmd->cmp("displayNamedCIDFontT1")) {
351         parseDisplayFont(tokens, displayNamedCIDFonts,
352                          displayFontT1, fileName, line);
353       } else if (!cmd->cmp("displayCIDFontT1")) {
354         parseDisplayFont(tokens, displayCIDFonts,
355                          displayFontT1, fileName, line);
356       } else if (!cmd->cmp("displayNamedCIDFontTT")) {
357         parseDisplayFont(tokens, displayNamedCIDFonts,
358                          displayFontTT, fileName, line);
359       } else if (!cmd->cmp("displayCIDFontTT")) {
360         parseDisplayFont(tokens, displayCIDFonts,
361                          displayFontTT, fileName, line);
362       } else if (!cmd->cmp("psFile")) {
363         parsePSFile(tokens, fileName, line);
364       } else if (!cmd->cmp("psFont")) {
365         parsePSFont(tokens, fileName, line);
366       } else if (!cmd->cmp("psNamedFont16")) {
367         parsePSFont16("psNamedFont16", psNamedFonts16,
368                       tokens, fileName, line);
369       } else if (!cmd->cmp("psFont16")) {
370         parsePSFont16("psFont16", psFonts16, tokens, fileName, line);
371       } else if (!cmd->cmp("psPaperSize")) {
372         parsePSPaperSize(tokens, fileName, line);
373       } else if (!cmd->cmp("psDuplex")) {
374         parseYesNo("psDuplex", &psDuplex, tokens, fileName, line);
375       } else if (!cmd->cmp("psLevel")) {
376         parsePSLevel(tokens, fileName, line);
377       } else if (!cmd->cmp("psEmbedType1Fonts")) {
378         parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line);
379       } else if (!cmd->cmp("psEmbedTrueTypeFonts")) {
380         parseYesNo("psEmbedTrueType", &psEmbedTrueType,
381                    tokens, fileName, line);
382       } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) {
383         parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript,
384                    tokens, fileName, line);
385       } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) {
386         parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType,
387                    tokens, fileName, line);
388       } else if (!cmd->cmp("psOPI")) {
389         parseYesNo("psOPI", &psOPI, tokens, fileName, line);
390       } else if (!cmd->cmp("psASCIIHex")) {
391         parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line);
392       } else if (!cmd->cmp("textEncoding")) {
393         parseTextEncoding(tokens, fileName, line);
394       } else if (!cmd->cmp("textEOL")) {
395         parseTextEOL(tokens, fileName, line);
396       } else if (!cmd->cmp("textKeepTinyChars")) {
397         parseYesNo("textKeepTinyChars", &textKeepTinyChars,
398                    tokens, fileName, line);
399       } else if (!cmd->cmp("fontDir")) {
400         parseFontDir(tokens, fileName, line);
401       } else if (!cmd->cmp("initialZoom")) {
402         parseInitialZoom(tokens, fileName, line);
403       } else if (!cmd->cmp("t1libControl")) {
404         parseFontRastControl("t1libControl", &t1libControl,
405                              tokens, fileName, line);
406       } else if (!cmd->cmp("freetypeControl")) {
407         parseFontRastControl("freetypeControl", &freetypeControl,
408                              tokens, fileName, line);
409       } else if (!cmd->cmp("urlCommand")) {
410         parseCommand("urlCommand", &urlCommand, tokens, fileName, line);
411       } else if (!cmd->cmp("movieCommand")) {
412         parseCommand("movieCommand", &movieCommand, tokens, fileName, line);
413       } else if (!cmd->cmp("mapNumericCharNames")) {
414         parseYesNo("mapNumericCharNames", &mapNumericCharNames,
415                    tokens, fileName, line);
416       } else if (!cmd->cmp("printCommands")) {
417         parseYesNo("printCommands", &printCommands, tokens, fileName, line);
418       } else if (!cmd->cmp("errQuiet")) {
419         parseYesNo("errQuiet", &errQuiet, tokens, fileName, line);
420       } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) {
421         error(-1, "Unknown config file command");
422         error(-1, "-- the config file format has changed since Xpdf 0.9x");
423       } else {
424         error(-1, "Unknown config file command '%s' (%s:%d)",
425               cmd->getCString(), fileName->getCString(), line);
426       }
427     }
428
429     deleteGList(tokens, GString);
430     ++line;
431   }
432 }
433
434 void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName,
435                                          int line) {
436   GString *name;
437   char *tok1, *tok2;
438   FILE *f;
439   char buf[256];
440   int line2;
441   Unicode u;
442
443   if (tokens->getLength() != 2) {
444     error(-1, "Bad 'nameToUnicode' config file command (%s:%d)",
445           fileName->getCString(), line);
446     return;
447   }
448   name = (GString *)tokens->get(1);
449   if (!(f = fopen(name->getCString(), "r"))) {
450     error(-1, "Couldn't open 'nameToUnicode' file '%s'",
451           name->getCString());
452     return;
453   }
454   line2 = 1;
455   while (getLine(buf, sizeof(buf), f)) {
456     tok1 = strtok(buf, " \t\r\n");
457     tok2 = strtok(NULL, " \t\r\n");
458     if (tok1 && tok2) {
459       sscanf(tok1, "%x", &u);
460       nameToUnicode->add(tok2, u);
461     } else {
462       error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2);
463     }
464     ++line2;
465   }
466   fclose(f);
467 }
468
469 void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName,
470                                      int line) {
471   GString *collection, *name, *old;
472
473   if (tokens->getLength() != 3) {
474     error(-1, "Bad 'cidToUnicode' config file command (%s:%d)",
475           fileName->getCString(), line);
476     return;
477   }
478   collection = (GString *)tokens->get(1);
479   name = (GString *)tokens->get(2);
480   if ((old = (GString *)cidToUnicodes->remove(collection))) {
481     delete old;
482   }
483   cidToUnicodes->add(collection->copy(), name->copy());
484 }
485
486 void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName,
487                                    int line) {
488   GString *encodingName, *name, *old;
489
490   if (tokens->getLength() != 3) {
491     error(-1, "Bad 'unicodeMap' config file command (%s:%d)",
492           fileName->getCString(), line);
493     return;
494   }
495   encodingName = (GString *)tokens->get(1);
496   name = (GString *)tokens->get(2);
497   if ((old = (GString *)unicodeMaps->remove(encodingName))) {
498     delete old;
499   }
500   unicodeMaps->add(encodingName->copy(), name->copy());
501 }
502
503 void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) {
504   GString *collection, *dir;
505   GList *list;
506
507   if (tokens->getLength() != 3) {
508     error(-1, "Bad 'cMapDir' config file command (%s:%d)",
509           fileName->getCString(), line);
510     return;
511   }
512   collection = (GString *)tokens->get(1);
513   dir = (GString *)tokens->get(2);
514   if (!(list = (GList *)cMapDirs->lookup(collection))) {
515     list = new GList();
516     cMapDirs->add(collection->copy(), list);
517   }
518   list->append(dir->copy());
519 }
520
521 void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName,
522                                      int line) {
523   if (tokens->getLength() != 2) {
524     error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)",
525           fileName->getCString(), line);
526     return;
527   }
528   toUnicodeDirs->append(((GString *)tokens->get(1))->copy());
529 }
530
531 void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash,
532                                     DisplayFontParamKind kind,
533                                     GString *fileName, int line) {
534   DisplayFontParam *param, *old;
535
536   if (tokens->getLength() < 2) {
537     goto err1;
538   }
539   param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind);
540   
541   switch (kind) {
542   case displayFontX:
543     if (tokens->getLength() != 4) {
544       goto err2;
545     }
546     param->x.xlfd = ((GString *)tokens->get(2))->copy();
547     param->x.encoding = ((GString *)tokens->get(3))->copy();
548     break;
549   case displayFontT1:
550     if (tokens->getLength() != 3) {
551       goto err2;
552     }
553     param->t1.fileName = ((GString *)tokens->get(2))->copy();
554     break;
555   case displayFontTT:
556     if (tokens->getLength() != 3) {
557       goto err2;
558     }
559     param->tt.fileName = ((GString *)tokens->get(2))->copy();
560     break;
561   }
562
563   if ((old = (DisplayFontParam *)fontHash->remove(param->name))) {
564     delete old;
565   }
566   fontHash->add(param->name, param);
567   return;
568
569  err2:
570   delete param;
571  err1:
572   error(-1, "Bad 'display*Font*' config file command (%s:%d)",
573         fileName->getCString(), line);
574 }
575
576 void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName,
577                                     int line) {
578   GString *tok;
579
580   if (tokens->getLength() == 2) {
581     tok = (GString *)tokens->get(1);
582     if (!setPSPaperSize(tok->getCString())) {
583       error(-1, "Bad 'psPaperSize' config file command (%s:%d)",
584             fileName->getCString(), line);
585     }
586   } else if (tokens->getLength() == 3) {
587     tok = (GString *)tokens->get(1);
588     psPaperWidth = atoi(tok->getCString());
589     tok = (GString *)tokens->get(2);
590     psPaperHeight = atoi(tok->getCString());
591   } else {
592     error(-1, "Bad 'psPaperSize' config file command (%s:%d)",
593           fileName->getCString(), line);
594   }
595 }
596
597 void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) {
598   GString *tok;
599
600   if (tokens->getLength() != 2) {
601     error(-1, "Bad 'psLevel' config file command (%s:%d)",
602           fileName->getCString(), line);
603     return;
604   }
605   tok = (GString *)tokens->get(1);
606   if (!tok->cmp("level1")) {
607     psLevel = psLevel1;
608   } else if (!tok->cmp("level1sep")) {
609     psLevel = psLevel1Sep;
610   } else if (!tok->cmp("level2")) {
611     psLevel = psLevel2;
612   } else if (!tok->cmp("level2sep")) {
613     psLevel = psLevel2Sep;
614   } else if (!tok->cmp("level3")) {
615     psLevel = psLevel3;
616   } else if (!tok->cmp("level3Sep")) {
617     psLevel = psLevel3Sep;
618   } else {
619     error(-1, "Bad 'psLevel' config file command (%s:%d)",
620           fileName->getCString(), line);
621   }
622 }
623
624 void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) {
625   if (tokens->getLength() != 2) {
626     error(-1, "Bad 'psFile' config file command (%s:%d)",
627           fileName->getCString(), line);
628     return;
629   }
630   if (psFile) {
631     delete psFile;
632   }
633   psFile = ((GString *)tokens->get(1))->copy();
634 }
635
636 void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) {
637   PSFontParam *param;
638
639   if (tokens->getLength() != 3) {
640     error(-1, "Bad 'psFont' config file command (%s:%d)",
641           fileName->getCString(), line);
642     return;
643   }
644   param = new PSFontParam(((GString *)tokens->get(1))->copy(), 0,
645                           ((GString *)tokens->get(2))->copy(), NULL);
646   psFonts->add(param->pdfFontName, param);
647 }
648
649 void GlobalParams::parsePSFont16(char *cmdName, GList *fontList,
650                                  GList *tokens, GString *fileName, int line) {
651   PSFontParam *param;
652   int wMode;
653   GString *tok;
654
655   if (tokens->getLength() != 5) {
656     error(-1, "Bad '%s' config file command (%s:%d)",
657           cmdName, fileName->getCString(), line);
658     return;
659   }
660   tok = (GString *)tokens->get(2);
661   if (!tok->cmp("H")) {
662     wMode = 0;
663   } else if (!tok->cmp("V")) {
664     wMode = 1;
665   } else {
666     error(-1, "Bad '%s' config file command (%s:%d)",
667           cmdName, fileName->getCString(), line);
668     return;
669   }
670   param = new PSFontParam(((GString *)tokens->get(1))->copy(),
671                           wMode,
672                           ((GString *)tokens->get(3))->copy(),
673                           ((GString *)tokens->get(4))->copy());
674   fontList->append(param);
675 }
676
677 void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName,
678                                      int line) {
679   if (tokens->getLength() != 2) {
680     error(-1, "Bad 'textEncoding' config file command (%s:%d)",
681           fileName->getCString(), line);
682     return;
683   }
684   delete textEncoding;
685   textEncoding = ((GString *)tokens->get(1))->copy();
686 }
687
688 void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) {
689   GString *tok;
690
691   if (tokens->getLength() != 2) {
692     error(-1, "Bad 'textEOL' config file command (%s:%d)",
693           fileName->getCString(), line);
694     return;
695   }
696   tok = (GString *)tokens->get(1);
697   if (!tok->cmp("unix")) {
698     textEOL = eolUnix;
699   } else if (!tok->cmp("dos")) {
700     textEOL = eolDOS;
701   } else if (!tok->cmp("mac")) {
702     textEOL = eolMac;
703   } else {
704     error(-1, "Bad 'textEOL' config file command (%s:%d)",
705           fileName->getCString(), line);
706   }
707 }
708
709 void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) {
710   if (tokens->getLength() != 2) {
711     error(-1, "Bad 'fontDir' config file command (%s:%d)",
712           fileName->getCString(), line);
713     return;
714   }
715   fontDirs->append(((GString *)tokens->get(1))->copy());
716 }
717
718 void GlobalParams::parseInitialZoom(GList *tokens,
719                                     GString *fileName, int line) {
720   if (tokens->getLength() != 2) {
721     error(-1, "Bad 'initialZoom' config file command (%s:%d)",
722           fileName->getCString(), line);
723     return;
724   }
725   delete initialZoom;
726   initialZoom = ((GString *)tokens->get(1))->copy();
727 }
728
729 void GlobalParams::parseFontRastControl(char *cmdName, FontRastControl *val,
730                                         GList *tokens, GString *fileName,
731                                         int line) {
732   GString *tok;
733
734   if (tokens->getLength() != 2) {
735     error(-1, "Bad '%s' config file command (%s:%d)",
736           cmdName, fileName->getCString(), line);
737     return;
738   }
739   tok = (GString *)tokens->get(1);
740   if (!setFontRastControl(val, tok->getCString())) {
741     error(-1, "Bad '%s' config file command (%s:%d)",
742           cmdName, fileName->getCString(), line);
743   }
744 }
745
746 void GlobalParams::parseCommand(char *cmdName, GString **val,
747                                 GList *tokens, GString *fileName, int line) {
748   if (tokens->getLength() != 2) {
749     error(-1, "Bad '%s' config file command (%s:%d)",
750           cmdName, fileName->getCString(), line);
751     return;
752   }
753   if (*val) {
754     delete *val;
755   }
756   *val = ((GString *)tokens->get(1))->copy();
757 }
758
759 void GlobalParams::parseYesNo(char *cmdName, GBool *flag,
760                               GList *tokens, GString *fileName, int line) {
761   GString *tok;
762
763   if (tokens->getLength() != 2) {
764     error(-1, "Bad '%s' config file command (%s:%d)",
765           cmdName, fileName->getCString(), line);
766     return;
767   }
768   tok = (GString *)tokens->get(1);
769   if (!tok->cmp("yes")) {
770     *flag = gTrue;
771   } else if (!tok->cmp("no")) {
772     *flag = gFalse;
773   } else {
774     error(-1, "Bad '%s' config file command (%s:%d)",
775           cmdName, fileName->getCString(), line);
776   }
777 }
778
779 GlobalParams::~GlobalParams() {
780   GHashIter *iter;
781   GString *key;
782   GList *list;
783
784   freeBuiltinFontTables();
785
786   delete macRomanReverseMap;
787
788   delete nameToUnicode;
789   deleteGHash(cidToUnicodes, GString);
790   deleteGHash(residentUnicodeMaps, UnicodeMap);
791   deleteGHash(unicodeMaps, GString);
792   deleteGList(toUnicodeDirs, GString);
793   deleteGHash(displayFonts, DisplayFontParam);
794   deleteGHash(displayCIDFonts, DisplayFontParam);
795   deleteGHash(displayNamedCIDFonts, DisplayFontParam);
796   if (psFile) {
797     delete psFile;
798   }
799   deleteGHash(psFonts, PSFontParam);
800   deleteGList(psNamedFonts16, PSFontParam);
801   deleteGList(psFonts16, PSFontParam);
802   delete textEncoding;
803   deleteGList(fontDirs, GString);
804   delete initialZoom;
805   if (urlCommand) {
806     delete urlCommand;
807   }
808   if (movieCommand) {
809     delete movieCommand;
810   }
811
812   cMapDirs->startIter(&iter);
813   while (cMapDirs->getNext(&iter, &key, (void **)&list)) {
814     deleteGList(list, GString);
815   }
816   delete cMapDirs;
817
818   delete cidToUnicodeCache;
819   delete unicodeMapCache;
820   delete cMapCache;
821
822 #if MULTITHREADED
823   gDestroyMutex(&mutex);
824 #endif
825 }
826
827 //------------------------------------------------------------------------
828 // accessors
829 //------------------------------------------------------------------------
830
831 CharCode GlobalParams::getMacRomanCharCode(char *charName) {
832   return macRomanReverseMap->lookup(charName);
833 }
834
835 Unicode GlobalParams::mapNameToUnicode(char *charName) {
836   return nameToUnicode->lookup(charName);
837 }
838
839 FILE *GlobalParams::getCIDToUnicodeFile(GString *collection) {
840   GString *fileName;
841
842   if (!(fileName = (GString *)cidToUnicodes->lookup(collection))) {
843     return NULL;
844   }
845   return fopen(fileName->getCString(), "r");
846 }
847
848 UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) {
849   return (UnicodeMap *)residentUnicodeMaps->lookup(encodingName);
850 }
851
852 FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) {
853   GString *fileName;
854
855   if (!(fileName = (GString *)unicodeMaps->lookup(encodingName))) {
856     return NULL;
857   }
858   return fopen(fileName->getCString(), "r");
859 }
860
861 FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) {
862   GList *list;
863   GString *dir;
864   GString *fileName;
865   FILE *f;
866   int i;
867
868   if (!(list = (GList *)cMapDirs->lookup(collection))) {
869     return NULL;
870   }
871   for (i = 0; i < list->getLength(); ++i) {
872     dir = (GString *)list->get(i);
873     fileName = appendToPath(dir->copy(), cMapName->getCString());
874     f = fopen(fileName->getCString(), "r");
875     delete fileName;
876     if (f) {
877       return f;
878     }
879   }
880   return NULL;
881 }
882
883 FILE *GlobalParams::findToUnicodeFile(GString *name) {
884   GString *dir, *fileName;
885   FILE *f;
886   int i;
887
888   for (i = 0; i < toUnicodeDirs->getLength(); ++i) {
889     dir = (GString *)toUnicodeDirs->get(i);
890     fileName = appendToPath(dir->copy(), name->getCString());
891     f = fopen(fileName->getCString(), "r");
892     delete fileName;
893     if (f) {
894       return f;
895     }
896   }
897   return NULL;
898 }
899
900 DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) {
901   DisplayFontParam *dfp;
902
903   globalParamsLock;
904   dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
905   globalParamsUnlock;
906   return dfp;
907 }
908
909 DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName,
910                                                   GString *collection) {
911   DisplayFontParam *dfp;
912
913   if (!fontName ||
914       !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) {
915     dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection);
916   }
917   return dfp;
918 }
919
920 GString *GlobalParams::getPSFile() {
921   GString *s;
922
923   globalParamsLock;
924   s = psFile ? psFile->copy() : (GString *)NULL;
925   globalParamsUnlock;
926   return s;
927 }
928
929 int GlobalParams::getPSPaperWidth() {
930   int w;
931
932   globalParamsLock;
933   w = psPaperWidth;
934   globalParamsUnlock;
935   return w;
936 }
937
938 int GlobalParams::getPSPaperHeight() {
939   int h;
940
941   globalParamsLock;
942   h = psPaperHeight;
943   globalParamsUnlock;
944   return h;
945 }
946
947 GBool GlobalParams::getPSDuplex() {
948   GBool d;
949
950   globalParamsLock;
951   d = psDuplex;
952   globalParamsUnlock;
953   return d;
954 }
955
956 PSLevel GlobalParams::getPSLevel() {
957   PSLevel level;
958
959   globalParamsLock;
960   level = psLevel;
961   globalParamsUnlock;
962   return level;
963 }
964
965 PSFontParam *GlobalParams::getPSFont(GString *fontName) {
966   return (PSFontParam *)psFonts->lookup(fontName);
967 }
968
969 PSFontParam *GlobalParams::getPSFont16(GString *fontName,
970                                        GString *collection, int wMode) {
971   PSFontParam *p;
972   int i;
973
974   p = NULL;
975   if (fontName) {
976     for (i = 0; i < psNamedFonts16->getLength(); ++i) {
977       p = (PSFontParam *)psNamedFonts16->get(i);
978       if (!p->pdfFontName->cmp(fontName) &&
979           p->wMode == wMode) {
980         break;
981       }
982       p = NULL;
983     }
984   }
985   if (!p && collection) {
986     for (i = 0; i < psFonts16->getLength(); ++i) {
987       p = (PSFontParam *)psFonts16->get(i);
988       if (!p->pdfFontName->cmp(collection) &&
989           p->wMode == wMode) {
990         break;
991       }
992       p = NULL;
993     }
994   }
995   return p;
996 }
997
998 GBool GlobalParams::getPSEmbedType1() {
999   GBool e;
1000
1001   globalParamsLock;
1002   e = psEmbedType1;
1003   globalParamsUnlock;
1004   return e;
1005 }
1006
1007 GBool GlobalParams::getPSEmbedTrueType() {
1008   GBool e;
1009
1010   globalParamsLock;
1011   e = psEmbedTrueType;
1012   globalParamsUnlock;
1013   return e;
1014 }
1015
1016 GBool GlobalParams::getPSEmbedCIDPostScript() {
1017   GBool e;
1018
1019   globalParamsLock;
1020   e = psEmbedCIDPostScript;
1021   globalParamsUnlock;
1022   return e;
1023 }
1024
1025 GBool GlobalParams::getPSEmbedCIDTrueType() {
1026   GBool e;
1027
1028   globalParamsLock;
1029   e = psEmbedCIDTrueType;
1030   globalParamsUnlock;
1031   return e;
1032 }
1033
1034 GBool GlobalParams::getPSOPI() {
1035   GBool opi;
1036
1037   globalParamsLock;
1038   opi = psOPI;
1039   globalParamsUnlock;
1040   return opi;
1041 }
1042
1043 GBool GlobalParams::getPSASCIIHex() {
1044   GBool ah;
1045
1046   globalParamsLock;
1047   ah = psASCIIHex;
1048   globalParamsUnlock;
1049   return ah;
1050 }
1051
1052 EndOfLineKind GlobalParams::getTextEOL() {
1053   EndOfLineKind eol;
1054
1055   globalParamsLock;
1056   eol = textEOL;
1057   globalParamsUnlock;
1058   return eol;
1059 }
1060
1061 GBool GlobalParams::getTextKeepTinyChars() {
1062   GBool tiny;
1063
1064   globalParamsLock;
1065   tiny = textKeepTinyChars;
1066   globalParamsUnlock;
1067   return tiny;
1068 }
1069
1070 GString *GlobalParams::findFontFile(GString *fontName, char **exts) {
1071   GString *dir, *fileName;
1072   char **ext;
1073   FILE *f;
1074   int i;
1075
1076   for (i = 0; i < fontDirs->getLength(); ++i) {
1077     dir = (GString *)fontDirs->get(i);
1078     for (ext = exts; *ext; ++ext) {
1079       fileName = appendToPath(dir->copy(), fontName->getCString());
1080       fileName->append(*ext);
1081       if ((f = fopen(fileName->getCString(), "r"))) {
1082         fclose(f);
1083         return fileName;
1084       }
1085       delete fileName;
1086     }
1087   }
1088   return NULL;
1089 }
1090
1091 GString *GlobalParams::getInitialZoom() {
1092   GString *s;
1093
1094   globalParamsLock;
1095   s = initialZoom->copy();
1096   globalParamsUnlock;
1097   return s;
1098 }
1099
1100 FontRastControl GlobalParams::getT1libControl() {
1101   FontRastControl c;
1102
1103   globalParamsLock;
1104   c = t1libControl;
1105   globalParamsUnlock;
1106   return c;
1107 }
1108
1109 FontRastControl GlobalParams::getFreeTypeControl() {
1110   FontRastControl c;
1111
1112   globalParamsLock;
1113   c = freetypeControl;
1114   globalParamsUnlock;
1115   return c;
1116 }
1117
1118 GBool GlobalParams::getMapNumericCharNames() {
1119   GBool map;
1120
1121   globalParamsLock;
1122   map = mapNumericCharNames;
1123   globalParamsUnlock;
1124   return map;
1125 }
1126
1127 GBool GlobalParams::getPrintCommands() {
1128   GBool p;
1129
1130   globalParamsLock;
1131   p = printCommands;
1132   globalParamsUnlock;
1133   return p;
1134 }
1135
1136 GBool GlobalParams::getErrQuiet() {
1137   GBool q;
1138
1139   globalParamsLock;
1140   q = errQuiet;
1141   globalParamsUnlock;
1142   return q;
1143 }
1144
1145 CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) {
1146   CharCodeToUnicode *ctu;
1147
1148   globalParamsLock;
1149   ctu = cidToUnicodeCache->getCIDToUnicode(collection);
1150   globalParamsUnlock;
1151   return ctu;
1152 }
1153
1154 UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) {
1155   UnicodeMap *map;
1156
1157   globalParamsLock;
1158   map = getUnicodeMap2(encodingName);
1159   globalParamsUnlock;
1160   return map;
1161 }
1162
1163 UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) {
1164   UnicodeMap *map;
1165
1166   if ((map = getResidentUnicodeMap(encodingName))) {
1167     map->incRefCnt();
1168   } else {
1169     map = unicodeMapCache->getUnicodeMap(encodingName);
1170   }
1171   return map;
1172 }
1173
1174 CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) {
1175   CMap *cMap;
1176
1177   globalParamsLock;
1178   cMap = cMapCache->getCMap(collection, cMapName);
1179   globalParamsUnlock;
1180   return cMap;
1181 }
1182
1183 UnicodeMap *GlobalParams::getTextEncoding() {
1184   UnicodeMap *map;
1185
1186   globalParamsLock;
1187   map = getUnicodeMap2(textEncoding);
1188   globalParamsUnlock;
1189   return map;
1190 }
1191
1192 //------------------------------------------------------------------------
1193 // functions to set parameters
1194 //------------------------------------------------------------------------
1195
1196 void GlobalParams::addDisplayFont(DisplayFontParam *param) {
1197   DisplayFontParam *old;
1198
1199   globalParamsLock;
1200   if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) {
1201     delete old;
1202   }
1203   displayFonts->add(param->name, param);
1204   globalParamsUnlock;
1205 }
1206
1207 void GlobalParams::setPSFile(char *file) {
1208   globalParamsLock;
1209   if (psFile) {
1210     delete psFile;
1211   }
1212   psFile = new GString(file);
1213   globalParamsUnlock;
1214 }
1215
1216 GBool GlobalParams::setPSPaperSize(char *size) {
1217   globalParamsLock;
1218   if (!strcmp(size, "match")) {
1219     psPaperWidth = psPaperHeight = -1;
1220   } else if (!strcmp(size, "letter")) {
1221     psPaperWidth = 612;
1222     psPaperHeight = 792;
1223   } else if (!strcmp(size, "legal")) {
1224     psPaperWidth = 612;
1225     psPaperHeight = 1008;
1226   } else if (!strcmp(size, "A4")) {
1227     psPaperWidth = 595;
1228     psPaperHeight = 842;
1229   } else if (!strcmp(size, "A3")) {
1230     psPaperWidth = 842;
1231     psPaperHeight = 1190;
1232   } else {
1233     globalParamsUnlock;
1234     return gFalse;
1235   }
1236   globalParamsUnlock;
1237   return gTrue;
1238 }
1239
1240 void GlobalParams::setPSPaperWidth(int width) {
1241   globalParamsLock;
1242   psPaperWidth = width;
1243   globalParamsUnlock;
1244 }
1245
1246 void GlobalParams::setPSPaperHeight(int height) {
1247   globalParamsLock;
1248   psPaperHeight = height;
1249   globalParamsUnlock;
1250 }
1251
1252 void GlobalParams::setPSDuplex(GBool duplex) {
1253   globalParamsLock;
1254   psDuplex = duplex;
1255   globalParamsUnlock;
1256 }
1257
1258 void GlobalParams::setPSLevel(PSLevel level) {
1259   globalParamsLock;
1260   psLevel = level;
1261   globalParamsUnlock;
1262 }
1263
1264 void GlobalParams::setPSEmbedType1(GBool embed) {
1265   globalParamsLock;
1266   psEmbedType1 = embed;
1267   globalParamsUnlock;
1268 }
1269
1270 void GlobalParams::setPSEmbedTrueType(GBool embed) {
1271   globalParamsLock;
1272   psEmbedTrueType = embed;
1273   globalParamsUnlock;
1274 }
1275
1276 void GlobalParams::setPSEmbedCIDPostScript(GBool embed) {
1277   globalParamsLock;
1278   psEmbedCIDPostScript = embed;
1279   globalParamsUnlock;
1280 }
1281
1282 void GlobalParams::setPSEmbedCIDTrueType(GBool embed) {
1283   globalParamsLock;
1284   psEmbedCIDTrueType = embed;
1285   globalParamsUnlock;
1286 }
1287
1288 void GlobalParams::setPSOPI(GBool opi) {
1289   globalParamsLock;
1290   psOPI = opi;
1291   globalParamsUnlock;
1292 }
1293
1294 void GlobalParams::setPSASCIIHex(GBool hex) {
1295   globalParamsLock;
1296   psASCIIHex = hex;
1297   globalParamsUnlock;
1298 }
1299
1300 void GlobalParams::setTextEncoding(char *encodingName) {
1301   globalParamsLock;
1302   delete textEncoding;
1303   textEncoding = new GString(encodingName);
1304   globalParamsUnlock;
1305 }
1306
1307 GBool GlobalParams::setTextEOL(char *s) {
1308   globalParamsLock;
1309   if (!strcmp(s, "unix")) {
1310     textEOL = eolUnix;
1311   } else if (!strcmp(s, "dos")) {
1312     textEOL = eolDOS;
1313   } else if (!strcmp(s, "mac")) {
1314     textEOL = eolMac;
1315   } else {
1316     globalParamsUnlock;
1317     return gFalse;
1318   }
1319   globalParamsUnlock;
1320   return gTrue;
1321 }
1322
1323 void GlobalParams::setTextKeepTinyChars(GBool keep) {
1324   globalParamsLock;
1325   textKeepTinyChars = keep;
1326   globalParamsUnlock;
1327 }
1328
1329 void GlobalParams::setInitialZoom(char *s) {
1330   globalParamsLock;
1331   delete initialZoom;
1332   initialZoom = new GString(s);
1333   globalParamsUnlock;
1334 }
1335
1336 GBool GlobalParams::setT1libControl(char *s) {
1337   GBool ok;
1338
1339   globalParamsLock;
1340   ok = setFontRastControl(&t1libControl, s);
1341   globalParamsUnlock;
1342   return ok;
1343 }
1344
1345 GBool GlobalParams::setFreeTypeControl(char *s) {
1346   GBool ok;
1347
1348   globalParamsLock;
1349   ok = setFontRastControl(&freetypeControl, s);
1350   globalParamsUnlock;
1351   return ok;
1352 }
1353
1354 GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) {
1355   if (!strcmp(s, "none")) {
1356     *val = fontRastNone;
1357   } else if (!strcmp(s, "plain")) {
1358     *val = fontRastPlain;
1359   } else if (!strcmp(s, "low")) {
1360     *val = fontRastAALow;
1361   } else if (!strcmp(s, "high")) {
1362     *val = fontRastAAHigh;
1363   } else {
1364     return gFalse;
1365   }
1366   return gTrue;
1367 }
1368
1369 void GlobalParams::setMapNumericCharNames(GBool map) {
1370   globalParamsLock;
1371   mapNumericCharNames = map;
1372   globalParamsUnlock;
1373 }
1374
1375 void GlobalParams::setPrintCommands(GBool printCommandsA) {
1376   globalParamsLock;
1377   printCommands = printCommandsA;
1378   globalParamsUnlock;
1379 }
1380
1381 void GlobalParams::setErrQuiet(GBool errQuietA) {
1382   globalParamsLock;
1383   errQuiet = errQuietA;
1384   globalParamsUnlock;
1385 }