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 *,...)
41 __attribute__ ((format (printf, 2, 3)));
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;
603 for (i = 0; i < old_kern_size; i++)
605 if (old_kern[i].ch1 == -1)
608 j = hash_kern (old_kern[i].ch1, old_kern[i].ch2) % font->kern_size;
609 while (font->kern[j].ch1 != -1)
611 j = font->kern_size - 1;
612 font->kern[j] = old_kern[i];
615 pool_free (font->owner, old_kern);
618 for (i = hash_kern (ch1, ch2) % font->kern_size; font->kern[i].ch1 != -1;)
620 i = font->kern_size - 1;
621 font->kern[i].ch1 = ch1;
622 font->kern[i].ch2 = ch2;
623 font->kern[i].adjust = adjust;
627 /* Finds a font file corresponding to font NAME for device DEV. */
629 find_font_file (const char *dev, const char *name)
631 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
636 cp = stpcpy (basename, "dev");
637 cp = stpcpy (cp, dev);
638 *cp++ = DIR_SEPARATOR;
642 1. $STAT_GROFF_FONT_PATH
644 3. GROFF_FONT_PATH from pref.h
647 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
648 && (filename = fn_search_path (basename, path, NULL)) != NULL)
651 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
652 && (filename = fn_search_path (basename, path, NULL)) != NULL)
655 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
658 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
661 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
668 /* Finds a font for device DEV with name NAME, reads it with
669 groff_read_font(), and returns the resultant font. */
671 groff_find_font (const char *dev, const char *name)
673 char *filename = find_font_file (dev, name);
674 struct font_desc *fd;
678 fd = groff_read_font (filename);
683 /* Reads a DESC file for device DEV and sets the appropriate fields in
684 output driver *DRIVER, which must be previously allocated. Returns
685 nonzero on success. */
687 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
689 char *filename; /* Full name of DESC file. */
690 FILE *f; /* DESC file. */
692 char *line = NULL; /* Current line. */
693 int line_len; /* Number of chars in current line. */
694 size_t line_size = 0; /* Number of chars allocated for line. */
696 char *token; /* strtok()'d token inside line. */
698 unsigned found = 0; /* Bitmask showing what settings
699 have been encountered. */
701 int m_sizes = 0; /* Number of int[2] items that
702 can fit in driver->sizes. */
704 char *sp; /* Tokenization string pointer. */
705 struct file_locator where;
715 for (i = 0; i < 4; i++)
716 dev->font_name[i] = NULL;
718 filename = find_font_file (dev_name, "DESC");
722 where.filename = filename;
723 where.line_number = 0;
724 err_push_file_locator (&where);
726 msg (VM (1), _("%s: Opening Groff description file..."), filename);
727 f = fopen (filename, "r");
731 while ((line_len = getline (&line, &line_size, f)) != -1)
735 token = strtok_r (line, whitespace, &sp);
739 if (!strcmp (token, "sizes"))
742 font_msg (SW, _("Multiple `sizes' declarations."));
750 token = strtok_r (NULL, whitespace, &sp);
755 if ((line_len = getline (&line, &line_size, f)) != -1)
759 font_msg (SE, _("Unexpected end of file. "
760 "Missing 0 terminator to `sizes' command?"));
765 if (!strcmp (token, "0"))
769 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
771 font_msg (SE, _("Bad argument to `sizes'."));
776 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
778 font_msg (SE, _("Bad argument to `sizes'."));
783 font_msg (SE, _("Bad range in argument to `sizes'."));
791 font_msg (SE, _("Bad argument to `sizes'."));
795 if (dev->n_sizes + 2 >= m_sizes)
798 dev->sizes = xrealloc (dev->sizes,
799 m_sizes * sizeof *dev->sizes);
801 dev->sizes[dev->n_sizes++][0] = lower;
802 dev->sizes[dev->n_sizes][1] = upper;
807 else if (!strcmp (token, "family"))
809 token = strtok_r (NULL, whitespace, &sp);
812 font_msg (SE, _("Family name expected."));
817 font_msg (SE, _("This command already specified."));
820 dev->family = xstrdup (token);
822 else if (!strcmp (token, "charset"))
826 static const char *id[]
827 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
831 for (cp = id; *cp; cp++)
832 if (!strcmp (token, *cp))
835 continue; /* completely ignore unrecognized lines */
836 if (found & (1 << (cp - id)))
837 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
839 token = strtok_r (NULL, whitespace, &sp);
841 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
843 font_msg (SE, _("%s: Invalid numeric format."), *cp);
846 found |= (1 << (cp - id));
859 dev->size_scale = value;
862 dev->unit_width = value;
871 if ((found & 0x10011) != 0x10011)
873 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
877 /* Font name = family name + suffix. */
879 static const char *suffix[4] =
880 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
881 int len; /* length of family name */
885 dev->family = xstrdup ("");
886 len = strlen (dev->family);
887 for (i = 0; i < 4; i++)
890 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
891 cp = stpcpy (dev->font_name[i], dev->family);
892 strcpy (cp, suffix[i]);
896 dev->sizes[dev->n_sizes][0] = 0;
897 dev->sizes[dev->n_sizes][1] = 0;
899 msg (VM (2), _("Description file read successfully."));
901 err_pop_file_locator (&where);
906 /* Come here on a file error. */
908 msg (ME, "%s: %s", filename, strerror (errno));
910 /* Come here on any error. */
920 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
922 for (i = 0; i < 4; i++)
924 free (dev->font_name[i]);
925 dev->font_name[i] = NULL;
929 err_pop_file_locator (&where);
931 msg (VM (1), _("Error reading description file."));
936 /* Finds character with index CH (as returned by name_to_index() or
937 number_to_index()) in font FONT and returns the associated metrics.
938 Nonexistent characters have width 0. */
939 struct char_metrics *
940 font_get_char_metrics (const struct font_desc *font, int ch)
944 if (ch < 0 || ch >= font->deref_size)
947 index = font->deref[ch];
951 return font->metric[index];
954 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
955 FONT and returns the associated kerning adjustment. */
957 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
963 for (i = hash_kern (ch1, ch2) % font->kern_size; font->kern[i].ch1 != -1;)
965 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
966 return font->kern[i].adjust;
968 i = font->kern_size - 1;
973 /* Returns a twelve-point fixed-pitch font that can be used as a
974 last-resort fallback. */
978 struct pool *font_pool;
979 static struct font_desc *font;
983 font_pool = pool_create ();
984 font = pool_alloc (font_pool, sizeof *font);
985 font->owner = font_pool;
987 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
988 font->encoding = pool_strdup (font_pool, "text.enc");
989 font->space_width = 12000;
994 font->descent = 4000;
996 font->deref_size = 0;
998 font->metric_size = 0;
999 font->metric_used = 0;
1001 font->kern_size = 8;
1002 font->kern_used = 0;
1003 font->kern_max_used = 0;