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., 59 Temple Place - Suite 330, Boston, MA
36 int font_number_to_index (int);
40 static int font_msg (int, const char *,...)
42 static void scan_badchars (char *, int);
43 static void dup_char_metric (struct font_desc * font, int dest, int src);
44 static void add_char_metric (struct font_desc * font, struct char_metrics *metrics,
46 static void add_kern (struct font_desc * font, int ch1, int ch2, int adjust);
48 /* Typical whitespace characters for tokenizing. */
49 static const char whitespace[] = " \t\n\r\v";
54 space_index = font_char_name_to_index ("space");
57 /* Some notes on the groff_font(8) manpage:
59 DESC file format: A typical PostScript `res' would be 72000, with
60 `hor' and `vert' set to 1 to indicate that all those positions are
61 valid. `sizescale' of 1000 would indicate that a scaled point is
62 1/1000 of a point (which is 1/72000 of an inch, the same as the
63 number of machine units per inch indicated on `res'). `unitwidth'
64 of 1000 would indicate that font files are set up for fonts with
65 point size of 1000 scaled points, which would equal 1/72 inch or 1
66 point (this would tell Groff's postprocessor that it needs to scale
67 the font 12 times larger to get a 12-point font). */
69 /* Reads a Groff font description file and converts it to a usable
70 binary format in memory. Installs the binary format in the global
71 font table. See groff_font(8) for a description of the font
72 description format supported. Returns nonzero on success. */
74 groff_read_font (const char *fn)
76 struct char_metrics *metrics;
78 /* Pool created for font, font being created, font file. */
79 struct pool *font_pool = NULL;
80 struct font_desc *font = NULL;
83 /* Current line, size of line buffer, length of line. */
88 /* Tokenization saved pointer. */
91 /* First token on line. */
94 /* 0=kernpairs section, 1=charset section. */
97 /* Index for previous line. */
100 /* Current location in file, used for error reporting. */
101 struct file_locator where;
104 fn = fn_tilde_expand (fn);
107 msg (VM (1), _("%s: Opening Groff font file..."), fn);
110 where.line_number = 1;
111 err_push_file_locator (&where);
117 font_pool = pool_create ();
118 font = pool_alloc (font_pool, sizeof *font);
119 font->owner = font_pool;
121 font->internal_name = NULL;
122 font->encoding = NULL;
123 font->space_width = 0;
128 font->deref_size = 0;
130 font->metric_size = 0;
131 font->metric_used = 0;
135 font->kern_max_used = 0;
137 /* Parses first section of font file. */
140 /* Location of '#' in line. */
143 len = getline (&line, &size, f);
147 scan_badchars (line, len);
148 p = strchr (line, '#');
150 *p = '\0'; /* Reject comments. */
152 key = strtok_r (line, whitespace, &sp);
156 if (!strcmp (key, "internalname"))
158 font->internal_name = strtok_r (NULL, whitespace, &sp);
159 if (font->internal_name == NULL)
161 font_msg (SE, _("Missing font name."));
164 font->internal_name = pool_strdup (font_pool, font->internal_name);
166 else if (!strcmp (key, "encoding"))
168 font->encoding = strtok_r (NULL, whitespace, &sp);
169 if (font->encoding == NULL)
171 font_msg (SE, _("Missing encoding filename."));
174 font->encoding = pool_strdup (font_pool, font->encoding);
176 else if (!strcmp (key, "spacewidth"))
178 char *n = strtok_r (NULL, whitespace, &sp);
181 font->space_width = strtol (n, &tail, 10);
182 if (n == NULL || tail == n)
184 font_msg (SE, _("Bad spacewidth value."));
188 else if (!strcmp (key, "slant"))
190 char *n = strtok_r (NULL, whitespace, &sp);
193 font->slant = strtod (n, &tail);
194 if (n == NULL || tail == n)
196 font_msg (SE, _("Bad slant value."));
200 else if (!strcmp (key, "ligatures"))
206 lig = strtok_r (NULL, whitespace, &sp);
207 if (!lig || !strcmp (lig, "0"))
209 else if (!strcmp (lig, "ff"))
210 font->ligatures |= LIG_ff;
211 else if (!strcmp (lig, "ffi"))
212 font->ligatures |= LIG_ffi;
213 else if (!strcmp (lig, "ffl"))
214 font->ligatures |= LIG_ffl;
215 else if (!strcmp (lig, "fi"))
216 font->ligatures |= LIG_fi;
217 else if (!strcmp (lig, "fl"))
218 font->ligatures |= LIG_fl;
221 font_msg (SE, _("Unknown ligature `%s'."), lig);
226 else if (!strcmp (key, "special"))
228 else if (!strcmp (key, "charset") || !strcmp (key, "kernpairs"))
236 /* Parses second section of font file (metrics & kerning data). */
239 key = strtok_r (line, whitespace, &sp);
243 if (!strcmp (key, "charset"))
245 else if (!strcmp (key, "kernpairs"))
249 struct char_metrics *metrics = pool_alloc (font_pool,
251 char *m, *type, *code, *tail;
253 m = strtok_r (NULL, whitespace, &sp);
256 font_msg (SE, _("Unexpected end of line reading character "
260 if (!strcmp (m, "\""))
264 font_msg (SE, _("Can't use ditto mark for first character."));
267 if (!strcmp (key, "---"))
269 font_msg (SE, _("Can't ditto into an unnamed character."));
272 dup_char_metric (font, font_char_name_to_index (key), prev_index);
279 metrics->code = metrics->width
280 = metrics->height = metrics->depth = 0;
283 if (m == NULL || 1 > sscanf (m, "%d,%d,%d", &metrics->width,
284 &metrics->height, &metrics->depth))
286 font_msg (SE, _("Missing metrics for character `%s'."), key);
290 type = strtok_r (NULL, whitespace, &sp);
292 metrics->type = strtol (type, &tail, 10);
293 if (!type || tail == type)
295 font_msg (SE, _("Missing type for character `%s'."), key);
299 code = strtok_r (NULL, whitespace, &sp);
301 metrics->code = strtol (code, &tail, 0);
304 font_msg (SE, _("Missing code for character `%s'."), key);
308 if (strcmp (key, "---"))
309 prev_index = font_char_name_to_index (key);
311 prev_index = font_number_to_index (metrics->code);
312 add_char_metric (font, metrics, prev_index);
317 char *c2 = strtok_r (NULL, whitespace, &sp);
323 font_msg (SE, _("Malformed kernpair."));
327 n = strtok_r (NULL, whitespace, &sp);
330 font_msg (SE, _("Unexpected end of line reading kernpairs."));
333 adjust = strtol (n, &tail, 10);
334 if (tail == n || *tail)
336 font_msg (SE, _("Bad kern value."));
339 add_kern (font, font_char_name_to_index (c1),
340 font_char_name_to_index (c2), adjust);
346 len = getline (&line, &size, f);
352 if (fclose (f) == EOF)
362 /* Get font ascent and descent. */
363 metrics = font_get_char_metrics (font, font_char_name_to_index ("d"));
364 font->ascent = metrics ? metrics->height : 0;
365 metrics = font_get_char_metrics (font, font_char_name_to_index ("p"));
366 font->descent = metrics ? metrics->depth : 0;
368 msg (VM (2), _("Font read successfully with internal name %s."),
369 font->internal_name == NULL ? "<none>" : font->internal_name);
371 err_pop_file_locator (&where);
375 /* Come here on a file error. */
377 msg (ME, "%s: %s", fn, strerror (errno));
379 /* Come here on any error. */
383 pool_destroy (font_pool);
387 err_pop_file_locator (&where);
389 msg (VM (1), _("Error reading font."));
393 /* Prints a font error on stderr. */
395 font_msg (int class, const char *format,...)
399 va_start (args, format);
400 tmsg (class, format, args, _("installation error: Groff font error: "));
406 /* Scans string LINE of length LEN (not incl. null terminator) for bad
407 characters, converts to spaces; reports warnings on file FN. */
409 scan_badchars (char *line, int len)
411 unsigned char *cp = line;
413 /* Same bad characters as Groff. */
414 static unsigned char badchars[32] =
416 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
423 if (badchars[*cp >> 3] & (1 << (*cp & 7)))
425 font_msg (SE, _("Bad character \\%3o."), *cp);
430 /* Character name hashing. */
432 /* Associates a character index with a character name. */
439 /* Character index hash table. */
442 int size; /* Size of table (must be power of 2). */
443 int used; /* Number of full entries. */
444 int next_index; /* Next index to allocate. */
445 struct index_hash *tab; /* Hash table proper. */
446 struct pool *ar; /* Pool for names. */
450 /* Searches for NAME in the global character code table, returns the
451 index if found; otherwise inserts NAME and returns the new
454 font_char_name_to_index (const char *name)
460 if (name[0] == '\0' || name[1] == '\0')
462 if (0 == strncmp (name, "char", 4))
465 int x = strtol (name + 4, &tail, 10);
466 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
474 hash.next_index = 256;
475 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
476 hash.ar = pool_create ();
477 for (i = 0; i < hash.size; i++)
478 hash.tab[i].name = NULL;
481 for (i = hsh_hash_string (name) & (hash.size - 1); hash.tab[i].name; )
483 if (!strcmp (hash.tab[i].name, name))
484 return hash.tab[i].index;
485 if (++i >= hash.size)
490 if (hash.used >= hash.size / 2)
492 struct index_hash *old_tab = hash.tab;
493 int old_size = hash.size;
497 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
498 for (i = 0; i < hash.size; i++)
499 hash.tab[i].name = NULL;
500 for (i = 0; i < old_size; i++)
503 for (j = hsh_hash_string (old_tab[i].name) & (hash.size - 1);
505 if (++j >= hash.size)
507 hash.tab[j] = old_tab[i];
512 hash.tab[i].name = pool_strdup (hash.ar, name);
513 hash.tab[i].index = hash.next_index;
514 return hash.next_index++;
517 /* Returns an index for a character that has only a code, not a
520 font_number_to_index (int x)
522 char name[INT_DIGITS + 2];
524 /* Note that space is the only character that can't appear in a
525 character name. That makes it an excellent choice for a name
526 that won't conflict. */
527 sprintf (name, " %d", x);
528 return font_char_name_to_index (name);
531 /* Font character metric entries. */
533 /* Ensures room for at least MIN_SIZE metric indexes in deref of
536 check_deref_space (struct font_desc *font, int min_size)
538 if (min_size >= font->deref_size)
540 int i = font->deref_size;
542 font->deref_size = min_size + 16;
543 if (font->deref_size < 256)
544 font->deref_size = 256;
545 font->deref = pool_realloc (font->owner, font->deref,
546 sizeof *font->deref * font->deref_size);
547 for (; i < font->deref_size; i++)
552 /* Inserts METRICS for character with code CODE into FONT. */
554 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
556 check_deref_space (font, code);
557 if (font->metric_used >= font->metric_size)
559 font->metric_size += 64;
560 font->metric = pool_realloc (font->owner, font->metric,
561 sizeof *font->metric * font->metric_size);
563 font->metric[font->metric_used] = metrics;
564 font->deref[code] = font->metric_used++;
567 /* Copies metric in FONT from character with code SRC to character
570 dup_char_metric (struct font_desc *font, int dest, int src)
572 check_deref_space (font, dest);
573 assert (font->deref[src] != -1);
574 font->deref[dest] = font->deref[src];
579 /* Returns a hash value for characters with codes CH1 and CH2. */
580 #define hash_kern(CH1, CH2) \
581 ((unsigned) (((CH1) << 16) ^ (CH2)))
583 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
586 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
590 if (font->kern_used >= font->kern_max_used)
592 struct kern_pair *old_kern = font->kern;
593 int old_kern_size = font->kern_size;
596 font->kern_size *= 2;
597 font->kern_max_used = font->kern_size / 2;
598 font->kern = pool_malloc (font->owner,
599 sizeof *font->kern * font->kern_size);
600 for (i = 0; i < font->kern_size; i++)
601 font->kern[i].ch1 = -1;
605 for (i = 0; i < old_kern_size; i++)
607 if (old_kern[i].ch1 == -1)
610 j = (hash_kern (old_kern[i].ch1, old_kern[i].ch2)
611 & (font->kern_size - 1));
612 while (font->kern[j].ch1 != -1)
614 j = font->kern_size - 1;
615 font->kern[j] = old_kern[i];
617 pool_free (font->owner, old_kern);
621 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
622 font->kern[i].ch1 != -1; )
624 i = font->kern_size - 1;
625 font->kern[i].ch1 = ch1;
626 font->kern[i].ch2 = ch2;
627 font->kern[i].adjust = adjust;
631 /* Finds a font file corresponding to font NAME for device DEV. */
633 find_font_file (const char *dev, const char *name)
635 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
640 cp = stpcpy (basename, "dev");
641 cp = stpcpy (cp, dev);
642 *cp++ = DIR_SEPARATOR;
646 1. $STAT_GROFF_FONT_PATH
648 3. GROFF_FONT_PATH from pref.h
651 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
652 && (filename = fn_search_path (basename, path, NULL)) != NULL)
655 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
656 && (filename = fn_search_path (basename, path, NULL)) != NULL)
659 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
662 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
665 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
672 /* Finds a font for device DEV with name NAME, reads it with
673 groff_read_font(), and returns the resultant font. */
675 groff_find_font (const char *dev, const char *name)
677 char *filename = find_font_file (dev, name);
678 struct font_desc *fd;
682 fd = groff_read_font (filename);
687 /* Reads a DESC file for device DEV and sets the appropriate fields in
688 output driver *DRIVER, which must be previously allocated. Returns
689 nonzero on success. */
691 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
693 char *filename; /* Full name of DESC file. */
694 FILE *f; /* DESC file. */
696 char *line = NULL; /* Current line. */
697 int line_len; /* Number of chars in current line. */
698 size_t line_size = 0; /* Number of chars allocated for line. */
700 char *token; /* strtok()'d token inside line. */
702 unsigned found = 0; /* Bitmask showing what settings
703 have been encountered. */
705 int m_sizes = 0; /* Number of int[2] items that
706 can fit in driver->sizes. */
708 char *sp; /* Tokenization string pointer. */
709 struct file_locator where;
719 for (i = 0; i < 4; i++)
720 dev->font_name[i] = NULL;
722 filename = find_font_file (dev_name, "DESC");
726 where.filename = filename;
727 where.line_number = 0;
728 err_push_file_locator (&where);
730 msg (VM (1), _("%s: Opening Groff description file..."), filename);
731 f = fopen (filename, "r");
735 while ((line_len = getline (&line, &line_size, f)) != -1)
739 token = strtok_r (line, whitespace, &sp);
743 if (!strcmp (token, "sizes"))
746 font_msg (SW, _("Multiple `sizes' declarations."));
754 token = strtok_r (NULL, whitespace, &sp);
759 if ((line_len = getline (&line, &line_size, f)) != -1)
763 font_msg (SE, _("Unexpected end of file. "
764 "Missing 0 terminator to `sizes' command?"));
769 if (!strcmp (token, "0"))
773 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
775 font_msg (SE, _("Bad argument to `sizes'."));
780 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
782 font_msg (SE, _("Bad argument to `sizes'."));
787 font_msg (SE, _("Bad range in argument to `sizes'."));
795 font_msg (SE, _("Bad argument to `sizes'."));
799 if (dev->n_sizes + 2 >= m_sizes)
802 dev->sizes = xrealloc (dev->sizes,
803 m_sizes * sizeof *dev->sizes);
805 dev->sizes[dev->n_sizes++][0] = lower;
806 dev->sizes[dev->n_sizes][1] = upper;
811 else if (!strcmp (token, "family"))
813 token = strtok_r (NULL, whitespace, &sp);
816 font_msg (SE, _("Family name expected."));
821 font_msg (SE, _("This command already specified."));
824 dev->family = xstrdup (token);
826 else if (!strcmp (token, "charset"))
830 static const char *id[]
831 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
835 for (cp = id; *cp; cp++)
836 if (!strcmp (token, *cp))
839 continue; /* completely ignore unrecognized lines */
840 if (found & (1 << (cp - id)))
841 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
843 token = strtok_r (NULL, whitespace, &sp);
845 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
847 font_msg (SE, _("%s: Invalid numeric format."), *cp);
850 found |= (1 << (cp - id));
863 dev->size_scale = value;
866 dev->unit_width = value;
875 if ((found & 0x10011) != 0x10011)
877 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
881 /* Font name = family name + suffix. */
883 static const char *suffix[4] =
884 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
885 int len; /* length of family name */
889 dev->family = xstrdup ("");
890 len = strlen (dev->family);
891 for (i = 0; i < 4; i++)
894 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
895 cp = stpcpy (dev->font_name[i], dev->family);
896 strcpy (cp, suffix[i]);
900 dev->sizes[dev->n_sizes][0] = 0;
901 dev->sizes[dev->n_sizes][1] = 0;
903 msg (VM (2), _("Description file read successfully."));
905 err_pop_file_locator (&where);
910 /* Come here on a file error. */
912 msg (ME, "%s: %s", filename, strerror (errno));
914 /* Come here on any error. */
924 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
926 for (i = 0; i < 4; i++)
928 free (dev->font_name[i]);
929 dev->font_name[i] = NULL;
933 err_pop_file_locator (&where);
935 msg (VM (1), _("Error reading description file."));
940 /* Finds character with index CH (as returned by name_to_index() or
941 number_to_index()) in font FONT and returns the associated metrics.
942 Nonexistent characters have width 0. */
943 struct char_metrics *
944 font_get_char_metrics (const struct font_desc *font, int ch)
948 if (ch < 0 || ch >= font->deref_size)
951 index = font->deref[ch];
955 return font->metric[index];
958 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
959 FONT and returns the associated kerning adjustment. */
961 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
967 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
968 font->kern[i].ch1 != -1;)
970 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
971 return font->kern[i].adjust;
973 i = font->kern_size - 1;
978 /* Returns a twelve-point fixed-pitch font that can be used as a
979 last-resort fallback. */
983 struct pool *font_pool;
984 static struct font_desc *font;
988 font_pool = pool_create ();
989 font = pool_alloc (font_pool, sizeof *font);
990 font->owner = font_pool;
992 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
993 font->encoding = pool_strdup (font_pool, "text.enc");
994 font->space_width = 12000;
999 font->descent = 4000;
1001 font->deref_size = 0;
1002 font->metric = NULL;
1003 font->metric_size = 0;
1004 font->metric_used = 0;
1006 font->kern_size = 8;
1007 font->kern_used = 0;
1008 font->kern_max_used = 0;