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;
134 font->kern_size_p = hsh_next_prime (64);
136 font->kern_max_used = 0;
138 /* Parses first section of font file. */
141 /* Location of '#' in line. */
144 len = getline (&line, &size, f);
148 scan_badchars (line, len);
149 p = strchr (line, '#');
151 *p = '\0'; /* Reject comments. */
153 key = strtok_r (line, whitespace, &sp);
157 if (!strcmp (key, "internalname"))
159 font->internal_name = strtok_r (NULL, whitespace, &sp);
160 if (font->internal_name == NULL)
162 font_msg (SE, _("Missing font name."));
165 font->internal_name = pool_strdup (font_pool, font->internal_name);
167 else if (!strcmp (key, "encoding"))
169 font->encoding = strtok_r (NULL, whitespace, &sp);
170 if (font->encoding == NULL)
172 font_msg (SE, _("Missing encoding filename."));
175 font->encoding = pool_strdup (font_pool, font->encoding);
177 else if (!strcmp (key, "spacewidth"))
179 char *n = strtok_r (NULL, whitespace, &sp);
182 font->space_width = strtol (n, &tail, 10);
183 if (n == NULL || tail == n)
185 font_msg (SE, _("Bad spacewidth value."));
189 else if (!strcmp (key, "slant"))
191 char *n = strtok_r (NULL, whitespace, &sp);
194 font->slant = strtod (n, &tail);
195 if (n == NULL || tail == n)
197 font_msg (SE, _("Bad slant value."));
201 else if (!strcmp (key, "ligatures"))
207 lig = strtok_r (NULL, whitespace, &sp);
208 if (!lig || !strcmp (lig, "0"))
210 else if (!strcmp (lig, "ff"))
211 font->ligatures |= LIG_ff;
212 else if (!strcmp (lig, "ffi"))
213 font->ligatures |= LIG_ffi;
214 else if (!strcmp (lig, "ffl"))
215 font->ligatures |= LIG_ffl;
216 else if (!strcmp (lig, "fi"))
217 font->ligatures |= LIG_fi;
218 else if (!strcmp (lig, "fl"))
219 font->ligatures |= LIG_fl;
222 font_msg (SE, _("Unknown ligature `%s'."), lig);
227 else if (!strcmp (key, "special"))
229 else if (!strcmp (key, "charset") || !strcmp (key, "kernpairs"))
237 /* Parses second section of font file (metrics & kerning data). */
240 key = strtok_r (line, whitespace, &sp);
244 if (!strcmp (key, "charset"))
246 else if (!strcmp (key, "kernpairs"))
250 struct char_metrics *metrics = pool_alloc (font_pool,
252 char *m, *type, *code, *tail;
254 m = strtok_r (NULL, whitespace, &sp);
257 font_msg (SE, _("Unexpected end of line reading character "
261 if (!strcmp (m, "\""))
265 font_msg (SE, _("Can't use ditto mark for first character."));
268 if (!strcmp (key, "---"))
270 font_msg (SE, _("Can't ditto into an unnamed character."));
273 dup_char_metric (font, font_char_name_to_index (key), prev_index);
280 metrics->code = metrics->width
281 = metrics->height = metrics->depth = 0;
284 if (m == NULL || 1 > sscanf (m, "%d,%d,%d", &metrics->width,
285 &metrics->height, &metrics->depth))
287 font_msg (SE, _("Missing metrics for character `%s'."), key);
291 type = strtok_r (NULL, whitespace, &sp);
293 metrics->type = strtol (type, &tail, 10);
294 if (!type || tail == type)
296 font_msg (SE, _("Missing type for character `%s'."), key);
300 code = strtok_r (NULL, whitespace, &sp);
302 metrics->code = strtol (code, &tail, 0);
305 font_msg (SE, _("Missing code for character `%s'."), key);
309 if (strcmp (key, "---"))
310 prev_index = font_char_name_to_index (key);
312 prev_index = font_number_to_index (metrics->code);
313 add_char_metric (font, metrics, prev_index);
318 char *c2 = strtok_r (NULL, whitespace, &sp);
324 font_msg (SE, _("Malformed kernpair."));
328 n = strtok_r (NULL, whitespace, &sp);
331 font_msg (SE, _("Unexpected end of line reading kernpairs."));
334 adjust = strtol (n, &tail, 10);
335 if (tail == n || *tail)
337 font_msg (SE, _("Bad kern value."));
340 add_kern (font, font_char_name_to_index (c1),
341 font_char_name_to_index (c2), adjust);
347 len = getline (&line, &size, f);
353 if (fclose (f) == EOF)
363 /* Get font ascent and descent. */
364 metrics = font_get_char_metrics (font, font_char_name_to_index ("d"));
365 font->ascent = metrics ? metrics->height : 0;
366 metrics = font_get_char_metrics (font, font_char_name_to_index ("p"));
367 font->descent = metrics ? metrics->depth : 0;
369 msg (VM (2), _("Font read successfully with internal name %s."),
370 font->internal_name == NULL ? "<none>" : font->internal_name);
372 err_pop_file_locator (&where);
376 /* Come here on a file error. */
378 msg (ME, "%s: %s", fn, strerror (errno));
380 /* 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. */
443 int *size_p; /* Next larger table size. */
444 int used; /* Number of full entries. */
445 int max_used; /* # used entries where we enlarge & rehash. */
446 int next_index; /* Next index to allocate. */
447 struct index_hash *tab; /* Hash table proper. */
448 struct pool *ar; /* Pool for names. */
452 /* Searches for NAME in the global character code table, returns the
453 index if found; otherwise inserts NAME and returns the new
456 font_char_name_to_index (const char *name)
462 if (name[0] == '\0' || name[1] == '\0')
464 if (0 == strncmp (name, "char", 4))
467 int x = strtol (name + 4, &tail, 10);
468 if (tail != name + 4 && *tail == 0 && x >= 0 && x <= 255)
474 hash.size_p = hsh_next_prime (128);
475 hash.size = *hash.size_p++;
477 hash.max_used = hash.size / 2;
478 hash.next_index = 256;
479 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
480 hash.ar = pool_create ();
481 for (i = 0; i < hash.size; i++)
482 hash.tab[i].name = NULL;
485 for (i = hashpjw (name) % hash.size; hash.tab[i].name;)
487 if (!strcmp (hash.tab[i].name, name))
488 return hash.tab[i].index;
489 if (++i >= hash.size)
494 if (hash.used >= hash.max_used)
496 struct index_hash *old_tab = hash.tab;
497 int old_size = hash.size;
500 hash.size = *hash.size_p++;
501 hash.max_used = hash.size / 2;
502 hash.tab = xmalloc (sizeof *hash.tab * hash.size);
503 for (i = 0; i < hash.size; i++)
504 hash.tab[i].name = NULL;
505 for (i = 0; i < old_size; i++)
508 for (j = hashpjw (old_tab[i].name) % hash.size; hash.tab[j].name;)
509 if (++j >= hash.size)
511 hash.tab[j] = old_tab[i];
516 hash.tab[i].name = pool_strdup (hash.ar, name);
517 hash.tab[i].index = hash.next_index;
518 return hash.next_index++;
521 /* Returns an index for a character that has only a code, not a
524 font_number_to_index (int x)
526 char name[INT_DIGITS + 2];
528 /* Note that space is the only character that can't appear in a
529 character name. That makes it an excellent choice for a name
530 that won't conflict. */
531 sprintf (name, " %d", x);
532 return font_char_name_to_index (name);
535 /* Font character metric entries. */
537 /* Ensures room for at least MIN_SIZE metric indexes in deref of
540 check_deref_space (struct font_desc *font, int min_size)
542 if (min_size >= font->deref_size)
544 int i = font->deref_size;
546 font->deref_size = min_size + 16;
547 if (font->deref_size < 256)
548 font->deref_size = 256;
549 font->deref = pool_realloc (font->owner, font->deref,
550 sizeof *font->deref * font->deref_size);
551 for (; i < font->deref_size; i++)
556 /* Inserts METRICS for character with code CODE into FONT. */
558 add_char_metric (struct font_desc *font, struct char_metrics *metrics, int code)
560 check_deref_space (font, code);
561 if (font->metric_used >= font->metric_size)
563 font->metric_size += 64;
564 font->metric = pool_realloc (font->owner, font->metric,
565 sizeof *font->metric * font->metric_size);
567 font->metric[font->metric_used] = metrics;
568 font->deref[code] = font->metric_used++;
571 /* Copies metric in FONT from character with code SRC to character
574 dup_char_metric (struct font_desc *font, int dest, int src)
576 check_deref_space (font, dest);
577 assert (font->deref[src] != -1);
578 font->deref[dest] = font->deref[src];
583 /* Returns a hash value for characters with codes CH1 and CH2. */
584 #define hash_kern(CH1, CH2) \
585 ((unsigned) (((CH1) << 16) ^ (CH2)))
587 /* Adds an ADJUST-size kern to FONT between characters with codes CH1
590 add_kern (struct font_desc *font, int ch1, int ch2, int adjust)
594 if (font->kern_used >= font->kern_max_used)
596 struct kern_pair *old_kern = font->kern;
597 int old_kern_size = font->kern_size;
600 font->kern_size = *font->kern_size_p++;
601 font->kern_max_used = font->kern_size / 2;
602 font->kern = pool_malloc (font->owner,
603 sizeof *font->kern * font->kern_size);
604 for (i = 0; i < font->kern_size; i++)
605 font->kern[i].ch1 = -1;
607 for (i = 0; i < old_kern_size; i++)
609 if (old_kern[i].ch1 == -1)
612 j = hash_kern (old_kern[i].ch1, old_kern[i].ch2) % font->kern_size;
613 while (font->kern[j].ch1 != -1)
615 j = font->kern_size - 1;
616 font->kern[j] = old_kern[i];
619 pool_free (font->owner, old_kern);
622 for (i = hash_kern (ch1, ch2) % font->kern_size; font->kern[i].ch1 != -1;)
624 i = font->kern_size - 1;
625 font->kern[i].ch1 = ch1;
626 font->kern[i].ch2 = ch2;
627 font->kern[i].adjust = adjust;
631 /* Finds a font file corresponding to font NAME for device DEV. */
633 find_font_file (const char *dev, const char *name)
635 char *basename = xmalloc (3 + strlen (dev) + 1 + strlen (name) + 1);
640 cp = stpcpy (basename, "dev");
641 cp = stpcpy (cp, dev);
642 *cp++ = DIR_SEPARATOR;
646 1. $STAT_GROFF_FONT_PATH
648 3. GROFF_FONT_PATH from pref.h
651 if ((path = getenv ("STAT_GROFF_FONT_PATH")) != NULL
652 && (filename = fn_search_path (basename, path, NULL)) != NULL)
655 if ((path = getenv ("GROFF_FONT_PATH")) != NULL
656 && (filename = fn_search_path (basename, path, NULL)) != NULL)
659 if ((filename = fn_search_path (basename, groff_font_path, NULL)) != NULL)
662 if ((filename = fn_search_path (basename, config_path, NULL)) != NULL)
665 msg (IE, _("Groff font error: Cannot find \"%s\"."), basename);
672 /* Finds a font for device DEV with name NAME, reads it with
673 groff_read_font(), and returns the resultant font. */
675 groff_find_font (const char *dev, const char *name)
677 char *filename = find_font_file (dev, name);
678 struct font_desc *fd;
682 fd = groff_read_font (filename);
687 /* Reads a DESC file for device DEV and sets the appropriate fields in
688 output driver *DRIVER, which must be previously allocated. Returns
689 nonzero on success. */
691 groff_read_DESC (const char *dev_name, struct groff_device_info * dev)
693 char *filename; /* Full name of DESC file. */
694 FILE *f; /* DESC file. */
696 char *line = NULL; /* Current line. */
697 int line_len; /* Number of chars in current line. */
698 size_t line_size = 0; /* Number of chars allocated for line. */
700 char *token; /* strtok()'d token inside line. */
702 unsigned found = 0; /* Bitmask showing what settings
703 have been encountered. */
705 int m_sizes = 0; /* Number of int[2] items that
706 can fit in driver->sizes. */
708 char *sp; /* Tokenization string pointer. */
709 struct file_locator where;
719 for (i = 0; i < 4; i++)
720 dev->font_name[i] = NULL;
722 filename = find_font_file (dev_name, "DESC");
726 where.filename = filename;
727 where.line_number = 0;
728 err_push_file_locator (&where);
730 msg (VM (1), _("%s: Opening Groff description file..."), filename);
731 f = fopen (filename, "r");
735 while ((line_len = getline (&line, &line_size, f)) != -1)
739 token = strtok_r (line, whitespace, &sp);
743 if (!strcmp (token, "sizes"))
746 font_msg (SW, _("Multiple `sizes' declarations."));
754 token = strtok_r (NULL, whitespace, &sp);
759 if ((line_len = getline (&line, &line_size, f)) != -1)
763 font_msg (SE, _("Unexpected end of file. "
764 "Missing 0 terminator to `sizes' command?"));
769 if (!strcmp (token, "0"))
773 if (0 == (lower = strtol (token, &tail, 0)) || errno == ERANGE)
775 font_msg (SE, _("Bad argument to `sizes'."));
780 if (0 == (upper = strtol (&tail[1], &tail, 0)) || errno == ERANGE)
782 font_msg (SE, _("Bad argument to `sizes'."));
787 font_msg (SE, _("Bad range in argument to `sizes'."));
795 font_msg (SE, _("Bad argument to `sizes'."));
799 if (dev->n_sizes + 2 >= m_sizes)
802 dev->sizes = xrealloc (dev->sizes,
803 m_sizes * sizeof *dev->sizes);
805 dev->sizes[dev->n_sizes++][0] = lower;
806 dev->sizes[dev->n_sizes][1] = upper;
811 else if (!strcmp (token, "family"))
813 token = strtok_r (NULL, whitespace, &sp);
816 font_msg (SE, _("Family name expected."));
821 font_msg (SE, _("This command already specified."));
824 dev->family = xstrdup (token);
826 else if (!strcmp (token, "charset"))
830 static const char *id[]
831 = {"res", "hor", "vert", "sizescale", "unitwidth", NULL};
835 for (cp = id; *cp; cp++)
836 if (!strcmp (token, *cp))
839 continue; /* completely ignore unrecognized lines */
840 if (found & (1 << (cp - id)))
841 font_msg (SW, _("%s: Device characteristic already defined."), *cp);
843 token = strtok_r (NULL, whitespace, &sp);
845 if (!token || (value = strtol (token, NULL, 0)) <= 0 || errno == ERANGE)
847 font_msg (SE, _("%s: Invalid numeric format."), *cp);
850 found |= (1 << (cp - id));
863 dev->size_scale = value;
866 dev->unit_width = value;
875 if ((found & 0x10011) != 0x10011)
877 font_msg (SE, _("Missing `res', `unitwidth', and/or `sizes' line(s)."));
881 /* Font name = family name + suffix. */
883 static const char *suffix[4] =
884 {"R", "I", "B", "BI"}; /* match OUTP_F_* */
885 int len; /* length of family name */
889 dev->family = xstrdup ("");
890 len = strlen (dev->family);
891 for (i = 0; i < 4; i++)
894 dev->font_name[i] = xmalloc (len + strlen (suffix[i]) + 1);
895 cp = stpcpy (dev->font_name[i], dev->family);
896 strcpy (cp, suffix[i]);
900 dev->sizes[dev->n_sizes][0] = 0;
901 dev->sizes[dev->n_sizes][1] = 0;
903 msg (VM (2), _("Description file read successfully."));
905 err_pop_file_locator (&where);
910 /* Come here on a file error. */
912 msg (ME, "%s: %s", filename, strerror (errno));
914 /* Come here on any error. */
924 #if 0 /* at the moment, no errors can come here when dev->font_name[*] are
926 for (i = 0; i < 4; i++)
928 free (dev->font_name[i]);
929 dev->font_name[i] = NULL;
933 err_pop_file_locator (&where);
935 msg (VM (1), _("Error reading description file."));
940 /* Finds character with index CH (as returned by name_to_index() or
941 number_to_index()) in font FONT and returns the associated metrics.
942 Nonexistent characters have width 0. */
943 struct char_metrics *
944 font_get_char_metrics (const struct font_desc *font, int ch)
948 if (ch < 0 || ch >= font->deref_size)
951 index = font->deref[ch];
955 return font->metric[index];
958 /* Finds kernpair consisting of CH1 and CH2, in that order, in font
959 FONT and returns the associated kerning adjustment. */
961 font_get_kern_adjust (const struct font_desc *font, int ch1, int ch2)
967 for (i = hash_kern (ch1, ch2) % font->kern_size; font->kern[i].ch1 != -1;)
969 if (font->kern[i].ch1 == ch1 && font->kern[i].ch2 == ch2)
970 return font->kern[i].adjust;
972 i = font->kern_size - 1;
977 /* Returns a twelve-point fixed-pitch font that can be used as a
978 last-resort fallback. */
982 struct pool *font_pool;
983 static struct font_desc *font;
987 font_pool = pool_create ();
988 font = pool_alloc (font_pool, sizeof *font);
989 font->owner = font_pool;
991 font->internal_name = pool_strdup (font_pool, _("<<fallback>>"));
992 font->encoding = pool_strdup (font_pool, "text.enc");
993 font->space_width = 12000;
998 font->descent = 4000;
1000 font->deref_size = 0;
1001 font->metric = NULL;
1002 font->metric_size = 0;
1003 font->metric_used = 0;
1005 font->kern_size = 0;
1006 font->kern_size_p = hsh_next_prime (64);
1007 font->kern_used = 0;
1008 font->kern_max_used = 0;