1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
38 #define _(msgid) gettext (msgid)
40 int font_number_to_index (int);
44 static int font_msg (int, const char *,...)
46 static void scan_badchars (char *, int);
47 static void dup_char_metric (struct font_desc * font, int dest, int src);
48 static void add_char_metric (struct font_desc * font, struct char_metrics *metrics,
50 static void add_kern (struct font_desc * font, int ch1, int ch2, int adjust);
52 /* Typical whitespace characters for tokenizing. */
53 static const char whitespace[] = " \t\n\r\v";
55 /* Some notes on the groff_font manpage:
57 DESC file format: A typical PostScript `res' would be 72000, with
58 `hor' and `vert' set to 1 to indicate that all those positions are
59 valid. `sizescale' of 1000 would indicate that a scaled point is
60 1/1000 of a point (which is 1/72000 of an inch, the same as the
61 number of machine units per inch indicated on `res'). `unitwidth'
62 of 1000 would indicate that font files are set up for fonts with
63 point size of 1000 scaled points, which would equal 1/72 inch or 1
64 point (this would tell Groff's postprocessor that it needs to scale
65 the font 12 times larger to get a 12-point font). */
67 /* Reads a Groff font description file and converts it to a usable
68 binary format in memory. Installs the binary format in the global
69 font table. See groff_font for a description of the font
70 description format supported. Returns nonzero on success. */
72 groff_read_font (const char *fn)
74 struct char_metrics *metrics;
76 /* Pool created for font, font being created, font file. */
77 struct pool *font_pool = NULL;
78 struct font_desc *font = NULL;
81 /* Current line, size of line buffer, length of line. */
86 /* Tokenization saved pointer. */
89 /* First token on line. */
92 /* 0=kernpairs section, 1=charset section. */
95 /* Index for previous line. */
98 /* Current location in file, used for error reporting. */
99 struct file_locator where;
102 fn = fn_tilde_expand (fn);
105 msg (VM (1), _("%s: Opening Groff font file..."), fn);
108 where.line_number = 1;
109 err_push_file_locator (&where);
115 font_pool = pool_create ();
116 font = pool_alloc (font_pool, sizeof *font);
117 font->owner = font_pool;
119 font->internal_name = NULL;
120 font->encoding = NULL;
121 font->space_width = 0;
126 font->deref_size = 0;
128 font->metric_size = 0;
129 font->metric_used = 0;
133 font->kern_max_used = 0;
135 /* Parses first section of font file. */
138 /* Location of '#' in line. */
141 len = getline (&line, &size, f);
145 scan_badchars (line, len);
146 p = strchr (line, '#');
148 *p = '\0'; /* Reject comments. */
150 key = strtok_r (line, whitespace, &sp);
154 if (!strcmp (key, "internalname"))
156 font->internal_name = strtok_r (NULL, whitespace, &sp);
157 if (font->internal_name == NULL)
159 font_msg (SE, _("Missing font name."));
162 font->internal_name = pool_strdup (font_pool, font->internal_name);
164 else if (!strcmp (key, "encoding"))
166 font->encoding = strtok_r (NULL, whitespace, &sp);
167 if (font->encoding == NULL)
169 font_msg (SE, _("Missing encoding filename."));
172 font->encoding = pool_strdup (font_pool, font->encoding);
174 else if (!strcmp (key, "spacewidth"))
176 char *n = strtok_r (NULL, whitespace, &sp);
179 font->space_width = strtol (n, &tail, 10);
180 if (n == NULL || tail == n)
182 font_msg (SE, _("Bad spacewidth value."));
186 else if (!strcmp (key, "slant"))
188 char *n = strtok_r (NULL, whitespace, &sp);
191 font->slant = strtod (n, &tail);
192 if (n == NULL || tail == n)
194 font_msg (SE, _("Bad slant value."));
198 else if (!strcmp (key, "ligatures"))
204 lig = strtok_r (NULL, whitespace, &sp);
205 if (!lig || !strcmp (lig, "0"))
207 else if (!strcmp (lig, "ff"))
208 font->ligatures |= LIG_ff;
209 else if (!strcmp (lig, "ffi"))
210 font->ligatures |= LIG_ffi;
211 else if (!strcmp (lig, "ffl"))
212 font->ligatures |= LIG_ffl;
213 else if (!strcmp (lig, "fi"))
214 font->ligatures |= LIG_fi;
215 else if (!strcmp (lig, "fl"))
216 font->ligatures |= LIG_fl;
219 font_msg (SE, _("Unknown ligature `%s'."), lig);
224 else if (!strcmp (key, "special"))
226 else if (!strcmp (key, "charset") || !strcmp (key, "kernpairs"))
234 /* Parses second section of font file (metrics & kerning data). */
237 key = strtok_r (line, whitespace, &sp);
241 if (!strcmp (key, "charset"))
243 else if (!strcmp (key, "kernpairs"))
247 struct char_metrics *metrics = pool_alloc (font_pool,
249 char *m, *type, *code, *tail;
251 m = strtok_r (NULL, whitespace, &sp);
254 font_msg (SE, _("Unexpected end of line reading character "
258 if (!strcmp (m, "\""))
262 font_msg (SE, _("Can't use ditto mark for first character."));
265 if (!strcmp (key, "---"))
267 font_msg (SE, _("Can't ditto into an unnamed character."));
270 dup_char_metric (font, font_char_name_to_index (key), prev_index);
277 metrics->code = metrics->width
278 = metrics->height = metrics->depth = 0;
281 if (m == NULL || 1 > sscanf (m, "%d,%d,%d", &metrics->width,
282 &metrics->height, &metrics->depth))
284 font_msg (SE, _("Missing metrics for character `%s'."), key);
288 type = strtok_r (NULL, whitespace, &sp);
290 metrics->type = strtol (type, &tail, 10);
291 if (!type || tail == type)
293 font_msg (SE, _("Missing type for character `%s'."), key);
297 code = strtok_r (NULL, whitespace, &sp);
299 metrics->code = strtol (code, &tail, 0);
302 font_msg (SE, _("Missing code for character `%s'."), key);
306 if (strcmp (key, "---"))
307 prev_index = font_char_name_to_index (key);
309 prev_index = font_number_to_index (metrics->code);
310 add_char_metric (font, metrics, prev_index);
315 char *c2 = strtok_r (NULL, whitespace, &sp);
321 font_msg (SE, _("Malformed kernpair."));
325 n = strtok_r (NULL, whitespace, &sp);
328 font_msg (SE, _("Unexpected end of line reading kernpairs."));
331 adjust = strtol (n, &tail, 10);
332 if (tail == n || *tail)
334 font_msg (SE, _("Bad kern value."));
337 add_kern (font, font_char_name_to_index (c1),
338 font_char_name_to_index (c2), adjust);
344 len = getline (&line, &size, f);
350 if (fclose (f) == EOF)
360 /* Get font ascent and descent. */
361 metrics = font_get_char_metrics (font, font_char_name_to_index ("d"));
362 font->ascent = metrics ? metrics->height : 0;
363 metrics = font_get_char_metrics (font, font_char_name_to_index ("p"));
364 font->descent = metrics ? metrics->depth : 0;
366 msg (VM (2), _("Font read successfully with internal name %s."),
367 font->internal_name == NULL ? "<none>" : font->internal_name);
369 err_pop_file_locator (&where);
373 /* Come here on a file error. */
375 msg (ME, "%s: %s", fn, strerror (errno));
377 /* Come here on any error. */
381 pool_destroy (font_pool);
385 err_pop_file_locator (&where);
387 msg (VM (1), _("Error reading font."));
391 /* Prints a font error on stderr. */
393 font_msg (int class, const char *format,...)
397 va_start (args, format);
398 tmsg (class, format, args, _("installation error: Groff font error: "));
404 /* Scans string LINE of length LEN (not incl. null terminator) for bad
405 characters, converts to spaces; reports warnings on file FN. */
407 scan_badchars (char *line, int len)
411 /* Same bad characters as Groff. */
412 static unsigned char badchars[32] =
414 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
422 int c = (unsigned char) *cp;
423 if (badchars[c >> 3] & (1 << (c & 7)))
425 font_msg (SE, _("Bad character \\%3o."), *cp);
431 /* Character name hashing. */
433 /* Associates a character index with a character name. */
440 /* Character index hash table. */
443 int size; /* Size of table (must be power of 2). */
444 int used; /* Number of full entries. */
445 int next_index; /* Next index to allocate. */
446 struct index_hash *tab; /* Hash table proper. */
447 struct pool *ar; /* Pool for names. */
454 space_index = font_char_name_to_index ("space");
461 pool_destroy(hash.ar);
465 /* Searches for NAME in the global character code table, returns the
466 index if found; otherwise inserts NAME and returns the new
469 font_char_name_to_index (const char *name)
475 if (name[0] == '\0' || name[1] == '\0')
477 if (0 == strncmp (name, "char", 4))
480 int x = strtol (name + 4, &tail, 10);
481 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
489 hash.next_index = 256;
490 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
491 hash.ar = pool_create ();
492 for (i = 0; i < hash.size; i++)
493 hash.tab[i].name = NULL;
496 for (i = hsh_hash_string (name) & (hash.size - 1); hash.tab[i].name; )
498 if (!strcmp (hash.tab[i].name, name))
499 return hash.tab[i].index;
500 if (++i >= hash.size)
505 if (hash.used >= hash.size / 2)
507 struct index_hash *old_tab = hash.tab;
508 int old_size = hash.size;
512 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
513 for (i = 0; i < hash.size; i++)
514 hash.tab[i].name = NULL;
515 for (i = 0; i < old_size; i++)
518 for (j = hsh_hash_string (old_tab[i].name) & (hash.size - 1);
520 if (++j >= hash.size)
522 hash.tab[j] = old_tab[i];
527 hash.tab[i].name = pool_strdup (hash.ar, name);
528 hash.tab[i].index = hash.next_index;
529 return hash.next_index++;
532 /* Returns an index for a character that has only a code, not a
535 font_number_to_index (int x)
537 char name[INT_DIGITS + 2];
539 /* Note that space is the only character that can't appear in a
540 character name. That makes it an excellent choice for a name
541 that won't conflict. */
542 sprintf (name, " %d", x);
543 return font_char_name_to_index (name);
546 /* Font character metric entries. */
548 /* Ensures room for at least MIN_SIZE metric indexes in deref of
551 check_deref_space (struct font_desc *font, int min_size)
553 if (min_size >= font->deref_size)
555 int i = font->deref_size;
557 font->deref_size = min_size + 16;
558 if (font->deref_size < 256)
559 font->deref_size = 256;
560 font->deref = pool_realloc (font->owner, font->deref,
561 sizeof *font->deref * font->deref_size);
562 for (; i < font->deref_size; i++)
567 /* Inserts METRICS for character with code CODE into FONT. */
569 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
571 check_deref_space (font, code);
572 if (font->metric_used >= font->metric_size)
574 font->metric_size += 64;
575 font->metric = pool_realloc (font->owner, font->metric,
576 sizeof *font->metric * font->metric_size);
578 font->metric[font->metric_used] = metrics;
579 font->deref[code] = font->metric_used++;
582 /* Copies metric in FONT from character with code SRC to character
585 dup_char_metric (struct font_desc *font, int dest, int src)
587 check_deref_space (font, dest);
588 assert (font->deref[src] != -1);
589 font->deref[dest] = font->deref[src];
594 /* Returns a hash value for characters with codes CH1 and CH2. */
595 #define hash_kern(CH1, CH2) \
596 ((unsigned) (((CH1) << 16) ^ (CH2)))
598 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
601 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
605 if (font->kern_used >= font->kern_max_used)
607 struct kern_pair *old_kern = font->kern;
608 int old_kern_size = font->kern_size;
611 font->kern_size *= 2;
612 font->kern_max_used = font->kern_size / 2;
613 font->kern = pool_malloc (font->owner,
614 sizeof *font->kern * font->kern_size);
615 for (i = 0; i < font->kern_size; i++)
616 font->kern[i].ch1 = -1;
620 for (i = 0; i < old_kern_size; i++)
622 if (old_kern[i].ch1 == -1)
625 j = (hash_kern (old_kern[i].ch1, old_kern[i].ch2)
626 & (font->kern_size - 1));
627 while (font->kern[j].ch1 != -1)
629 j = font->kern_size - 1;
630 font->kern[j] = old_kern[i];
632 pool_free (font->owner, old_kern);
636 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
637 font->kern[i].ch1 != -1; )
639 i = font->kern_size - 1;
640 font->kern[i].ch1 = ch1;
641 font->kern[i].ch2 = ch2;
642 font->kern[i].adjust = adjust;
646 /* Finds a font file corresponding to font NAME for device DEV. */
648 find_font_file (const char *dev, const char *name)
650 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
655 cp = stpcpy (basename, "dev");
656 cp = stpcpy (cp, dev);
657 *cp++ = DIR_SEPARATOR;
661 1. $STAT_GROFF_FONT_PATH
663 3. GROFF_FONT_PATH from pref.h
666 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
667 && (filename = fn_search_path (basename, path, NULL)) != NULL)
670 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
671 && (filename = fn_search_path (basename, path, NULL)) != NULL)
674 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
677 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
680 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
687 /* Finds a font for device DEV with name NAME, reads it with
688 groff_read_font(), and returns the resultant font. */
690 groff_find_font (const char *dev, const char *name)
692 char *filename = find_font_file (dev, name);
693 struct font_desc *fd;
697 fd = groff_read_font (filename);
702 /* Reads a DESC file for device DEV and sets the appropriate fields in
703 output driver *DRIVER, which must be previously allocated. Returns
704 nonzero on success. */
706 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
708 char *filename; /* Full name of DESC file. */
709 FILE *f; /* DESC file. */
711 char *line = NULL; /* Current line. */
712 int line_len; /* Number of chars in current line. */
713 size_t line_size = 0; /* Number of chars allocated for line. */
715 char *token; /* strtok()'d token inside line. */
717 unsigned found = 0; /* Bitmask showing what settings
718 have been encountered. */
720 int m_sizes = 0; /* Number of int[2] items that
721 can fit in driver->sizes. */
723 char *sp; /* Tokenization string pointer. */
724 struct file_locator where;
734 for (i = 0; i < 4; i++)
735 dev->font_name[i] = NULL;
737 filename = find_font_file (dev_name, "DESC");
741 where.filename = filename;
742 where.line_number = 0;
743 err_push_file_locator (&where);
745 msg (VM (1), _("%s: Opening Groff description file..."), filename);
746 f = fopen (filename, "r");
750 while ((line_len = getline (&line, &line_size, f)) != -1)
754 token = strtok_r (line, whitespace, &sp);
758 if (!strcmp (token, "sizes"))
761 font_msg (SW, _("Multiple `sizes' declarations."));
769 token = strtok_r (NULL, whitespace, &sp);
774 if ((line_len = getline (&line, &line_size, f)) != -1)
778 font_msg (SE, _("Unexpected end of file. "
779 "Missing 0 terminator to `sizes' command?"));
784 if (!strcmp (token, "0"))
788 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
790 font_msg (SE, _("Bad argument to `sizes'."));
795 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
797 font_msg (SE, _("Bad argument to `sizes'."));
802 font_msg (SE, _("Bad range in argument to `sizes'."));
810 font_msg (SE, _("Bad argument to `sizes'."));
814 if (dev->n_sizes + 2 >= m_sizes)
817 dev->sizes = xrealloc (dev->sizes,
818 m_sizes * sizeof *dev->sizes);
820 dev->sizes[dev->n_sizes++][0] = lower;
821 dev->sizes[dev->n_sizes][1] = upper;
826 else if (!strcmp (token, "family"))
828 token = strtok_r (NULL, whitespace, &sp);
831 font_msg (SE, _("Family name expected."));
836 font_msg (SE, _("This command already specified."));
839 dev->family = xstrdup (token);
841 else if (!strcmp (token, "charset"))
845 static const char *id[]
846 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
850 for (cp = id; *cp; cp++)
851 if (!strcmp (token, *cp))
854 continue; /* completely ignore unrecognized lines */
855 if (found & (1 << (cp - id)))
856 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
858 token = strtok_r (NULL, whitespace, &sp);
860 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
862 font_msg (SE, _("%s: Invalid numeric format."), *cp);
865 found |= (1 << (cp - id));
878 dev->size_scale = value;
881 dev->unit_width = value;
890 if ((found & 0x10011) != 0x10011)
892 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
896 /* Font name = family name + suffix. */
898 static const char *suffix[4] =
899 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
900 int len; /* length of family name */
904 dev->family = xstrdup ("");
905 len = strlen (dev->family);
906 for (i = 0; i < 4; i++)
909 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
910 cp = stpcpy (dev->font_name[i], dev->family);
911 strcpy (cp, suffix[i]);
915 dev->sizes[dev->n_sizes][0] = 0;
916 dev->sizes[dev->n_sizes][1] = 0;
918 msg (VM (2), _("Description file read successfully."));
920 err_pop_file_locator (&where);
925 /* Come here on a file error. */
927 msg (ME, "%s: %s", filename, strerror (errno));
929 /* Come here on any error. */
939 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
941 for (i = 0; i < 4; i++)
943 free (dev->font_name[i]);
944 dev->font_name[i] = NULL;
948 err_pop_file_locator (&where);
950 msg (VM (1), _("Error reading description file."));
955 /* Finds character with index CH (as returned by name_to_index() or
956 number_to_index()) in font FONT and returns the associated metrics.
957 Nonexistent characters have width 0. */
958 struct char_metrics *
959 font_get_char_metrics (const struct font_desc *font, int ch)
963 if (ch < 0 || ch >= font->deref_size)
966 index = font->deref[ch];
970 return font->metric[index];
973 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
974 FONT and returns the associated kerning adjustment. */
976 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
982 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
983 font->kern[i].ch1 != -1;)
985 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
986 return font->kern[i].adjust;
988 i = font->kern_size - 1;
993 /* Returns a twelve-point fixed-pitch font that can be used as a
994 last-resort fallback. */
998 struct pool *font_pool;
999 static struct font_desc *font;
1003 font_pool = pool_create ();
1004 font = pool_alloc (font_pool, sizeof *font);
1005 font->owner = font_pool;
1007 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
1008 font->encoding = pool_strdup (font_pool, "text.enc");
1009 font->space_width = 12000;
1011 font->ligatures = 0;
1013 font->ascent = 8000;
1014 font->descent = 4000;
1016 font->deref_size = 0;
1017 font->metric = NULL;
1018 font->metric_size = 0;
1019 font->metric_used = 0;
1021 font->kern_size = 8;
1022 font->kern_used = 0;
1023 font->kern_max_used = 0;