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,...)
397 va_start (args, format);
398 tmsg (class, format, args, _("installation error: Groff font error: "));
404 /* Scans string LINE of length LEN (not incl. null terminator) for bad
405 characters, converts to spaces; reports warnings on file FN. */
407 scan_badchars (char *line, int len)
409 unsigned char *cp = line;
411 /* Same bad characters as Groff. */
412 static unsigned char badchars[32] =
414 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 if (badchars[*cp >> 3] & (1 << (*cp & 7)))
423 font_msg (SE, _("Bad character \\%3o."), *cp);
428 /* Character name hashing. */
430 /* Associates a character index with a character name. */
437 /* Character index hash table. */
440 int size; /* Size of table (must be power of 2). */
441 int used; /* Number of full entries. */
442 int next_index; /* Next index to allocate. */
443 struct index_hash *tab; /* Hash table proper. */
444 struct pool *ar; /* Pool for names. */
451 space_index = font_char_name_to_index ("space");
458 pool_destroy(hash.ar);
462 /* Searches for NAME in the global character code table, returns the
463 index if found; otherwise inserts NAME and returns the new
466 font_char_name_to_index (const char *name)
472 if (name[0] == '\0' || name[1] == '\0')
474 if (0 == strncmp (name, "char", 4))
477 int x = strtol (name + 4, &tail, 10);
478 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
486 hash.next_index = 256;
487 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
488 hash.ar = pool_create ();
489 for (i = 0; i < hash.size; i++)
490 hash.tab[i].name = NULL;
493 for (i = hsh_hash_string (name) & (hash.size - 1); hash.tab[i].name; )
495 if (!strcmp (hash.tab[i].name, name))
496 return hash.tab[i].index;
497 if (++i >= hash.size)
502 if (hash.used >= hash.size / 2)
504 struct index_hash *old_tab = hash.tab;
505 int old_size = hash.size;
509 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
510 for (i = 0; i < hash.size; i++)
511 hash.tab[i].name = NULL;
512 for (i = 0; i < old_size; i++)
515 for (j = hsh_hash_string (old_tab[i].name) & (hash.size - 1);
517 if (++j >= hash.size)
519 hash.tab[j] = old_tab[i];
524 hash.tab[i].name = pool_strdup (hash.ar, name);
525 hash.tab[i].index = hash.next_index;
526 return hash.next_index++;
529 /* Returns an index for a character that has only a code, not a
532 font_number_to_index (int x)
534 char name[INT_DIGITS + 2];
536 /* Note that space is the only character that can't appear in a
537 character name. That makes it an excellent choice for a name
538 that won't conflict. */
539 sprintf (name, " %d", x);
540 return font_char_name_to_index (name);
543 /* Font character metric entries. */
545 /* Ensures room for at least MIN_SIZE metric indexes in deref of
548 check_deref_space (struct font_desc *font, int min_size)
550 if (min_size >= font->deref_size)
552 int i = font->deref_size;
554 font->deref_size = min_size + 16;
555 if (font->deref_size < 256)
556 font->deref_size = 256;
557 font->deref = pool_realloc (font->owner, font->deref,
558 sizeof *font->deref * font->deref_size);
559 for (; i < font->deref_size; i++)
564 /* Inserts METRICS for character with code CODE into FONT. */
566 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
568 check_deref_space (font, code);
569 if (font->metric_used >= font->metric_size)
571 font->metric_size += 64;
572 font->metric = pool_realloc (font->owner, font->metric,
573 sizeof *font->metric * font->metric_size);
575 font->metric[font->metric_used] = metrics;
576 font->deref[code] = font->metric_used++;
579 /* Copies metric in FONT from character with code SRC to character
582 dup_char_metric (struct font_desc *font, int dest, int src)
584 check_deref_space (font, dest);
585 assert (font->deref[src] != -1);
586 font->deref[dest] = font->deref[src];
591 /* Returns a hash value for characters with codes CH1 and CH2. */
592 #define hash_kern(CH1, CH2) \
593 ((unsigned) (((CH1) << 16) ^ (CH2)))
595 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
598 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
602 if (font->kern_used >= font->kern_max_used)
604 struct kern_pair *old_kern = font->kern;
605 int old_kern_size = font->kern_size;
608 font->kern_size *= 2;
609 font->kern_max_used = font->kern_size / 2;
610 font->kern = pool_malloc (font->owner,
611 sizeof *font->kern * font->kern_size);
612 for (i = 0; i < font->kern_size; i++)
613 font->kern[i].ch1 = -1;
617 for (i = 0; i < old_kern_size; i++)
619 if (old_kern[i].ch1 == -1)
622 j = (hash_kern (old_kern[i].ch1, old_kern[i].ch2)
623 & (font->kern_size - 1));
624 while (font->kern[j].ch1 != -1)
626 j = font->kern_size - 1;
627 font->kern[j] = old_kern[i];
629 pool_free (font->owner, old_kern);
633 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
634 font->kern[i].ch1 != -1; )
636 i = font->kern_size - 1;
637 font->kern[i].ch1 = ch1;
638 font->kern[i].ch2 = ch2;
639 font->kern[i].adjust = adjust;
643 /* Finds a font file corresponding to font NAME for device DEV. */
645 find_font_file (const char *dev, const char *name)
647 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
652 cp = stpcpy (basename, "dev");
653 cp = stpcpy (cp, dev);
654 *cp++ = DIR_SEPARATOR;
658 1. $STAT_GROFF_FONT_PATH
660 3. GROFF_FONT_PATH from pref.h
663 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
664 && (filename = fn_search_path (basename, path, NULL)) != NULL)
667 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
668 && (filename = fn_search_path (basename, path, NULL)) != NULL)
671 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
674 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
677 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
684 /* Finds a font for device DEV with name NAME, reads it with
685 groff_read_font(), and returns the resultant font. */
687 groff_find_font (const char *dev, const char *name)
689 char *filename = find_font_file (dev, name);
690 struct font_desc *fd;
694 fd = groff_read_font (filename);
699 /* Reads a DESC file for device DEV and sets the appropriate fields in
700 output driver *DRIVER, which must be previously allocated. Returns
701 nonzero on success. */
703 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
705 char *filename; /* Full name of DESC file. */
706 FILE *f; /* DESC file. */
708 char *line = NULL; /* Current line. */
709 int line_len; /* Number of chars in current line. */
710 size_t line_size = 0; /* Number of chars allocated for line. */
712 char *token; /* strtok()'d token inside line. */
714 unsigned found = 0; /* Bitmask showing what settings
715 have been encountered. */
717 int m_sizes = 0; /* Number of int[2] items that
718 can fit in driver->sizes. */
720 char *sp; /* Tokenization string pointer. */
721 struct file_locator where;
731 for (i = 0; i < 4; i++)
732 dev->font_name[i] = NULL;
734 filename = find_font_file (dev_name, "DESC");
738 where.filename = filename;
739 where.line_number = 0;
740 err_push_file_locator (&where);
742 msg (VM (1), _("%s: Opening Groff description file..."), filename);
743 f = fopen (filename, "r");
747 while ((line_len = getline (&line, &line_size, f)) != -1)
751 token = strtok_r (line, whitespace, &sp);
755 if (!strcmp (token, "sizes"))
758 font_msg (SW, _("Multiple `sizes' declarations."));
766 token = strtok_r (NULL, whitespace, &sp);
771 if ((line_len = getline (&line, &line_size, f)) != -1)
775 font_msg (SE, _("Unexpected end of file. "
776 "Missing 0 terminator to `sizes' command?"));
781 if (!strcmp (token, "0"))
785 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
787 font_msg (SE, _("Bad argument to `sizes'."));
792 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
794 font_msg (SE, _("Bad argument to `sizes'."));
799 font_msg (SE, _("Bad range in argument to `sizes'."));
807 font_msg (SE, _("Bad argument to `sizes'."));
811 if (dev->n_sizes + 2 >= m_sizes)
814 dev->sizes = xrealloc (dev->sizes,
815 m_sizes * sizeof *dev->sizes);
817 dev->sizes[dev->n_sizes++][0] = lower;
818 dev->sizes[dev->n_sizes][1] = upper;
823 else if (!strcmp (token, "family"))
825 token = strtok_r (NULL, whitespace, &sp);
828 font_msg (SE, _("Family name expected."));
833 font_msg (SE, _("This command already specified."));
836 dev->family = xstrdup (token);
838 else if (!strcmp (token, "charset"))
842 static const char *id[]
843 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
847 for (cp = id; *cp; cp++)
848 if (!strcmp (token, *cp))
851 continue; /* completely ignore unrecognized lines */
852 if (found & (1 << (cp - id)))
853 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
855 token = strtok_r (NULL, whitespace, &sp);
857 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
859 font_msg (SE, _("%s: Invalid numeric format."), *cp);
862 found |= (1 << (cp - id));
875 dev->size_scale = value;
878 dev->unit_width = value;
887 if ((found & 0x10011) != 0x10011)
889 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
893 /* Font name = family name + suffix. */
895 static const char *suffix[4] =
896 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
897 int len; /* length of family name */
901 dev->family = xstrdup ("");
902 len = strlen (dev->family);
903 for (i = 0; i < 4; i++)
906 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
907 cp = stpcpy (dev->font_name[i], dev->family);
908 strcpy (cp, suffix[i]);
912 dev->sizes[dev->n_sizes][0] = 0;
913 dev->sizes[dev->n_sizes][1] = 0;
915 msg (VM (2), _("Description file read successfully."));
917 err_pop_file_locator (&where);
922 /* Come here on a file error. */
924 msg (ME, "%s: %s", filename, strerror (errno));
926 /* Come here on any error. */
936 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
938 for (i = 0; i < 4; i++)
940 free (dev->font_name[i]);
941 dev->font_name[i] = NULL;
945 err_pop_file_locator (&where);
947 msg (VM (1), _("Error reading description file."));
952 /* Finds character with index CH (as returned by name_to_index() or
953 number_to_index()) in font FONT and returns the associated metrics.
954 Nonexistent characters have width 0. */
955 struct char_metrics *
956 font_get_char_metrics (const struct font_desc *font, int ch)
960 if (ch < 0 || ch >= font->deref_size)
963 index = font->deref[ch];
967 return font->metric[index];
970 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
971 FONT and returns the associated kerning adjustment. */
973 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
979 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
980 font->kern[i].ch1 != -1;)
982 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
983 return font->kern[i].adjust;
985 i = font->kern_size - 1;
990 /* Returns a twelve-point fixed-pitch font that can be used as a
991 last-resort fallback. */
995 struct pool *font_pool;
996 static struct font_desc *font;
1000 font_pool = pool_create ();
1001 font = pool_alloc (font_pool, sizeof *font);
1002 font->owner = font_pool;
1004 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
1005 font->encoding = pool_strdup (font_pool, "text.enc");
1006 font->space_width = 12000;
1008 font->ligatures = 0;
1010 font->ascent = 8000;
1011 font->descent = 4000;
1013 font->deref_size = 0;
1014 font->metric = NULL;
1015 font->metric_size = 0;
1016 font->metric_used = 0;
1018 font->kern_size = 8;
1019 font->kern_used = 0;
1020 font->kern_max_used = 0;