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,...)
399 err_location (&error.where);
400 error.title = _("installation error: Groff font error: ");
402 va_start (args, format);
403 err_vmsg (&error, format, args);
409 /* Scans string LINE of length LEN (not incl. null terminator) for bad
410 characters, converts to spaces; reports warnings on file FN. */
412 scan_badchars (char *line, int len)
416 /* Same bad characters as Groff. */
417 static unsigned char badchars[32] =
419 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
427 int c = (unsigned char) *cp;
428 if (badchars[c >> 3] & (1 << (c & 7)))
430 font_msg (SE, _("Bad character \\%3o."), *cp);
436 /* Character name hashing. */
438 /* Associates a character index with a character name. */
445 /* Character index hash table. */
448 int size; /* Size of table (must be power of 2). */
449 int used; /* Number of full entries. */
450 int next_index; /* Next index to allocate. */
451 struct index_hash *tab; /* Hash table proper. */
452 struct pool *ar; /* Pool for names. */
459 space_index = font_char_name_to_index ("space");
466 pool_destroy(hash.ar);
470 /* Searches for NAME in the global character code table, returns the
471 index if found; otherwise inserts NAME and returns the new
474 font_char_name_to_index (const char *name)
480 if (name[0] == '\0' || name[1] == '\0')
482 if (0 == strncmp (name, "char", 4))
485 int x = strtol (name + 4, &tail, 10);
486 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
494 hash.next_index = 256;
495 hash.tab = xnmalloc (hash.size, sizeof *hash.tab);
496 hash.ar = pool_create ();
497 for (i = 0; i < hash.size; i++)
498 hash.tab[i].name = NULL;
501 for (i = hsh_hash_string (name) & (hash.size - 1); hash.tab[i].name; )
503 if (!strcmp (hash.tab[i].name, name))
504 return hash.tab[i].index;
505 if (++i >= hash.size)
510 if (hash.used >= hash.size / 2)
512 struct index_hash *old_tab = hash.tab;
513 int old_size = hash.size;
517 hash.tab = xnmalloc (hash.size, sizeof *hash.tab);
518 for (i = 0; i < hash.size; i++)
519 hash.tab[i].name = NULL;
520 for (i = 0; i < old_size; i++)
523 for (j = hsh_hash_string (old_tab[i].name) & (hash.size - 1);
525 if (++j >= hash.size)
527 hash.tab[j] = old_tab[i];
532 hash.tab[i].name = pool_strdup (hash.ar, name);
533 hash.tab[i].index = hash.next_index;
534 return hash.next_index++;
537 /* Returns an index for a character that has only a code, not a
540 font_number_to_index (int x)
542 char name[INT_DIGITS + 2];
544 /* Note that space is the only character that can't appear in a
545 character name. That makes it an excellent choice for a name
546 that won't conflict. */
547 sprintf (name, " %d", x);
548 return font_char_name_to_index (name);
551 /* Font character metric entries. */
553 /* Ensures room for at least MIN_SIZE metric indexes in deref of
556 check_deref_space (struct font_desc *font, int min_size)
558 if (min_size >= font->deref_size)
560 int i = font->deref_size;
562 font->deref_size = min_size + 16;
563 if (font->deref_size < 256)
564 font->deref_size = 256;
565 font->deref = pool_nrealloc (font->owner, font->deref,
566 font->deref_size, sizeof *font->deref);
567 for (; i < font->deref_size; i++)
572 /* Inserts METRICS for character with code CODE into FONT. */
574 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
576 check_deref_space (font, code);
577 if (font->metric_used >= font->metric_size)
579 font->metric_size += 64;
580 font->metric = pool_nrealloc (font->owner, font->metric,
581 font->metric_size, sizeof *font->metric);
583 font->metric[font->metric_used] = metrics;
584 font->deref[code] = font->metric_used++;
587 /* Copies metric in FONT from character with code SRC to character
590 dup_char_metric (struct font_desc *font, int dest, int src)
592 check_deref_space (font, dest);
593 assert (font->deref[src] != -1);
594 font->deref[dest] = font->deref[src];
599 /* Returns a hash value for characters with codes CH1 and CH2. */
600 #define hash_kern(CH1, CH2) \
601 ((unsigned) (((CH1) << 16) ^ (CH2)))
603 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
606 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
610 if (font->kern_used >= font->kern_max_used)
612 struct kern_pair *old_kern = font->kern;
613 int old_kern_size = font->kern_size;
616 font->kern_size *= 2;
617 font->kern_max_used = font->kern_size / 2;
618 font->kern = pool_nmalloc (font->owner,
619 font->kern_size, sizeof *font->kern);
620 for (i = 0; i < font->kern_size; i++)
621 font->kern[i].ch1 = -1;
625 for (i = 0; i < old_kern_size; i++)
627 if (old_kern[i].ch1 == -1)
630 j = (hash_kern (old_kern[i].ch1, old_kern[i].ch2)
631 & (font->kern_size - 1));
632 while (font->kern[j].ch1 != -1)
634 j = font->kern_size - 1;
635 font->kern[j] = old_kern[i];
637 pool_free (font->owner, old_kern);
641 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
642 font->kern[i].ch1 != -1; )
644 i = font->kern_size - 1;
645 font->kern[i].ch1 = ch1;
646 font->kern[i].ch2 = ch2;
647 font->kern[i].adjust = adjust;
651 /* Finds a font file corresponding to font NAME for device DEV. */
653 find_font_file (const char *dev, const char *name)
655 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
660 cp = stpcpy (basename, "dev");
661 cp = stpcpy (cp, dev);
662 *cp++ = DIR_SEPARATOR;
666 1. $STAT_GROFF_FONT_PATH
668 3. GROFF_FONT_PATH from pref.h
671 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
672 && (filename = fn_search_path (basename, path, NULL)) != NULL)
675 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
676 && (filename = fn_search_path (basename, path, NULL)) != NULL)
679 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
682 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
685 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
692 /* Finds a font for device DEV with name NAME, reads it with
693 groff_read_font(), and returns the resultant font. */
695 groff_find_font (const char *dev, const char *name)
697 char *filename = find_font_file (dev, name);
698 struct font_desc *fd;
702 fd = groff_read_font (filename);
707 /* Reads a DESC file for device DEV and sets the appropriate fields in
708 output driver *DRIVER, which must be previously allocated. Returns
709 nonzero on success. */
711 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
713 char *filename; /* Full name of DESC file. */
714 FILE *f; /* DESC file. */
716 char *line = NULL; /* Current line. */
717 int line_len; /* Number of chars in current line. */
718 size_t line_size = 0; /* Number of chars allocated for line. */
720 char *token; /* strtok()'d token inside line. */
722 unsigned found = 0; /* Bitmask showing what settings
723 have been encountered. */
725 int m_sizes = 0; /* Number of int[2] items that
726 can fit in driver->sizes. */
728 char *sp; /* Tokenization string pointer. */
729 struct file_locator where;
739 for (i = 0; i < 4; i++)
740 dev->font_name[i] = NULL;
742 filename = find_font_file (dev_name, "DESC");
746 where.filename = filename;
747 where.line_number = 0;
748 err_push_file_locator (&where);
750 msg (VM (1), _("%s: Opening Groff description file..."), filename);
751 f = fopen (filename, "r");
755 while ((line_len = getline (&line, &line_size, f)) != -1)
759 token = strtok_r (line, whitespace, &sp);
763 if (!strcmp (token, "sizes"))
766 font_msg (SW, _("Multiple `sizes' declarations."));
774 token = strtok_r (NULL, whitespace, &sp);
779 if ((line_len = getline (&line, &line_size, f)) != -1)
783 font_msg (SE, _("Unexpected end of file. "
784 "Missing 0 terminator to `sizes' command?"));
789 if (!strcmp (token, "0"))
793 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
795 font_msg (SE, _("Bad argument to `sizes'."));
800 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
802 font_msg (SE, _("Bad argument to `sizes'."));
807 font_msg (SE, _("Bad range in argument to `sizes'."));
815 font_msg (SE, _("Bad argument to `sizes'."));
819 if (dev->n_sizes + 2 >= m_sizes)
822 dev->sizes = xnrealloc (dev->sizes,
823 m_sizes, sizeof *dev->sizes);
825 dev->sizes[dev->n_sizes++][0] = lower;
826 dev->sizes[dev->n_sizes][1] = upper;
831 else if (!strcmp (token, "family"))
833 token = strtok_r (NULL, whitespace, &sp);
836 font_msg (SE, _("Family name expected."));
841 font_msg (SE, _("This command already specified."));
844 dev->family = xstrdup (token);
846 else if (!strcmp (token, "charset"))
850 static const char *id[]
851 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
855 for (cp = id; *cp; cp++)
856 if (!strcmp (token, *cp))
859 continue; /* completely ignore unrecognized lines */
860 if (found & (1 << (cp - id)))
861 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
863 token = strtok_r (NULL, whitespace, &sp);
865 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
867 font_msg (SE, _("%s: Invalid numeric format."), *cp);
870 found |= (1 << (cp - id));
883 dev->size_scale = value;
886 dev->unit_width = value;
895 if ((found & 0x10011) != 0x10011)
897 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
901 /* Font name = family name + suffix. */
903 static const char *suffix[4] =
904 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
905 int len; /* length of family name */
909 dev->family = xstrdup ("");
910 len = strlen (dev->family);
911 for (i = 0; i < 4; i++)
914 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
915 cp = stpcpy (dev->font_name[i], dev->family);
916 strcpy (cp, suffix[i]);
920 dev->sizes[dev->n_sizes][0] = 0;
921 dev->sizes[dev->n_sizes][1] = 0;
923 msg (VM (2), _("Description file read successfully."));
925 err_pop_file_locator (&where);
930 /* Come here on a file error. */
932 msg (ME, "%s: %s", filename, strerror (errno));
934 /* Come here on any error. */
944 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
946 for (i = 0; i < 4; i++)
948 free (dev->font_name[i]);
949 dev->font_name[i] = NULL;
953 err_pop_file_locator (&where);
955 msg (VM (1), _("Error reading description file."));
960 /* Finds character with index CH (as returned by name_to_index() or
961 number_to_index()) in font FONT and returns the associated metrics.
962 Nonexistent characters have width 0. */
963 struct char_metrics *
964 font_get_char_metrics (const struct font_desc *font, int ch)
968 if (ch < 0 || ch >= font->deref_size)
971 index = font->deref[ch];
975 return font->metric[index];
978 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
979 FONT and returns the associated kerning adjustment. */
981 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
987 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
988 font->kern[i].ch1 != -1;)
990 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
991 return font->kern[i].adjust;
993 i = font->kern_size - 1;
998 /* Returns a twelve-point fixed-pitch font that can be used as a
999 last-resort fallback. */
1003 struct pool *font_pool;
1004 static struct font_desc *font;
1008 font_pool = pool_create ();
1009 font = pool_alloc (font_pool, sizeof *font);
1010 font->owner = font_pool;
1012 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
1013 font->encoding = pool_strdup (font_pool, "text.enc");
1014 font->space_width = 12000;
1016 font->ligatures = 0;
1018 font->ascent = 8000;
1019 font->descent = 4000;
1021 font->deref_size = 0;
1022 font->metric = NULL;
1023 font->metric_size = 0;
1024 font->metric_used = 0;
1026 font->kern_size = 8;
1027 font->kern_used = 0;
1028 font->kern_max_used = 0;