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
39 #define _(msgid) gettext (msgid)
41 int font_number_to_index (int);
45 static int font_msg (int, const char *,...)
47 static void scan_badchars (char *, int);
48 static void dup_char_metric (struct font_desc * font, int dest, int src);
49 static void add_char_metric (struct font_desc * font, struct char_metrics *metrics,
51 static void add_kern (struct font_desc * font, int ch1, int ch2, int adjust);
53 /* Typical whitespace characters for tokenizing. */
54 static const char whitespace[] = " \t\n\r\v";
56 /* Some notes on the groff_font manpage:
58 DESC file format: A typical PostScript `res' would be 72000, with
59 `hor' and `vert' set to 1 to indicate that all those positions are
60 valid. `sizescale' of 1000 would indicate that a scaled point is
61 1/1000 of a point (which is 1/72000 of an inch, the same as the
62 number of machine units per inch indicated on `res'). `unitwidth'
63 of 1000 would indicate that font files are set up for fonts with
64 point size of 1000 scaled points, which would equal 1/72 inch or 1
65 point (this would tell Groff's postprocessor that it needs to scale
66 the font 12 times larger to get a 12-point font). */
68 /* Reads a Groff font description file and converts it to a usable
69 binary format in memory. Installs the binary format in the global
70 font table. See groff_font for a description of the font
71 description format supported. Returns nonzero on success. */
73 groff_read_font (const char *fn)
75 struct char_metrics *metrics;
77 /* Pool created for font, font being created, font file. */
78 struct pool *font_pool = NULL;
79 struct font_desc *font = NULL;
82 /* Current line, size of line buffer, length of line. */
87 /* Tokenization saved pointer. */
90 /* First token on line. */
93 /* 0=kernpairs section, 1=charset section. */
96 /* Index for previous line. */
99 /* Current location in file, used for error reporting. */
100 struct file_locator where;
103 fn = fn_tilde_expand (fn);
106 msg (VM (1), _("%s: Opening Groff font file..."), fn);
109 where.line_number = 1;
110 err_push_file_locator (&where);
116 font_pool = pool_create ();
117 font = pool_alloc (font_pool, sizeof *font);
118 font->owner = font_pool;
120 font->internal_name = NULL;
121 font->encoding = NULL;
122 font->space_width = 0;
127 font->deref_size = 0;
129 font->metric_size = 0;
130 font->metric_used = 0;
134 font->kern_max_used = 0;
136 /* Parses first section of font file. */
139 /* Location of '#' in line. */
142 len = getline (&line, &size, f);
146 scan_badchars (line, len);
147 p = strchr (line, '#');
149 *p = '\0'; /* Reject comments. */
151 key = strtok_r (line, whitespace, &sp);
155 if (!strcmp (key, "internalname"))
157 font->internal_name = strtok_r (NULL, whitespace, &sp);
158 if (font->internal_name == NULL)
160 font_msg (SE, _("Missing font name."));
163 font->internal_name = pool_strdup (font_pool, font->internal_name);
165 else if (!strcmp (key, "encoding"))
167 font->encoding = strtok_r (NULL, whitespace, &sp);
168 if (font->encoding == NULL)
170 font_msg (SE, _("Missing encoding filename."));
173 font->encoding = pool_strdup (font_pool, font->encoding);
175 else if (!strcmp (key, "spacewidth"))
177 char *n = strtok_r (NULL, whitespace, &sp);
180 font->space_width = strtol (n, &tail, 10);
181 if (n == NULL || tail == n)
183 font_msg (SE, _("Bad spacewidth value."));
187 else if (!strcmp (key, "slant"))
189 char *n = strtok_r (NULL, whitespace, &sp);
192 font->slant = strtod (n, &tail);
193 if (n == NULL || tail == n)
195 font_msg (SE, _("Bad slant value."));
199 else if (!strcmp (key, "ligatures"))
205 lig = strtok_r (NULL, whitespace, &sp);
206 if (!lig || !strcmp (lig, "0"))
208 else if (!strcmp (lig, "ff"))
209 font->ligatures |= LIG_ff;
210 else if (!strcmp (lig, "ffi"))
211 font->ligatures |= LIG_ffi;
212 else if (!strcmp (lig, "ffl"))
213 font->ligatures |= LIG_ffl;
214 else if (!strcmp (lig, "fi"))
215 font->ligatures |= LIG_fi;
216 else if (!strcmp (lig, "fl"))
217 font->ligatures |= LIG_fl;
220 font_msg (SE, _("Unknown ligature `%s'."), lig);
225 else if (!strcmp (key, "special"))
227 else if (!strcmp (key, "charset") || !strcmp (key, "kernpairs"))
235 /* Parses second section of font file (metrics & kerning data). */
238 key = strtok_r (line, whitespace, &sp);
242 if (!strcmp (key, "charset"))
244 else if (!strcmp (key, "kernpairs"))
248 struct char_metrics *metrics = pool_alloc (font_pool,
250 char *m, *type, *code, *tail;
252 m = strtok_r (NULL, whitespace, &sp);
255 font_msg (SE, _("Unexpected end of line reading character "
259 if (!strcmp (m, "\""))
263 font_msg (SE, _("Can't use ditto mark for first character."));
266 if (!strcmp (key, "---"))
268 font_msg (SE, _("Can't ditto into an unnamed character."));
271 dup_char_metric (font, font_char_name_to_index (key), prev_index);
278 metrics->code = metrics->width
279 = metrics->height = metrics->depth = 0;
282 if (m == NULL || 1 > sscanf (m, "%d,%d,%d", &metrics->width,
283 &metrics->height, &metrics->depth))
285 font_msg (SE, _("Missing metrics for character `%s'."), key);
289 type = strtok_r (NULL, whitespace, &sp);
291 metrics->type = strtol (type, &tail, 10);
292 if (!type || tail == type)
294 font_msg (SE, _("Missing type for character `%s'."), key);
298 code = strtok_r (NULL, whitespace, &sp);
300 metrics->code = strtol (code, &tail, 0);
303 font_msg (SE, _("Missing code for character `%s'."), key);
307 if (strcmp (key, "---"))
308 prev_index = font_char_name_to_index (key);
310 prev_index = font_number_to_index (metrics->code);
311 add_char_metric (font, metrics, prev_index);
316 char *c2 = strtok_r (NULL, whitespace, &sp);
322 font_msg (SE, _("Malformed kernpair."));
326 n = strtok_r (NULL, whitespace, &sp);
329 font_msg (SE, _("Unexpected end of line reading kernpairs."));
332 adjust = strtol (n, &tail, 10);
333 if (tail == n || *tail)
335 font_msg (SE, _("Bad kern value."));
338 add_kern (font, font_char_name_to_index (c1),
339 font_char_name_to_index (c2), adjust);
345 len = getline (&line, &size, f);
351 if (fclose (f) == EOF)
361 /* Get font ascent and descent. */
362 metrics = font_get_char_metrics (font, font_char_name_to_index ("d"));
363 font->ascent = metrics ? metrics->height : 0;
364 metrics = font_get_char_metrics (font, font_char_name_to_index ("p"));
365 font->descent = metrics ? metrics->depth : 0;
367 msg (VM (2), _("Font read successfully with internal name %s."),
368 font->internal_name == NULL ? "<none>" : font->internal_name);
370 err_pop_file_locator (&where);
374 /* Come here on a file error. */
376 msg (ME, "%s: %s", fn, strerror (errno));
378 /* Come here on any error. */
382 pool_destroy (font_pool);
386 err_pop_file_locator (&where);
388 msg (VM (1), _("Error reading font."));
392 /* Prints a font error on stderr. */
394 font_msg (int class, const char *format,...)
400 err_location (&error.where);
401 error.title = _("installation error: Groff font error: ");
403 va_start (args, format);
404 err_vmsg (&error, format, args);
410 /* Scans string LINE of length LEN (not incl. null terminator) for bad
411 characters, converts to spaces; reports warnings on file FN. */
413 scan_badchars (char *line, int len)
417 /* Same bad characters as Groff. */
418 static unsigned char badchars[32] =
420 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
422 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
428 int c = (unsigned char) *cp;
429 if (badchars[c >> 3] & (1 << (c & 7)))
431 font_msg (SE, _("Bad character \\%3o."), *cp);
437 /* Character name hashing. */
439 /* Associates a character index with a character name. */
446 /* Character index hash table. */
449 int size; /* Size of table (must be power of 2). */
450 int used; /* Number of full entries. */
451 int next_index; /* Next index to allocate. */
452 struct index_hash *tab; /* Hash table proper. */
453 struct pool *ar; /* Pool for names. */
460 space_index = font_char_name_to_index ("space");
467 pool_destroy(hash.ar);
471 /* Searches for NAME in the global character code table, returns the
472 index if found; otherwise inserts NAME and returns the new
475 font_char_name_to_index (const char *name)
481 if (name[0] == '\0' || name[1] == '\0')
483 if (0 == strncmp (name, "char", 4))
486 int x = strtol (name + 4, &tail, 10);
487 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
495 hash.next_index = 256;
496 hash.tab = xnmalloc (hash.size, sizeof *hash.tab);
497 hash.ar = pool_create ();
498 for (i = 0; i < hash.size; i++)
499 hash.tab[i].name = NULL;
502 for (i = hsh_hash_string (name) & (hash.size - 1); hash.tab[i].name; )
504 if (!strcmp (hash.tab[i].name, name))
505 return hash.tab[i].index;
506 if (++i >= hash.size)
511 if (hash.used >= hash.size / 2)
513 struct index_hash *old_tab = hash.tab;
514 int old_size = hash.size;
518 hash.tab = xnmalloc (hash.size, sizeof *hash.tab);
519 for (i = 0; i < hash.size; i++)
520 hash.tab[i].name = NULL;
521 for (i = 0; i < old_size; i++)
524 for (j = hsh_hash_string (old_tab[i].name) & (hash.size - 1);
526 if (++j >= hash.size)
528 hash.tab[j] = old_tab[i];
533 hash.tab[i].name = pool_strdup (hash.ar, name);
534 hash.tab[i].index = hash.next_index;
535 return hash.next_index++;
538 /* Returns an index for a character that has only a code, not a
541 font_number_to_index (int x)
543 char name[INT_STRLEN_BOUND (x) + 2];
545 /* Note that space is the only character that can't appear in a
546 character name. That makes it an excellent choice for a name
547 that won't conflict. */
548 sprintf (name, " %d", x);
549 return font_char_name_to_index (name);
552 /* Font character metric entries. */
554 /* Ensures room for at least MIN_SIZE metric indexes in deref of
557 check_deref_space (struct font_desc *font, int min_size)
559 if (min_size >= font->deref_size)
561 int i = font->deref_size;
563 font->deref_size = min_size + 16;
564 if (font->deref_size < 256)
565 font->deref_size = 256;
566 font->deref = pool_nrealloc (font->owner, font->deref,
567 font->deref_size, sizeof *font->deref);
568 for (; i < font->deref_size; i++)
573 /* Inserts METRICS for character with code CODE into FONT. */
575 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
577 check_deref_space (font, code);
578 if (font->metric_used >= font->metric_size)
580 font->metric_size += 64;
581 font->metric = pool_nrealloc (font->owner, font->metric,
582 font->metric_size, sizeof *font->metric);
584 font->metric[font->metric_used] = metrics;
585 font->deref[code] = font->metric_used++;
588 /* Copies metric in FONT from character with code SRC to character
591 dup_char_metric (struct font_desc *font, int dest, int src)
593 check_deref_space (font, dest);
594 assert (font->deref[src] != -1);
595 font->deref[dest] = font->deref[src];
600 /* Returns a hash value for characters with codes CH1 and CH2. */
601 #define hash_kern(CH1, CH2) \
602 ((unsigned) (((CH1) << 16) ^ (CH2)))
604 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
607 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
611 if (font->kern_used >= font->kern_max_used)
613 struct kern_pair *old_kern = font->kern;
614 int old_kern_size = font->kern_size;
617 font->kern_size *= 2;
618 font->kern_max_used = font->kern_size / 2;
619 font->kern = pool_nmalloc (font->owner,
620 font->kern_size, sizeof *font->kern);
621 for (i = 0; i < font->kern_size; i++)
622 font->kern[i].ch1 = -1;
626 for (i = 0; i < old_kern_size; i++)
628 if (old_kern[i].ch1 == -1)
631 j = (hash_kern (old_kern[i].ch1, old_kern[i].ch2)
632 & (font->kern_size - 1));
633 while (font->kern[j].ch1 != -1)
635 j = font->kern_size - 1;
636 font->kern[j] = old_kern[i];
638 pool_free (font->owner, old_kern);
642 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
643 font->kern[i].ch1 != -1; )
645 i = font->kern_size - 1;
646 font->kern[i].ch1 = ch1;
647 font->kern[i].ch2 = ch2;
648 font->kern[i].adjust = adjust;
652 /* Finds a font file corresponding to font NAME for device DEV. */
654 find_font_file (const char *dev, const char *name)
656 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
661 cp = stpcpy (basename, "dev");
662 cp = stpcpy (cp, dev);
663 *cp++ = DIR_SEPARATOR;
667 1. $STAT_GROFF_FONT_PATH
669 3. GROFF_FONT_PATH from pref.h
672 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
673 && (filename = fn_search_path (basename, path, NULL)) != NULL)
676 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
677 && (filename = fn_search_path (basename, path, NULL)) != NULL)
680 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
683 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
686 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
693 /* Finds a font for device DEV with name NAME, reads it with
694 groff_read_font(), and returns the resultant font. */
696 groff_find_font (const char *dev, const char *name)
698 char *filename = find_font_file (dev, name);
699 struct font_desc *fd;
703 fd = groff_read_font (filename);
708 /* Reads a DESC file for device DEV and sets the appropriate fields in
709 output driver *DRIVER, which must be previously allocated. Returns
710 nonzero on success. */
712 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
714 char *filename; /* Full name of DESC file. */
715 FILE *f; /* DESC file. */
717 char *line = NULL; /* Current line. */
718 int line_len; /* Number of chars in current line. */
719 size_t line_size = 0; /* Number of chars allocated for line. */
721 char *token; /* strtok()'d token inside line. */
723 unsigned found = 0; /* Bitmask showing what settings
724 have been encountered. */
726 int m_sizes = 0; /* Number of int[2] items that
727 can fit in driver->sizes. */
729 char *sp; /* Tokenization string pointer. */
730 struct file_locator where;
740 for (i = 0; i < 4; i++)
741 dev->font_name[i] = NULL;
743 filename = find_font_file (dev_name, "DESC");
747 where.filename = filename;
748 where.line_number = 0;
749 err_push_file_locator (&where);
751 msg (VM (1), _("%s: Opening Groff description file..."), filename);
752 f = fopen (filename, "r");
756 while ((line_len = getline (&line, &line_size, f)) != -1)
760 token = strtok_r (line, whitespace, &sp);
764 if (!strcmp (token, "sizes"))
767 font_msg (SW, _("Multiple `sizes' declarations."));
775 token = strtok_r (NULL, whitespace, &sp);
780 if ((line_len = getline (&line, &line_size, f)) != -1)
784 font_msg (SE, _("Unexpected end of file. "
785 "Missing 0 terminator to `sizes' command?"));
790 if (!strcmp (token, "0"))
794 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
796 font_msg (SE, _("Bad argument to `sizes'."));
801 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
803 font_msg (SE, _("Bad argument to `sizes'."));
808 font_msg (SE, _("Bad range in argument to `sizes'."));
816 font_msg (SE, _("Bad argument to `sizes'."));
820 if (dev->n_sizes + 2 >= m_sizes)
823 dev->sizes = xnrealloc (dev->sizes,
824 m_sizes, sizeof *dev->sizes);
826 dev->sizes[dev->n_sizes++][0] = lower;
827 dev->sizes[dev->n_sizes][1] = upper;
832 else if (!strcmp (token, "family"))
834 token = strtok_r (NULL, whitespace, &sp);
837 font_msg (SE, _("Family name expected."));
842 font_msg (SE, _("This command already specified."));
845 dev->family = xstrdup (token);
847 else if (!strcmp (token, "charset"))
851 static const char *id[]
852 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
856 for (cp = id; *cp; cp++)
857 if (!strcmp (token, *cp))
860 continue; /* completely ignore unrecognized lines */
861 if (found & (1 << (cp - id)))
862 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
864 token = strtok_r (NULL, whitespace, &sp);
866 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
868 font_msg (SE, _("%s: Invalid numeric format."), *cp);
871 found |= (1 << (cp - id));
884 dev->size_scale = value;
887 dev->unit_width = value;
896 if ((found & 0x10011) != 0x10011)
898 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
902 /* Font name = family name + suffix. */
904 static const char *suffix[4] =
905 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
906 int len; /* length of family name */
910 dev->family = xstrdup ("");
911 len = strlen (dev->family);
912 for (i = 0; i < 4; i++)
915 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
916 cp = stpcpy (dev->font_name[i], dev->family);
917 strcpy (cp, suffix[i]);
921 dev->sizes[dev->n_sizes][0] = 0;
922 dev->sizes[dev->n_sizes][1] = 0;
924 msg (VM (2), _("Description file read successfully."));
926 err_pop_file_locator (&where);
931 /* Come here on a file error. */
933 msg (ME, "%s: %s", filename, strerror (errno));
935 /* Come here on any error. */
945 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
947 for (i = 0; i < 4; i++)
949 free (dev->font_name[i]);
950 dev->font_name[i] = NULL;
954 err_pop_file_locator (&where);
956 msg (VM (1), _("Error reading description file."));
961 /* Finds character with index CH (as returned by name_to_index() or
962 number_to_index()) in font FONT and returns the associated metrics.
963 Nonexistent characters have width 0. */
964 struct char_metrics *
965 font_get_char_metrics (const struct font_desc *font, int ch)
969 if (ch < 0 || ch >= font->deref_size)
972 index = font->deref[ch];
976 return font->metric[index];
979 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
980 FONT and returns the associated kerning adjustment. */
982 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
988 for (i = hash_kern (ch1, ch2) & (font->kern_size - 1);
989 font->kern[i].ch1 != -1;)
991 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
992 return font->kern[i].adjust;
994 i = font->kern_size - 1;
999 /* Returns a twelve-point fixed-pitch font that can be used as a
1000 last-resort fallback. */
1004 struct pool *font_pool;
1005 static struct font_desc *font;
1009 font_pool = pool_create ();
1010 font = pool_alloc (font_pool, sizeof *font);
1011 font->owner = font_pool;
1013 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
1014 font->encoding = pool_strdup (font_pool, "text.enc");
1015 font->space_width = 12000;
1017 font->ligatures = 0;
1019 font->ascent = 8000;
1020 font->descent = 4000;
1022 font->deref_size = 0;
1023 font->metric = NULL;
1024 font->metric_size = 0;
1025 font->metric_used = 0;
1027 font->kern_size = 8;
1028 font->kern_used = 0;
1029 font->kern_max_used = 0;