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;
604 for (i = 0; i < old_kern_size; i++)
606 if (old_kern[i].ch1 == -1)
609 j = hash_kern (old_kern[i].ch1, old_kern[i].ch2) % font->kern_size;
610 while (font->kern[j].ch1 != -1)
612 j = font->kern_size - 1;
613 font->kern[j] = old_kern[i];
615 pool_free (font->owner, old_kern);
619 for (i = hash_kern (ch1, ch2) % font->kern_size; font->kern[i].ch1 != -1;)
621 i = font->kern_size - 1;
622 font->kern[i].ch1 = ch1;
623 font->kern[i].ch2 = ch2;
624 font->kern[i].adjust = adjust;
628 /* Finds a font file corresponding to font NAME for device DEV. */
630 find_font_file (const char *dev, const char *name)
632 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
637 cp = stpcpy (basename, "dev");
638 cp = stpcpy (cp, dev);
639 *cp++ = DIR_SEPARATOR;
643 1. $STAT_GROFF_FONT_PATH
645 3. GROFF_FONT_PATH from pref.h
648 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
649 && (filename = fn_search_path (basename, path, NULL)) != NULL)
652 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
653 && (filename = fn_search_path (basename, path, NULL)) != NULL)
656 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
659 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
662 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
669 /* Finds a font for device DEV with name NAME, reads it with
670 groff_read_font(), and returns the resultant font. */
672 groff_find_font (const char *dev, const char *name)
674 char *filename = find_font_file (dev, name);
675 struct font_desc *fd;
679 fd = groff_read_font (filename);
684 /* Reads a DESC file for device DEV and sets the appropriate fields in
685 output driver *DRIVER, which must be previously allocated. Returns
686 nonzero on success. */
688 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
690 char *filename; /* Full name of DESC file. */
691 FILE *f; /* DESC file. */
693 char *line = NULL; /* Current line. */
694 int line_len; /* Number of chars in current line. */
695 size_t line_size = 0; /* Number of chars allocated for line. */
697 char *token; /* strtok()'d token inside line. */
699 unsigned found = 0; /* Bitmask showing what settings
700 have been encountered. */
702 int m_sizes = 0; /* Number of int[2] items that
703 can fit in driver->sizes. */
705 char *sp; /* Tokenization string pointer. */
706 struct file_locator where;
716 for (i = 0; i < 4; i++)
717 dev->font_name[i] = NULL;
719 filename = find_font_file (dev_name, "DESC");
723 where.filename = filename;
724 where.line_number = 0;
725 err_push_file_locator (&where);
727 msg (VM (1), _("%s: Opening Groff description file..."), filename);
728 f = fopen (filename, "r");
732 while ((line_len = getline (&line, &line_size, f)) != -1)
736 token = strtok_r (line, whitespace, &sp);
740 if (!strcmp (token, "sizes"))
743 font_msg (SW, _("Multiple `sizes' declarations."));
751 token = strtok_r (NULL, whitespace, &sp);
756 if ((line_len = getline (&line, &line_size, f)) != -1)
760 font_msg (SE, _("Unexpected end of file. "
761 "Missing 0 terminator to `sizes' command?"));
766 if (!strcmp (token, "0"))
770 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
772 font_msg (SE, _("Bad argument to `sizes'."));
777 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
779 font_msg (SE, _("Bad argument to `sizes'."));
784 font_msg (SE, _("Bad range in argument to `sizes'."));
792 font_msg (SE, _("Bad argument to `sizes'."));
796 if (dev->n_sizes + 2 >= m_sizes)
799 dev->sizes = xrealloc (dev->sizes,
800 m_sizes * sizeof *dev->sizes);
802 dev->sizes[dev->n_sizes++][0] = lower;
803 dev->sizes[dev->n_sizes][1] = upper;
808 else if (!strcmp (token, "family"))
810 token = strtok_r (NULL, whitespace, &sp);
813 font_msg (SE, _("Family name expected."));
818 font_msg (SE, _("This command already specified."));
821 dev->family = xstrdup (token);
823 else if (!strcmp (token, "charset"))
827 static const char *id[]
828 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
832 for (cp = id; *cp; cp++)
833 if (!strcmp (token, *cp))
836 continue; /* completely ignore unrecognized lines */
837 if (found & (1 << (cp - id)))
838 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
840 token = strtok_r (NULL, whitespace, &sp);
842 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
844 font_msg (SE, _("%s: Invalid numeric format."), *cp);
847 found |= (1 << (cp - id));
860 dev->size_scale = value;
863 dev->unit_width = value;
872 if ((found & 0x10011) != 0x10011)
874 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
878 /* Font name = family name + suffix. */
880 static const char *suffix[4] =
881 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
882 int len; /* length of family name */
886 dev->family = xstrdup ("");
887 len = strlen (dev->family);
888 for (i = 0; i < 4; i++)
891 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
892 cp = stpcpy (dev->font_name[i], dev->family);
893 strcpy (cp, suffix[i]);
897 dev->sizes[dev->n_sizes][0] = 0;
898 dev->sizes[dev->n_sizes][1] = 0;
900 msg (VM (2), _("Description file read successfully."));
902 err_pop_file_locator (&where);
907 /* Come here on a file error. */
909 msg (ME, "%s: %s", filename, strerror (errno));
911 /* Come here on any error. */
921 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
923 for (i = 0; i < 4; i++)
925 free (dev->font_name[i]);
926 dev->font_name[i] = NULL;
930 err_pop_file_locator (&where);
932 msg (VM (1), _("Error reading description file."));
937 /* Finds character with index CH (as returned by name_to_index() or
938 number_to_index()) in font FONT and returns the associated metrics.
939 Nonexistent characters have width 0. */
940 struct char_metrics *
941 font_get_char_metrics (const struct font_desc *font, int ch)
945 if (ch < 0 || ch >= font->deref_size)
948 index = font->deref[ch];
952 return font->metric[index];
955 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
956 FONT and returns the associated kerning adjustment. */
958 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
964 for (i = hash_kern (ch1, ch2) % font->kern_size; font->kern[i].ch1 != -1;)
966 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
967 return font->kern[i].adjust;
969 i = font->kern_size - 1;
974 /* Returns a twelve-point fixed-pitch font that can be used as a
975 last-resort fallback. */
979 struct pool *font_pool;
980 static struct font_desc *font;
984 font_pool = pool_create ();
985 font = pool_alloc (font_pool, sizeof *font);
986 font->owner = font_pool;
988 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
989 font->encoding = pool_strdup (font_pool, "text.enc");
990 font->space_width = 12000;
995 font->descent = 4000;
997 font->deref_size = 0;
999 font->metric_size = 0;
1000 font->metric_used = 0;
1002 font->kern_size = 8;
1003 font->kern_used = 0;
1004 font->kern_max_used = 0;