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
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";
51 /* Some notes on the groff_font(8) manpage:
53 DESC file format: A typical PostScript `res' would be 72000, with
54 `hor' and `vert' set to 1 to indicate that all those positions are
55 valid. `sizescale' of 1000 would indicate that a scaled point is
56 1/1000 of a point (which is 1/72000 of an inch, the same as the
57 number of machine units per inch indicated on `res'). `unitwidth'
58 of 1000 would indicate that font files are set up for fonts with
59 point size of 1000 scaled points, which would equal 1/72 inch or 1
60 point (this would tell Groff's postprocessor that it needs to scale
61 the font 12 times larger to get a 12-point font). */
63 /* Reads a Groff font description file and converts it to a usable
64 binary format in memory. Installs the binary format in the global
65 font table. See groff_font(8) for a description of the font
66 description format supported. Returns nonzero on success. */
68 groff_read_font (const char *fn)
70 struct char_metrics *metrics;
72 /* Pool created for font, font being created, font file. */
73 struct pool *font_pool = NULL;
74 struct font_desc *font = NULL;
77 /* Current line, size of line buffer, length of line. */
82 /* Tokenization saved pointer. */
85 /* First token on line. */
88 /* 0=kernpairs section, 1=charset section. */
91 /* Index for previous line. */
94 /* Current location in file, used for error reporting. */
95 struct file_locator where;
98 fn = fn_tilde_expand (fn);
101 msg (VM (1), _("%s: Opening Groff font file..."), fn);
104 where.line_number = 1;
105 err_push_file_locator (&where);
111 font_pool = pool_create ();
112 font = pool_alloc (font_pool, sizeof *font);
113 font->owner = font_pool;
115 font->internal_name = NULL;
116 font->encoding = NULL;
117 font->space_width = 0;
122 font->deref_size = 0;
124 font->metric_size = 0;
125 font->metric_used = 0;
129 font->kern_max_used = 0;
131 /* Parses first section of font file. */
134 /* Location of '#' in line. */
137 len = getline (&line, &size, f);
141 scan_badchars (line, len);
142 p = strchr (line, '#');
144 *p = '\0'; /* Reject comments. */
146 key = strtok_r (line, whitespace, &sp);
150 if (!strcmp (key, "internalname"))
152 font->internal_name = strtok_r (NULL, whitespace, &sp);
153 if (font->internal_name == NULL)
155 font_msg (SE, _("Missing font name."));
158 font->internal_name = pool_strdup (font_pool, font->internal_name);
160 else if (!strcmp (key, "encoding"))
162 font->encoding = strtok_r (NULL, whitespace, &sp);
163 if (font->encoding == NULL)
165 font_msg (SE, _("Missing encoding filename."));
168 font->encoding = pool_strdup (font_pool, font->encoding);
170 else if (!strcmp (key, "spacewidth"))
172 char *n = strtok_r (NULL, whitespace, &sp);
175 font->space_width = strtol (n, &tail, 10);
176 if (n == NULL || tail == n)
178 font_msg (SE, _("Bad spacewidth value."));
182 else if (!strcmp (key, "slant"))
184 char *n = strtok_r (NULL, whitespace, &sp);
187 font->slant = strtod (n, &tail);
188 if (n == NULL || tail == n)
190 font_msg (SE, _("Bad slant value."));
194 else if (!strcmp (key, "ligatures"))
200 lig = strtok_r (NULL, whitespace, &sp);
201 if (!lig || !strcmp (lig, "0"))
203 else if (!strcmp (lig, "ff"))
204 font->ligatures |= LIG_ff;
205 else if (!strcmp (lig, "ffi"))
206 font->ligatures |= LIG_ffi;
207 else if (!strcmp (lig, "ffl"))
208 font->ligatures |= LIG_ffl;
209 else if (!strcmp (lig, "fi"))
210 font->ligatures |= LIG_fi;
211 else if (!strcmp (lig, "fl"))
212 font->ligatures |= LIG_fl;
215 font_msg (SE, _("Unknown ligature `%s'."), lig);
220 else if (!strcmp (key, "special"))
222 else if (!strcmp (key, "charset") || !strcmp (key, "kernpairs"))
230 /* Parses second section of font file (metrics & kerning data). */
233 key = strtok_r (line, whitespace, &sp);
237 if (!strcmp (key, "charset"))
239 else if (!strcmp (key, "kernpairs"))
243 struct char_metrics *metrics = pool_alloc (font_pool,
245 char *m, *type, *code, *tail;
247 m = strtok_r (NULL, whitespace, &sp);
250 font_msg (SE, _("Unexpected end of line reading character "
254 if (!strcmp (m, "\""))
258 font_msg (SE, _("Can't use ditto mark for first character."));
261 if (!strcmp (key, "---"))
263 font_msg (SE, _("Can't ditto into an unnamed character."));
266 dup_char_metric (font, font_char_name_to_index (key), prev_index);
273 metrics->code = metrics->width
274 = metrics->height = metrics->depth = 0;
277 if (m == NULL || 1 > sscanf (m, "%d,%d,%d", &metrics->width,
278 &metrics->height, &metrics->depth))
280 font_msg (SE, _("Missing metrics for character `%s'."), key);
284 type = strtok_r (NULL, whitespace, &sp);
286 metrics->type = strtol (type, &tail, 10);
287 if (!type || tail == type)
289 font_msg (SE, _("Missing type for character `%s'."), key);
293 code = strtok_r (NULL, whitespace, &sp);
295 metrics->code = strtol (code, &tail, 0);
298 font_msg (SE, _("Missing code for character `%s'."), key);
302 if (strcmp (key, "---"))
303 prev_index = font_char_name_to_index (key);
305 prev_index = font_number_to_index (metrics->code);
306 add_char_metric (font, metrics, prev_index);
311 char *c2 = strtok_r (NULL, whitespace, &sp);
317 font_msg (SE, _("Malformed kernpair."));
321 n = strtok_r (NULL, whitespace, &sp);
324 font_msg (SE, _("Unexpected end of line reading kernpairs."));
327 adjust = strtol (n, &tail, 10);
328 if (tail == n || *tail)
330 font_msg (SE, _("Bad kern value."));
333 add_kern (font, font_char_name_to_index (c1),
334 font_char_name_to_index (c2), adjust);
340 len = getline (&line, &size, f);
346 if (fclose (f) == EOF)
356 /* Get font ascent and descent. */
357 metrics = font_get_char_metrics (font, font_char_name_to_index ("d"));
358 font->ascent = metrics ? metrics->height : 0;
359 metrics = font_get_char_metrics (font, font_char_name_to_index ("p"));
360 font->descent = metrics ? metrics->depth : 0;
362 msg (VM (2), _("Font read successfully with internal name %s."),
363 font->internal_name == NULL ? "<none>" : font->internal_name);
365 err_pop_file_locator (&where);
369 /* Come here on a file error. */
371 msg (ME, "%s: %s", fn, strerror (errno));
373 /* Come here on any error. */
377 pool_destroy (font_pool);
381 err_pop_file_locator (&where);
383 msg (VM (1), _("Error reading font."));
387 /* Prints a font error on stderr. */
389 font_msg (int class, const char *format,...)
393 va_start (args, format);
394 tmsg (class, format, args, _("installation error: Groff font error: "));
400 /* Scans string LINE of length LEN (not incl. null terminator) for bad
401 characters, converts to spaces; reports warnings on file FN. */
403 scan_badchars (char *line, int len)
405 unsigned char *cp = line;
407 /* Same bad characters as Groff. */
408 static unsigned char badchars[32] =
410 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
412 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
417 if (badchars[*cp >> 3] & (1 << (*cp & 7)))
419 font_msg (SE, _("Bad character \\%3o."), *cp);
424 /* Character name hashing. */
426 /* Associates a character index with a character name. */
433 /* Character index hash table. */
436 int size; /* Size of table (must be power of 2). */
437 int used; /* Number of full entries. */
438 int next_index; /* Next index to allocate. */
439 struct index_hash *tab; /* Hash table proper. */
440 struct pool *ar; /* Pool for names. */
447 space_index = font_char_name_to_index ("space");
454 pool_destroy(hash.ar);
458 /* Searches for NAME in the global character code table, returns the
459 index if found; otherwise inserts NAME and returns the new
462 font_char_name_to_index (const char *name)
468 if (name[0] == '\0' || name[1] == '\0')
470 if (0 == strncmp (name, "char", 4))
473 int x = strtol (name + 4, &tail, 10);
474 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
482 hash.next_index = 256;
483 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
484 hash.ar = pool_create ();
485 for (i = 0; i < hash.size; i++)
486 hash.tab[i].name = NULL;
489 for (i = hsh_hash_string (name) & (hash.size - 1); hash.tab[i].name; )
491 if (!strcmp (hash.tab[i].name, name))
492 return hash.tab[i].index;
493 if (++i >= hash.size)
498 if (hash.used >= hash.size / 2)
500 struct index_hash *old_tab = hash.tab;
501 int old_size = hash.size;
505 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
506 for (i = 0; i < hash.size; i++)
507 hash.tab[i].name = NULL;
508 for (i = 0; i < old_size; i++)
511 for (j = hsh_hash_string (old_tab[i].name) & (hash.size - 1);
513 if (++j >= hash.size)
515 hash.tab[j] = old_tab[i];
520 hash.tab[i].name = pool_strdup (hash.ar, name);
521 hash.tab[i].index = hash.next_index;
522 return hash.next_index++;
525 /* Returns an index for a character that has only a code, not a
528 font_number_to_index (int x)
530 char name[INT_DIGITS + 2];
532 /* Note that space is the only character that can't appear in a
533 character name. That makes it an excellent choice for a name
534 that won't conflict. */
535 sprintf (name, " %d", x);
536 return font_char_name_to_index (name);
539 /* Font character metric entries. */
541 /* Ensures room for at least MIN_SIZE metric indexes in deref of
544 check_deref_space (struct font_desc *font, int min_size)
546 if (min_size >= font->deref_size)
548 int i = font->deref_size;
550 font->deref_size = min_size + 16;
551 if (font->deref_size < 256)
552 font->deref_size = 256;
553 font->deref = pool_realloc (font->owner, font->deref,
554 sizeof *font->deref * font->deref_size);
555 for (; i < font->deref_size; i++)
560 /* Inserts METRICS for character with code CODE into FONT. */
562 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
564 check_deref_space (font, code);
565 if (font->metric_used >= font->metric_size)
567 font->metric_size += 64;
568 font->metric = pool_realloc (font->owner, font->metric,
569 sizeof *font->metric * font->metric_size);
571 font->metric[font->metric_used] = metrics;
572 font->deref[code] = font->metric_used++;
575 /* Copies metric in FONT from character with code SRC to character
578 dup_char_metric (struct font_desc *font, int dest, int src)
580 check_deref_space (font, dest);
581 assert (font->deref[src] != -1);
582 font->deref[dest] = font->deref[src];
587 /* Returns a hash value for characters with codes CH1 and CH2. */
588 #define hash_kern(CH1, CH2) \
589 ((unsigned) (((CH1) << 16) ^ (CH2)))
591 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
594 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
598 if (font->kern_used >= font->kern_max_used)
600 struct kern_pair *old_kern = font->kern;
601 int old_kern_size = font->kern_size;
604 font->kern_size *= 2;
605 font->kern_max_used = font->kern_size / 2;
606 font->kern = pool_malloc (font->owner,
607 sizeof *font->kern * font->kern_size);
608 for (i = 0; i < font->kern_size; i++)
609 font->kern[i].ch1 = -1;
613 for (i = 0; i < old_kern_size; i++)
615 if (old_kern[i].ch1 == -1)
618 j = (hash_kern (old_kern[i].ch1, old_kern[i].ch2)
619 & (font->kern_size - 1));
620 while (font->kern[j].ch1 != -1)
622 j = font->kern_size - 1;
623 font->kern[j] = old_kern[i];
625 pool_free (font->owner, old_kern);
629 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
630 font->kern[i].ch1 != -1; )
632 i = font->kern_size - 1;
633 font->kern[i].ch1 = ch1;
634 font->kern[i].ch2 = ch2;
635 font->kern[i].adjust = adjust;
639 /* Finds a font file corresponding to font NAME for device DEV. */
641 find_font_file (const char *dev, const char *name)
643 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
648 cp = stpcpy (basename, "dev");
649 cp = stpcpy (cp, dev);
650 *cp++ = DIR_SEPARATOR;
654 1. $STAT_GROFF_FONT_PATH
656 3. GROFF_FONT_PATH from pref.h
659 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
660 && (filename = fn_search_path (basename, path, NULL)) != NULL)
663 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
664 && (filename = fn_search_path (basename, path, NULL)) != NULL)
667 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
670 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
673 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
680 /* Finds a font for device DEV with name NAME, reads it with
681 groff_read_font(), and returns the resultant font. */
683 groff_find_font (const char *dev, const char *name)
685 char *filename = find_font_file (dev, name);
686 struct font_desc *fd;
690 fd = groff_read_font (filename);
695 /* Reads a DESC file for device DEV and sets the appropriate fields in
696 output driver *DRIVER, which must be previously allocated. Returns
697 nonzero on success. */
699 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
701 char *filename; /* Full name of DESC file. */
702 FILE *f; /* DESC file. */
704 char *line = NULL; /* Current line. */
705 int line_len; /* Number of chars in current line. */
706 size_t line_size = 0; /* Number of chars allocated for line. */
708 char *token; /* strtok()'d token inside line. */
710 unsigned found = 0; /* Bitmask showing what settings
711 have been encountered. */
713 int m_sizes = 0; /* Number of int[2] items that
714 can fit in driver->sizes. */
716 char *sp; /* Tokenization string pointer. */
717 struct file_locator where;
727 for (i = 0; i < 4; i++)
728 dev->font_name[i] = NULL;
730 filename = find_font_file (dev_name, "DESC");
734 where.filename = filename;
735 where.line_number = 0;
736 err_push_file_locator (&where);
738 msg (VM (1), _("%s: Opening Groff description file..."), filename);
739 f = fopen (filename, "r");
743 while ((line_len = getline (&line, &line_size, f)) != -1)
747 token = strtok_r (line, whitespace, &sp);
751 if (!strcmp (token, "sizes"))
754 font_msg (SW, _("Multiple `sizes' declarations."));
762 token = strtok_r (NULL, whitespace, &sp);
767 if ((line_len = getline (&line, &line_size, f)) != -1)
771 font_msg (SE, _("Unexpected end of file. "
772 "Missing 0 terminator to `sizes' command?"));
777 if (!strcmp (token, "0"))
781 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
783 font_msg (SE, _("Bad argument to `sizes'."));
788 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
790 font_msg (SE, _("Bad argument to `sizes'."));
795 font_msg (SE, _("Bad range in argument to `sizes'."));
803 font_msg (SE, _("Bad argument to `sizes'."));
807 if (dev->n_sizes + 2 >= m_sizes)
810 dev->sizes = xrealloc (dev->sizes,
811 m_sizes * sizeof *dev->sizes);
813 dev->sizes[dev->n_sizes++][0] = lower;
814 dev->sizes[dev->n_sizes][1] = upper;
819 else if (!strcmp (token, "family"))
821 token = strtok_r (NULL, whitespace, &sp);
824 font_msg (SE, _("Family name expected."));
829 font_msg (SE, _("This command already specified."));
832 dev->family = xstrdup (token);
834 else if (!strcmp (token, "charset"))
838 static const char *id[]
839 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
843 for (cp = id; *cp; cp++)
844 if (!strcmp (token, *cp))
847 continue; /* completely ignore unrecognized lines */
848 if (found & (1 << (cp - id)))
849 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
851 token = strtok_r (NULL, whitespace, &sp);
853 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
855 font_msg (SE, _("%s: Invalid numeric format."), *cp);
858 found |= (1 << (cp - id));
871 dev->size_scale = value;
874 dev->unit_width = value;
883 if ((found & 0x10011) != 0x10011)
885 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
889 /* Font name = family name + suffix. */
891 static const char *suffix[4] =
892 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
893 int len; /* length of family name */
897 dev->family = xstrdup ("");
898 len = strlen (dev->family);
899 for (i = 0; i < 4; i++)
902 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
903 cp = stpcpy (dev->font_name[i], dev->family);
904 strcpy (cp, suffix[i]);
908 dev->sizes[dev->n_sizes][0] = 0;
909 dev->sizes[dev->n_sizes][1] = 0;
911 msg (VM (2), _("Description file read successfully."));
913 err_pop_file_locator (&where);
918 /* Come here on a file error. */
920 msg (ME, "%s: %s", filename, strerror (errno));
922 /* Come here on any error. */
932 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
934 for (i = 0; i < 4; i++)
936 free (dev->font_name[i]);
937 dev->font_name[i] = NULL;
941 err_pop_file_locator (&where);
943 msg (VM (1), _("Error reading description file."));
948 /* Finds character with index CH (as returned by name_to_index() or
949 number_to_index()) in font FONT and returns the associated metrics.
950 Nonexistent characters have width 0. */
951 struct char_metrics *
952 font_get_char_metrics (const struct font_desc *font, int ch)
956 if (ch < 0 || ch >= font->deref_size)
959 index = font->deref[ch];
963 return font->metric[index];
966 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
967 FONT and returns the associated kerning adjustment. */
969 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
975 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
976 font->kern[i].ch1 != -1;)
978 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
979 return font->kern[i].adjust;
981 i = font->kern_size - 1;
986 /* Returns a twelve-point fixed-pitch font that can be used as a
987 last-resort fallback. */
991 struct pool *font_pool;
992 static struct font_desc *font;
996 font_pool = pool_create ();
997 font = pool_alloc (font_pool, sizeof *font);
998 font->owner = font_pool;
1000 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
1001 font->encoding = pool_strdup (font_pool, "text.enc");
1002 font->space_width = 12000;
1004 font->ligatures = 0;
1006 font->ascent = 8000;
1007 font->descent = 4000;
1009 font->deref_size = 0;
1010 font->metric = NULL;
1011 font->metric_size = 0;
1012 font->metric_used = 0;
1014 font->kern_size = 8;
1015 font->kern_used = 0;
1016 font->kern_max_used = 0;