summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ChangeLog1414
-rw-r--r--lib/GNUmakefile38
-rw-r--r--lib/README73
-rw-r--r--lib/atou.obin0 -> 4976 bytes
-rw-r--r--lib/basename.obin0 -> 4956 bytes
-rw-r--r--lib/bb-list.c76
-rw-r--r--lib/bb-outline.c114
-rw-r--r--lib/bitmap.c258
-rw-r--r--lib/bounding-box.c78
-rw-r--r--lib/charcode.c85
-rw-r--r--lib/charspec.c63
-rw-r--r--lib/cmdline.c63
-rw-r--r--lib/concat.c41
-rw-r--r--lib/concat3.c40
-rw-r--r--lib/concat4.c43
-rw-r--r--lib/concat5.c45
-rw-r--r--lib/dlsym.c28
-rw-r--r--lib/edge.c265
-rw-r--r--lib/encoding.c191
-rw-r--r--lib/file-input.c158
-rw-r--r--lib/file-output.c73
-rw-r--r--lib/filename.c99
-rw-r--r--lib/fix-num.c43
-rw-r--r--lib/float-ok.c60
-rw-r--r--lib/fmod.c145
-rw-r--r--lib/font.c466
-rw-r--r--lib/fontmap.c210
-rw-r--r--lib/gmalloc.c1172
-rw-r--r--lib/hexify.c46
-rw-r--r--lib/identity.c38
-rw-r--r--lib/integer-ok.c44
-rw-r--r--lib/libfile.c130
-rw-r--r--lib/line.c63
-rw-r--r--lib/list.c64
-rw-r--r--lib/logreport.c36
-rw-r--r--lib/make-prefix.c41
-rw-r--r--lib/math.c173
-rw-r--r--lib/now.c38
-rw-r--r--lib/numtoa.c50
-rw-r--r--lib/pathsrch.c509
-rw-r--r--lib/rand.c70
-rw-r--r--lib/report.c27
-rw-r--r--lib/safe-free.c37
-rw-r--r--lib/scaled-num.c75
-rw-r--r--lib/spline.c216
-rw-r--r--lib/statistics.c79
-rw-r--r--lib/str-lcase.c49
-rw-r--r--lib/str-to-bit.c111
-rw-r--r--lib/strstr.obin0 -> 5172 bytes
-rw-r--r--lib/substring.c50
-rw-r--r--lib/varstring.c97
-rw-r--r--lib/vector.c272
-rw-r--r--lib/xchdir.c29
-rw-r--r--lib/xfseek.obin0 -> 3592 bytes
-rw-r--r--lib/xftell.obin0 -> 3648 bytes
-rw-r--r--lib/xgetcwd.c104
-rw-r--r--lib/xmessage.c101
-rw-r--r--lib/xopendir.c47
-rw-r--r--lib/xrename.c44
-rw-r--r--lib/xstrdup.c29
60 files changed, 8010 insertions, 0 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog
new file mode 100644
index 0000000..0f3ff5d
--- /dev/null
+++ b/lib/ChangeLog
@@ -0,0 +1,1414 @@
+Tue Dec 26 10:16:08 1995 Kathy Hargreaves <kathy@cs.umb.edu>
+
+ * identity.c (get_identity): Added.
+
+Sun Nov 26 12:47:00 1995 Kathy Hargreaves <karl@cs.umb.edu>
+
+ * bb-outline.c: (find_outline_bbs): Doc fix.
+
+ * edge.c: (next_unmarked_outline_edge): Doc fix.
+
+Fri Nov 24 05:48:20 1995 Kathy Hargreaves <karl@cs.umb.edu>
+
+ * concat*.c: made arguments const_string's to conform to .h files.
+ Call assert on the arguments, that they aren't NULL, because it
+ makes strlen blow up if they are. Set answer to NULL, and only
+ work on it if all the arguments are non-NULL.
+
+Thu Nov 23 09:08:00 1995 Kathy Hargreaves <karl@cs.umb.edu>
+
+ * font.c: (get_font): replaced find_tfm_filename with kpse_find_tfm.
+
+Thu Aug 24 16:00:46 1995 Karl Berry <karl@cs.umb.edu>
+
+ * GNUmakefile (c_only): strstr is now in kpathsea.
+
+Sat May 27 13:52:19 1995 Karl Berry <karl@cs.umb.edu>
+
+ * GNUmakefile (c_only): atou is in kpathsea.
+
+Fri Apr 14 15:56:43 1995 Karl Berry <karl@cs.umb.edu>
+
+ * GNUmakefile (c_only): Remove xfseek and xftell.
+
+Mon Oct 24 19:04:34 1994 Karl Berry <karl@cs.umb.edu>
+
+ * GNUmakefile (c_only): basename is in kpathsea now.
+
+Sun May 1 15:31:10 1994 Karl Berry (karl@cs.umb.edu)
+
+ * vector.c (Vangle): Declare const.
+
+Thu Sep 30 10:13:45 1993 Karl Berry (karl@cs.umb.edu)
+
+ * str-to-bit.c (string_to_bitmap): Call close_font.
+
+Sun Aug 1 09:56:42 1993 Karl Berry (karl@cs.umb.edu)
+
+ * Most *.c: Include files now in kpathsea.
+
+ * GNUmakefile (c_only): Add statistics, remove many things now in
+ kpathsea.
+
+Tue Jul 27 09:24:08 1993 Karl Berry (karl@cs.umb.edu)
+
+ * GNUmakefile (c_only): Remove dir-p and find-suffix (now in kpathsea).
+
+Fri May 21 13:45:30 1993 Karl Berry (karl@cs.umb.edu)
+
+ * gmalloc.c (my_memmove): New routine, since ISC doesn't have a
+ real memmove.
+
+Thu May 20 19:11:05 1993 Karl Berry (karl@cs.umb.edu)
+
+ * gmalloc.c: New file from the malloc distribution (plus a few
+ edits).
+ * GNUmakefile (malloc): Define to be gmalloc, and toss the old
+ malloc.c.
+
+Thu Apr 22 17:03:53 1993 Karl Berry (karl@cs.umb.edu)
+
+ * remove-suffx.c (remove_suffix): If no suffix, return the string,
+ not NULL.
+
+Tue Apr 6 19:58:45 1993 Karl Berry (karl@cs.umb.edu)
+
+ * malloc.c (getpagesize.h): Do not include.
+ (memalign, valloc): Remove, since we don't need them.
+
+ * filename.c (find_tfm_filename): Call extend_filename to get the
+ `.tfm', instead of just concatenating. Not sure if this is a good
+ idea, but periods in font names are problematic all over, I think.
+
+Tue Mar 16 07:47:38 1993 Karl Berry (karl@cs.umb.edu)
+
+ * fontmap.c (map_lookup): Don't extend the filename if there was
+ no suffix.
+
+Wed Mar 3 06:20:09 1993 Karl Berry (karl@cs.umb.edu)
+
+ * xftell.c (xftell): Declare as unsigned long.
+
+Mon Jan 18 15:43:02 1993 Karl Berry (karl@cs.umb.edu)
+
+ * xrealloc.c: Doc fix.
+
+Sun Jan 3 19:36:39 1993 Karl Berry (karl@cs.umb.edu)
+
+ * pathsrch.c (R_OK): Defined in the config files now.
+
+Fri Dec 11 15:00:31 1992 Karl Berry (karl@cs.umb.edu)
+
+ * font.c (print_char): Change ctype references to use uppercase macros.
+ * libfile.c (libfile_line),
+ * pathsrch.c (absolute_p),
+ * str-to-bit.c (string_to_bitmap),
+ * float-ok.c (float_ok),
+ * integer-ok.c (integer_ok),
+ * charspec.c (xparse_charspec): Likewise.
+
+Sun Nov 29 17:05:40 1992 Karl Berry (karl@cs.umb.edu)
+
+ * xmessage.c [X_DISPLAY_MISSING]: Conditionalize whole file.
+
+ * numtoa.c (xdtoa): Rename from `dtoa', to avoid Linux conflict.
+ (awasthi@cps.msu.edu)
+
+Tue Nov 17 09:25:58 1992 Karl Berry (karl@cs.umb.edu)
+
+ * hexify.c: Doc fix.
+
+Mon Nov 16 16:08:39 1992 Karl Berry (karl@cs.umb.edu)
+
+ * malloc.c (calloc): Complain if the malloc fails.
+
+Tue Oct 27 12:56:15 1992 Karl Berry (karl@cs.umb.edu)
+
+ * Version 0.6.
+
+Sun Oct 25 06:26:42 1992 Karl Berry (karl@cs.umb.edu)
+
+ * getopt.c: New version.
+
+Thu Oct 22 17:58:12 1992 Karl Berry (karl@cs.umb.edu)
+
+ * make-suffix.c: Doc fix.
+
+Tue Oct 20 11:57:57 1992 Karl Berry (karl@cs.umb.edu)
+
+ * filename.c (find_{gf,pk,tfm}_filename): Just concatenate the
+ suffix onto the main font name, don't replace a suffix.
+
+Mon Oct 5 10:07:59 1992 Karl Berry (karl@cs.umb.edu)
+
+ * report.c (report_file): New variable.
+
+Sun Oct 4 09:13:24 1992 Karl Berry (karl@cs.umb.edu)
+
+ * bb-list.c: New file, from bb-outline.c.
+ * GNUmakefile (c_only): Add it.
+ * bb-outline.c: Change calls and decls for new improved names.
+
+Sat Oct 3 16:58:38 1992 Karl Berry (karl@cs.umb.edu)
+
+ * bb-outline.c: Doc fix.
+
+Tue Sep 22 12:46:49 1992 Karl Berry (karl@cs.umb.edu)
+
+ * malloc.c (realloc): abort if we can't malloc enough memory to do
+ the realloc.
+
+ * bitmap.c (bb_ensure_bounds): new routine.
+ (extract_subbitmap): call it.
+
+Mon Sep 21 12:00:35 1992 Karl Berry (karl@cs.umb.edu)
+
+ * malloc.c: define NO_NEW_HANDLER.
+
+Thu Sep 3 09:31:06 1992 Karl Berry (karl@hayley)
+
+ * Version 0.5.
+
+Thu Aug 27 09:06:25 1992 Karl Berry (karl@hayley)
+
+ * getopt.c: update from MIT.
+
+Mon Aug 24 15:50:03 1992 Karl Berry (karl@hayley)
+
+ * rand.c (k_rand): use Ghostscript's algorithm exactly, to avoid
+ overflow problems.
+
+ * rand.c (seed_rand): Our simplification was a loser if the
+ state ever became zero, so set the state to the seed + 1, and
+ subtract again before output.
+
+Wed Aug 19 07:10:12 1992 Karl Berry (karl@hayley)
+
+ * charspec.c: doc fix.
+
+Mon Aug 17 15:43:42 1992 Karl Berry (karl@hayley)
+
+ * encoding.c: doc fix.
+
+Mon Aug 10 11:11:52 1992 Karl Berry (karl@hayley)
+
+ * rand.c (x): change the default seed to 1.
+
+Mon Jul 27 15:29:33 1992 Karl Berry (karl@hayley)
+
+ * charspec.c (xparse_charspec): use an `int' while figuring out
+ the charcode.
+
+Sat Jul 25 14:38:23 1992 Karl Berry (karl@hayley)
+
+ * getopt.c: new version.
+
+ * pathsrch.c (expand_tilde): cast the result of getpwnam.
+
+Sat Jul 18 16:35:41 1992 Karl Berry (karl@hayley)
+
+ * edge.c: add ^L's.
+
+Fri Jul 3 15:26:12 1992 Karl Berry (karl@hayley)
+
+ * charspec.c (xparse_charspec): if arg is one character long, and
+ undefined in the encoding, use its value in C.
+
+Fri Jun 26 16:53:39 1992 Karl Berry (karl@hayley)
+
+ * charspec.c: new file.
+ * GNUmakefile: add it.
+
+Thu Jun 25 07:04:49 1992 Karl Berry (karl@hayley)
+
+ * pathsrch.c (readable) [ENAMETOOLONG]: conditionalize the test
+ for doing our own truncating, since it appears not all systems
+ have ENAMETOOLONG.
+
+Sun Jun 14 08:11:32 1992 Karl Berry (karl@hayley)
+
+ * font.c (get_font): remove computation of NCHARS (and reading of
+ all the TFM chars).
+
+ * str-lcase.c (str_to_lower): assert the arg is non-null.
+
+Sat Jun 13 16:28:08 1992 Karl Berry (karl@hayley)
+
+ * libfile.c (libfile_start): return the FILE * we open.
+
+Sat Jun 13 13:52:30 1992 Kathy Hargreaves (kathy@hayley)
+
+ * encoding.c (DEFAULT_ENCODING): moved to .h file.
+
+Sat Jun 13 09:24:12 1992 Karl Berry (karl@hayley)
+
+ * encoding.c: include `str-lcase.h', not `str-casefold.h'.
+
+ * xmessage.c (x_message): cast initializer in `popup_args' to
+ avoid warning.
+
+ * str-to-bit.c (string_to_bitmap): `TFM_FONT_PARAMETER' is now
+ `TFM_FONTDIMEN'.
+
+ * pathsrch.c (absolute_p): add parens to stop GCC 2's stupid warning.
+
+ * encoding.c: change for new list fn names.
+ * font.c: likewise.
+
+ * list.c (new_list): rename to `list_init', and rewrite to use
+ accessor macros.
+ (append_element): rename to `list_append', and likewise rewrite.
+ (list_free): new routine.
+
+Sun Jun 7 17:25:43 1992 Karl Berry (karl@hayley)
+
+ * encoding.c (coding_scheme_to_filename): rewrite to avoid
+ sentinel boolean, lowercasing the passed codingscheme more than
+ once, etc.
+
+ * str-casefold.c (str_to_lower): rewrite to use ? :.
+ (str_to_upper): remove this.
+ Rename to str-lcase.c.
+ * GNUmakefile (c_only): change str-casefold to str-lcase.
+
+Sun Jun 7 14:39:09 1992 Kathy Hargreaves (kathy@hayley)
+
+ * bb-outline.c (find_outline_bbs): don't calculate edge if it's an
+ interior pixel.
+
+ * bb-outline.c (find_outline_bbs): deleted avoiding finding a
+ bounding box which corresponds to a counterform by not looking
+ inside existing bounding boxes.
+ Added finding the bounding box for a counterform (i.e., marking
+ its edges) but not adding it to the list unless find_all is true.
+ Changed find_all to find_inner.
+
+Sun Jun 7 08:55:31 1992 Karl Berry (karl@hayley)
+
+ * GNUmakefile (c_only): add `str-to-bit'.
+ * font.c (string_to_bitmap): extract the interword space out of
+ the TFM information, instead of expecting it in the main font
+ structure. Also, move this fn to its own file, `str-to-bit.c'.
+
+ * float-ok.c (float_ok): don't accept the empty string, or just a
+ sign, or just a sign and a `.', etc.
+ * integer-ok.c (integer_ok): likewise.
+
+Thu Jun 4 08:11:36 1992 Karl Berry (karl@hayley)
+
+ * pathsrch.c (absolute_p): `k./' should not be considered
+ explicitly relative.
+
+Tue Jun 2 11:40:32 1992 Karl Berry (karl@hayley)
+
+ * encoding.c (encoding_number): don't crash if NAME is NULL.
+
+Mon Jun 1 15:16:15 1992 Karl Berry (karl@hayley)
+
+ * GNUmakefile (c_only): add `integer-ok' and `float-ok'.
+ * {integer,float}-ok.c: new files.
+
+ * libfile.c (libfile_start): use extend_filename.
+
+ * encoding.c (read_encoding_file): initialize the return structure
+ after we know the file exists.
+
+Fri May 29 08:29:26 1992 Karl Berry (karl@hayley)
+
+ * getopt*.c: new versions.
+
+Sat May 23 15:51:53 1992 Karl Berry (karl@hayley)
+
+ * charcode.c (parse_charcode): ensure there are no extra
+ characters at the end of the charcode; change return type to
+ charcode_type.
+ (xparse_charcode): change return type.
+
+Sat May 23 12:33:32 1992 Kathy Hargreaves (kathy@hayley)
+
+ * str-casefold.c (str_to_lower): added variable `length'; put 0 at
+ end of return string.
+
+Sat May 23 06:27:28 1992 Karl Berry (karl@hayley)
+
+ * dir-p.c (leaf_dir_p): remove; `expand_subdir' now calls stat
+ itself, for efficiency.
+
+ * pathsrch.c (expand_subdir): rewrite to always look for subdirs.
+ (initialize_path_list): check for the dir-ness of `foo' in
+ `foo//'. This change makes symlinks under `foo' be considered.
+
+ * pathsrch.c (add_directory): don't check for the arg being a
+ directory.
+ (initialize_path_list): check here for the directory-ness of a
+ path element.
+ (expand_subdir): check here, too.
+
+ * pathsrch.c (expand_subdir): call closedir after we read the
+ directory contents.
+
+Thu May 21 11:40:53 1992 Karl Berry (karl@hayley)
+
+ * hexify.c (hexify): take a block of memory and a length, instead
+ of a varstring.
+
+Tue May 19 16:43:43 1992 Kathy Hargreaves (kathy@hayley)
+
+ * line.c (read_line): return a string if not at EOF.
+
+Sat May 16 21:22:57 1992 Kathy Hargreaves (kathy@hayley)
+
+ * varstring.c (vs_concat): added.
+
+Fri May 15 10:22:27 1992 Karl Berry (karl@hayley)
+
+ * getopt.c: new version.
+
+Thu May 14 22:05:10 1992 Karl Berry (karl@claude.cs.umb.edu)
+
+ * rand.c (srand): -> seed_rand, to avoid header conflicts.
+ (rand): -> k_rand, same reason.
+
+Sun May 10 10:05:36 1992 Karl Berry (karl@hayley)
+
+ * encoding.c (coding_scheme_to_filename): don't xstrdup the return
+ value.
+ (DEFAULT_ENCODING): new macro.
+
+Fri May 8 15:38:38 1992 Karl Berry (karl@hayley)
+
+ * pathshare from dvips.
+
+Thu May 7 16:44:14 1992 Karl Berry (karl@hayley)
+
+ * GNUmakefile (c_only): add dlsym.
+ * dlsym.c: new file.
+
+Wed May 6 10:08:09 1992 Karl Berry (karl@hayley)
+
+ * bitmap.c (bitmap_find_transitions): don't look outside the
+ current row when it's only one pixel long.
+
+Tue May 5 08:46:48 1992 Karl Berry (karl@hayley)
+
+ * dir-p.c: doc fix.
+
+Sat May 2 07:51:53 1992 Karl Berry (karl@hayley)
+
+ * pathsrch.c (add_directory): use ?:.
+
+Thu Apr 30 08:52:34 1992 Karl Berry (karl@hayley)
+
+ * pathsrch.c (parse_envpath): expand the ~ here;
+ (add_directory): not here.
+
+ * pathsrch.c (expand_tilde): free space for the login name.
+
+ * dir-p.c (leaf_dir_p): use stat, not xlstat, so we don't bomb
+ out on missing directories in paths, and so we get info about
+ the (potential) dir, not the link.
+
+Tue Apr 21 07:44:52 1992 Karl Berry (karl@hayley)
+
+ * bitmap.c (bitmap_find_transitions): use XTALLOC1.
+ * font.c (get_char): likewise.
+
+Mon Apr 20 08:35:23 1992 Karl Berry (karl@hayley)
+
+ * pathsrch.c: doc fix.
+
+ * malloc.c: don't include config.h.
+ (my_bzero, my_bcopy): new routines to simplify things.
+
+Sat Apr 18 12:22:29 1992 Kathy Hargreaves (kathy@hayley)
+
+ * str-casefold.c: added.
+
+ * encoding.c (coding_scheme_to_filename): compare case-folded
+ versions of the coding scheme and the mapped scheme.
+
+Wed Apr 15 15:23:20 1992 Karl Berry (karl@hayley)
+
+ * make-output.c: rename to `extend-fname.c'; rename the fn to
+ `extend_filename'.
+ * GNUmakefile (c_only): analogously.
+
+Wed Apr 15 13:20:11 1992 Kathy Hargreaves (kathy@hayley)
+
+ * encoding.c (coding_scheme_to_filename): changed some variable
+ names; added `mapped_coding' and set it to a second call to
+ strtok with `mapping'.
+
+Tue Apr 14 13:46:45 1992 Karl Berry (karl@hayley)
+
+ * scaled-num.c (scaled_to_real): as below.
+
+Sun Apr 12 15:06:58 1992 Karl Berry (karl@hayley)
+
+ * scaled-num.c (real_to_scaled): simplify to just multiply the
+ real by SCALED_UNITY.
+
+Fri Apr 10 16:36:33 1992 Karl Berry (karl@hayley)
+
+ * concat.c: put concat[345] in separate files.
+ * GNUmakefile (c_only): update.
+
+ * filename.c: remove prefix/suffix routines.
+ ({make-{output,prefix,suffix},remove-suffx,find-suffix}.c): new files.
+ * GNUmakefile (c_only): update.
+
+ * pathsrch.c (initialize_path_list): remove cwd_first_p.
+ * filename.c (find_*_filename): change calls.
+ * libfile.c (libfile_start): change call.
+
+Mon Apr 6 13:46:36 1992 Kathy Hargreaves (kathy@fosse)
+
+ * encoding.c (encoding_scheme_to_filename): added.
+
+Fri Apr 3 13:17:22 1992 Karl Berry (karl@hayley)
+
+ * rand.c: new file.
+ * GNUmakefile (c_only): include it.
+
+Wed Apr 1 14:14:01 1992 Karl Berry (karl at hayley)
+
+ * (pathshare from web2c)
+
+ * filename.c (make_output_filename): don't duplicate the input
+ string, just return it.
+
+ * filename.c (remove_suffix): remove.
+
+ * edge.c: new file.
+ * GNUmakefile (c_only): add it.
+ * bb-outline.c: remove edge stuff in favor of this new file.
+
+Tue Mar 31 13:35:51 1992 Karl Berry (karl at hayley)
+
+ * bitmap.c (bitmap_find_transitions): handle a row with a single
+ black pixel at the end correctly.
+
+Sun Mar 29 10:58:27 1992 Karl Berry (karl at hayley)
+
+ * xrealloc.c (xrealloc): cast the ptr.
+
+ * file-input.c (get_n_bytes): had args switched to fatal.
+
+ * bb-outline.c (is_outline_edge): remove the assertion that we're
+ at a valid pixel, since it's half-implied by the types, anyway.
+
+ * GNUmakefile (malloc.o): remove the special rule and vars.
+ * malloc.c [STDC_HEADERS | USG]: add the former for memset etc.
+
+Sat Mar 28 07:49:09 1992 Karl Berry (karl at hayley)
+
+ * malloc.c: new version, from libg++ 2.0.
+
+ * GNUmakefile (malloc_stats): don't define this.
+
+ * Version 0.4.
+
+ * Change copyright years to 1992 only.
+
+Wed Mar 25 08:37:28 1992 Karl Berry (karl at hayley)
+
+ * GNUmakefile (c_only): add fmod.
+ * fmod.c: new file.
+
+Thu Mar 19 07:47:30 1992 Karl Berry (karl at hayley)
+
+ * pathsearch.c, libfile.c, filename.c: include paths.h.
+
+ * pathsearch.c: rename to pathsrch.c; new version.
+
+Wed Mar 11 10:03:12 1992 Karl Berry (karl at hayley)
+
+ * bitmap.c (bitmap_find_transitions): handle the pixel at the end
+ of the row specially, unfortunately.
+
+Tue Mar 10 12:17:09 1992 Kathy Hargreaves (kathy at hayley)
+
+ * libfile.c (libfile_start): use find_suffix instead of finding a
+ dot position.
+
+Mon Mar 9 16:42:49 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (make_stem_suffix): remove suffix from name before
+ adding stem_suffix and putting suffix back on.
+
+ * filename.c (make_stem_suffix): don't add a dot if no suffix.
+
+ * filename.c (make_stem_suffix): added.
+
+Sun Mar 8 17:08:06 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (make_output_filename): put dot between NAME and
+ DEFAULT_SUFFIX.
+
+Sun Mar 8 08:37:46 1992 Karl Berry (karl at fosse)
+
+ * numtoa.c (dtoa): rename from ftoa.
+
+ * strstr.c: new file.
+ GNUmakefile (c_only): add strstr.
+
+Sat Mar 7 17:00:44 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (sizeless_font_name): removed.
+
+Sat Mar 7 13:21:33 1992 Karl Berry (karl at fosse)
+
+ * xmessage.c: include xmessage.h.
+
+ * GNUmakefile (c_only): remove statistics; we never use it.
+
+ * pathsearch.c: add prototypes for the subroutines.
+
+ * line.c: include line.h.
+
+ * bb-outline.c (find_outlines_bbs): rename parameters to avoid
+ shadow warnings.
+
+Sat Mar 7 09:14:00 1992 Karl Berry (karl at hayley)
+
+ * GNUmakefile (files, headers, sources): replace with `c_and_h', etc.
+
+ * scaled-num.c (print_scaled): use putchar instead of printf where
+ possible.
+
+Wed Mar 4 10:40:02 1992 Karl Berry (karl at hayley)
+
+ * filename.c (remove_suffix): don't include the `.' in what we
+ return.
+
+Tue Mar 3 16:28:38 1992 Karl Berry (karl at hayley)
+
+ * filename.c (find_suffix): new routine.
+ (remove_suffix, make_output_filename, make_suffix): write in terms
+ of it.
+
+Sun Mar 1 16:33:49 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (make_output_file): use concat instead of make_suffix.
+
+Sun Mar 1 15:17:28 1992 Karl Berry (karl at hayley)
+
+ * GNUmakefile (files): add bb-outline.
+
+Sun Mar 1 14:48:41 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (make_output_file): added.
+
+Mon Feb 24 08:38:56 1992 Karl Berry (karl at hayley)
+
+ * pathsearch.c (truncate_pathname): separate this out from `readable'.
+
+ * concat.c dir-p.c file-p.c pathsearch.c xmalloc.c xopendir.c
+ xrealloc.c xstat.c xstrdup.c: redo with (un)prototype macros.
+
+Wed Feb 19 10:00:35 1992 Karl Berry (karl at hayley)
+
+ * varstring.c (vs_set_char): set the allocated field after we
+ allocate more space.
+
+ * hexify.c (hexify): add 'a' to each hex char to make it visible
+ ASCII; shift the upper nybble down before adding.
+
+Mon Feb 17 07:38:27 1992 Karl Berry (karl at hayley)
+
+ * filename.c (sizeless_font_name): new routine.
+
+ * line.c (read_line): use vs_append_char, and generally simplify.
+
+ * varstring.c (vs_append_char): don't append a null afterwards.
+
+ * GNUmakefile (files): add it.
+ * hexify.c: new file.
+
+Sun Feb 16 10:31:41 1992 Karl Berry (karl at hayley)
+
+ * pathsearch.c (readable): keep track of the component lengths
+ properly; do the second test on the new name, not the old.
+
+Sat Feb 15 16:10:30 1992 Karl Berry (karl at hayley)
+
+ * pathsearch.c (READABLE): redo the macro as a function, and
+ truncate the pathname if necessary.
+
+Fri Feb 14 07:26:35 1992 Karl Berry (karl at hayley)
+
+ * varstring.c (vs_append_char): use VS_USED instead of strlen.
+ (vs_init): initialize VS_USED to zero.
+ (vs_set_char): set VS_USED.
+ All routines: rename `VS_LENGTH to `VS_ALLOCATED'.
+
+ * varstring.c (vs_free): new routine.
+
+ * math.c (acosd): clear errno before testing it.
+
+Thu Feb 13 13:32:54 1992 Karl Berry (karl at hayley)
+
+ * pathsearch.c (READABLE): call it readable if the error is
+ ENAMETOOLONG; include <errno.h> and declare errno if that is
+ undefined.
+
+Sun Feb 2 16:08:44 1992 Karl Berry (karl at hayley)
+
+ * filename.c (find_{gf,pk}_filename): allocate enough space for
+ the null sprintf writes.
+
+Sat Feb 1 14:53:39 1992 Karl Berry (karl at hayley)
+
+ * filename.c (depath): remove.
+
+ * pathsearch.c (initialize_path_list): subdirectories are now
+ indicated by // terminating a path element, instead of as
+ a separate envvar/path.
+ * filename.c (find*filename): remove subdirectory stuff.
+ * libfile.c (libfile_start): likewise.
+
+Mon Jan 20 11:09:10 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (depath): added this routine to take the path off the
+ front of a filename.
+
+ * filename.c (make_prefix): added this routine to add a prefix to
+ a filename which may or may not be the full pathname.
+
+Wed Jan 15 16:57:36 1992 Kathy Hargreaves (kathy at hayley)
+
+ * libfile.c (libfile_start): when FATAL, report `name', not it
+ concatenated with the default suffix.
+
+Wed Jan 15 13:01:30 1992 Karl Berry (karl at hayley)
+
+ * GNUmakefile (c_only): remove xchdir and xgetcwd, as we don't
+ need them anymore.
+ * pathsearch.c: changes from TeX.
+
+Wed Jan 15 11:59:56 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (find_*_filename): only free `name' if it's not the
+ same string as `*_name'.
+
+Tue Jan 14 12:36:15 1992 Kathy Hargreaves (kathy at hayley)
+
+ * bitmap.c (bitmap_find_transitions): make the last transition
+ always imply a black-to-white transition, even if ROW's last
+ pixel is black.
+
+ * libfile.c (libfile_start): make FATAL2 report `name', not
+ `filename' as the library file not found. Also, only add suffix
+ to the library file name if it doesn't have one already.
+
+Sun Jan 12 16:29:11 1992 Kathy Hargreaves (kathy at hayley)
+
+ * filename.c (make_suffix): copy suffix into new_s, not s.
+
+Sun Jan 12 14:57:24 1992 Karl Berry (karl at hayley)
+
+ * pathsearch.c (check_subdir): add every existing subdirectory,
+ even if it's not a leaf.
+
+Sun Jan 12 12:47:57 1992 Kathy Hargreaves (kathy at hayley)
+
+ * libfile.c (libfile_start): don't prepend a dot to the suffix.
+
+ * dir-p.c (dir_p): call stat instead of xstat.
+
+Sat Jan 11 15:01:02 1992 Karl Berry (karl at hayley)
+
+ * filename.c (find_*_filename): set cwd_first_p.
+
+ * pathsearch.c (initialize_path_list): take an additional
+ argument, saying whether to search `.' first.
+
+Fri Jan 10 07:40:50 1992 Karl Berry (karl at hayley)
+
+ * xgetcwd.c (xgetcwd) [GETWD_MISSING]: if it's not missing, use
+ it.
+
+ * filename.c (find_*_filename): only initialize the path lists
+ once.
+
+ * pathsearch.c (expand_colon): if env_path is null, return the
+ default path.
+
+ * file-input.c (MOVE_BACK): use xfseek.
+
+ * filename.c (*_suffix): use strrchr instead of rpos.
+
+ * varstring.c: change names to start with `vs'.
+
+ * memory.c: split into various files.
+
+ * math.c (adjacent_points): rename to `points_adjacent_p'.
+
+ * math.c (find_bounds): use MAXDOUBLE and MINDOUBLE instead of
+ MAXFLOAT and MINFLOAT.
+
+ * filename.c (find_dpi): move to cmdline.c.
+ (basename): move to basename.c.
+
+Thu Jan 9 08:57:39 1992 Karl Berry (karl at hayley)
+
+ * convert.c: split into various files.
+ * GNUmakefile: update.
+
+ * cmdline.c (scan_integer_list): rename to `scan_unsigned_list'.
+
+ * *.c: do not include global.h.
+
+ * arith.c: split into `scaled-num.c' and `fix-num.c'.
+ * GNUmakefile: update.
+
+Wed Jan 8 09:14:45 1992 Karl Berry (karl at hayley)
+
+ * update copyright messages.
+
+ * change `allocate to `xmalloc', `reallocate' to `xrealloc', and
+ `string_copy' to `strdup'.
+
+ * list.c: doc fix.
+
+Tue Jan 7 17:28:07 1992 Karl Berry (karl at hayley)
+
+ * filename.c (expand_colon): don't put the default value at the
+ end if we've already put it at the beginning.
+
+Thu Sep 12 11:06:58 1991 Karl Berry (karl at hayley)
+
+ * malloc.c (malloc_sanity_check): new function.
+
+ * bitmap.c (bitmap_find_transitions): rearrange logic for clarity.
+
+ * malloc.c, getpagesize.h: new files.
+ * GNUmakefile (c_only): add Doug Lea's malloc.
+ (malloc_stats, malloc_inline): new variables.
+ (malloc.o): rule to explicitly use them.
+
+Tue Jul 30 13:18:12 1991 Karl Berry (karl at ra.cs.umb.edu)
+
+ * Version 0.3.
+
+Wed Jul 24 06:34:11 1991 Karl Berry (karl at hayley)
+
+ * bitmap.c (concat_bitmaps): remove; it's only used in one program.
+
+ * bitmap.c (new_bitmap): call it.
+
+ * memory.c (xcalloc): new routine.
+
+Tue Jul 16 08:24:08 1991 Karl Berry (karl at hayley)
+
+ * memory.c (allocate): don't do assignment inside if.
+
+ * bitmap.c (bitmap_find_transitions): we don't need to look at the
+ first black pixel twice.
+
+Fri Jun 28 09:09:59 1991 Karl Berry (karl at hayley)
+
+ * font.c (close_font): only close the TFM file if the font is not
+ bitmap-only.
+
+Sat Jun 15 09:51:45 1991 Karl Berry (karl at hayley)
+
+ * font.c (get_font): set the new `tfm_font' and `tfm_filename'
+ members.
+
+ * {dirio,file-misc,file-open,filename,libfile}.c: change
+ `checked_' to `x'.
+
+Tue Jun 11 16:46:25 1991 Karl Berry (karl at hayley)
+
+ * font.c (get_char): use XTALLOC.
+
+ * font.c (close_font): close the TFM file here, instead of in
+ `get_font'.
+
+Sun Jun 9 13:23:59 1991 Karl Berry (karl at hayley)
+
+ * font.c (string_to_bitmap): use `BITMAP_PIXEL (CHAR_BITMAP'...
+ instead of `CHAR_BITMAP_PIXEL'.
+
+Thu Jun 6 07:30:07 1991 Karl Berry (karl at hayley)
+
+ * All files: change to version 2 of the GPL.
+
+Sat Jun 1 16:00:03 1991 Kathy Hargreaves (kathy at hayley)
+
+ * libfile.c (libfile_start): Don't concat a `.' to suffix if it's
+ the empty string.
+
+Thu May 16 07:35:47 1991 Karl Berry (karl at hayley)
+
+ * GNUmakefile (files): include `xmessage' (from xbce).
+ * xmessage.c: new file.
+
+Sun Apr 21 17:38:48 1991 Karl Berry (karl at hayley)
+
+ * bitmap.c (bitmap_to_bb): declare the arg as const.
+
+Sun Apr 14 13:45:29 1991 Karl Berry (karl at hayley)
+
+ * bitmap.c (print_bitmap): use `bitmap_to_bb' instead of
+ `dimensions_to_bb'.
+
+Fri Apr 12 15:12:32 1991 Karl Berry (karl at hayley)
+
+ * math.c: doc fix.
+
+ * GNUmakefile (files): add `report' and `logreport'.
+ * {log,}report.c: new files.
+
+Wed Apr 10 11:27:49 1991 Karl Berry (karl at hayley)
+
+ * font.c (save_internal_font): omit needless casts.
+
+Mon Apr 8 07:57:20 1991 Karl Berry (karl at hayley)
+
+ * font.c (ascender_part): move to ospace.
+
+ * encoding.c (parse_encoding_line): make a copy of the character
+ name, since the line gets freed.
+
+ * encoding.c (read_encoding_file): reinitialize the character
+ code, so we fill up the right array.
+
+ * libfile.c (libfile_start): prepend the `.' to the suffix.
+
+Sun Apr 7 14:34:06 1991 Karl Berry (karl at hayley)
+
+ * file-output.c (put_signed_four): declare this as a macro in the
+ .h file.
+
+Thu Apr 4 07:03:36 1991 Karl Berry (karl at hayley)
+
+ * font.c (get_char): don't allocate any space unless the character
+ actually exists in the font.
+
+Mon Apr 1 07:57:58 1991 Karl Berry (karl at hayley)
+
+ * {encoding,libfile}.c: new files.
+ GNUmakefile (files): add them to the list.
+
+Sat Mar 23 16:42:39 1991 Karl Berry (karl at hayley)
+
+ * font.c (delete_internal_font): free the memory for the internal
+ font, and for the font name.
+
+Sat Mar 9 17:06:57 1991 Karl Berry (karl at hayley)
+
+ * string.c: declare args to routines as const.
+
+ * string.c (lowercasify): new routine.
+
+Thu Mar 7 07:33:05 1991 Karl Berry (karl at hayley)
+
+ * Version 0.2.
+
+Mon Mar 4 15:06:59 1991 Karl Berry (karl at hayley)
+
+ * font.c (delete_internal_font): new routine.
+ (close_font): call it, thus preventing us from finding a font that
+ has been closed.
+
+Mon Feb 25 15:58:21 1991 Karl Berry (karl at hayley)
+
+ * font.c (get_font): use `tfm_...' instead of `..._tfm_...'; use
+ `pk_...' instead of `..._pk_...'; use `gf_...' instead of
+ `..._gf_...'.
+
+Sun Feb 24 15:34:36 1991 Karl Berry (karl at ra.cs.umb.edu)
+
+ * math.c (int_distance): cast the arguments to `double'.
+
+Sun Feb 17 09:43:06 1991 Karl Berry (karl at hayley)
+
+ * *.c: include config.h.
+
+Sat Feb 16 16:54:18 1991 Karl Berry (karl at hayley)
+
+ * dirio.c (checked_lstat) [HAVE_SYMBOLIC_LINKS]: change
+ conditional from being on S_ISLNK and S_IFLNK.
+
+Tue Jan 22 15:44:43 1991 Karl Berry (karl at hayley)
+
+ * bitmap.c (extract_subbitmap): new routine from imgtogf.
+
+Fri Jan 18 08:14:23 1991 Karl Berry (karl at hayley)
+
+ * vector.c (all routines): declare args to be const.
+
+ * vector.c (Vabs): new routine.
+
+Tue Jan 15 15:29:38 1991 Karl Berry (karl at hayley)
+
+ * spline.c (append_spline): use LAST_SPLINE_LIST_ELT.
+
+ * spline.c (new_spline_list_array, free_spline_list_array,
+ append_spline_list): new routines.
+
+ * spline.c (append_spline_list): rename to concat_spline_lists.
+
+Sun Jan 13 09:48:56 1991 Karl Berry (karl at hayley)
+
+ * font.c (bitmap_format_type): move to font.h.
+
+ * file-output.c (put_n_bytes): give the arguments to fwrite in the
+ correct order.
+
+Sat Jan 12 16:46:44 1991 Karl Berry (karl at hayley)
+
+ * file-output.c (put_n_bytes): use fwrite to do all the bytes at
+ one shot.
+
+Mon Jan 7 10:42:22 1991 Karl Berry (karl at hayley)
+
+ * spline.c (evaluate_spline): no compiler bug anymore without
+ temporaries (as of gcc 1.38).
+
+Sat Dec 29 17:43:40 1990 Karl Berry (karl at hayley)
+
+ * spline.c (print_spline): make the output lines shorter.
+
+Wed Dec 26 15:13:26 1990 Karl Berry (karl at hayley)
+
+ * math.c (find_bounds): use MAXFLOAT and MINFLOAT, instead of
+ MAXDOUBLE and MINDOUBLE, since Sun's atof can't deal with
+ the latter.
+
+Sun Dec 9 11:02:20 1990 Karl Berry (karl at hayley)
+
+ * spline.c: doc fix.
+
+ * dirio.c (getwd): close each directory after we read it.
+
+ * filename.c (find_subdir_path_filename): use getwd instead of
+ getcwd, and use checked_chdir.
+
+ * dirio.c (checked_opendir, is_dir): make arguments be const strings.
+
+ * dirio.c (checked_chdir, checked_stat, checked_lstat, getwd): new
+ routines.
+
+Sat Nov 17 11:09:56 1990 Karl Berry (karl at hayley)
+
+ * file-*.c: include the appropriate file-....h file.
+
+ * math.c (distance): put this back; it's too annoying to call
+ hypot with the x and y arguments.
+
+Thu Oct 18 15:00:32 1990 Karl Berry (karl at hayley)
+
+ * filename.c (find_subdir_path_filename): initialize the list of
+ subdirectories to the empty string.
+
+Wed Oct 17 17:54:40 1990 Karl Berry (karl at aten)
+
+ * filename.c (find_subdir_path_filename): do not do strlen when
+ the path is empty.
+
+Tue Oct 9 08:59:43 1990 Karl Berry (karl at hayley)
+
+ * filename.c (find_dpi): don't crash if the argument doesn't have
+ a `.' at all.
+
+ * cmdline.c: new file.
+ * GNUmakefile (files): add it.
+
+Mon Oct 8 09:08:30 1990 Karl Berry (karl at hayley)
+
+ * filename.c (find_dpi): new routine.
+
+Wed Oct 3 07:33:07 1990 Karl Berry (karl at hayley)
+
+ * filename.c (find_tfm_filename, find_pk_filename,
+ find_gf_filename): new routines.
+
+Sat Sep 29 08:34:52 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (new_bitmap): don't use memset if the bitmap is null.
+
+ * font.c (find_internal_font): use STREQ.
+
+Fri Sep 28 08:30:04 1990 Karl Berry (karl at hayley)
+
+ * filename.c (next_component): return NULL after we've read all
+ the directories in the list.
+
+ * filename.c (next_component): omit the path separator from the
+ returned directory.
+
+Thu Sep 27 11:45:36 1990 Karl Berry (karl at hayley)
+
+ * font.c (DEFAULT_SUBDIR_PATH): new macro.
+ (get_bitmap_font): try to open the PK and GF files using
+ subdirectories if opening without them fails.
+ (get_font): likewise, for the TFM file.
+ * filename.c (get_subdir_path_filename): new routine.
+ (next_component): new routine, replaces `find_components'.
+
+Fri Sep 21 09:15:28 1990 Karl Berry (karl at hayley)
+
+ * dirio.o (is_dir): use S_ISDIR.
+
+Thu Sep 13 10:38:32 1990 Karl Berry (karl at hayley)
+
+ * convert.c (parse_char_code): new routine to replace the
+ PARSE_CHAR_CODE macro; return a status indicator.
+ (xparse_char_code): like the above, but gives a fatal error.
+
+Wed Sep 12 18:19:13 1990 Karl Berry (karl at aten)
+
+ * font.c (get_font): set `bitmap_only' to false.
+ (save_internal_font): overwrite the old value if we're called with
+ the same key twice.
+
+Sun Sep 9 07:10:29 1990 Karl Berry (karl at hayley)
+
+ * convert.c: new file for some numeric conversions.
+ * math.c: move atou to convert.c.
+
+Mon Sep 3 11:05:19 1990 Karl Berry (karl at hayley)
+
+ * line.c (read_line): doc fix.
+
+Fri Aug 31 11:04:02 1990 Karl Berry (karl at hayley)
+
+ * font.c (get_bitmap_font): new routine, taken from get_font.
+
+Thu Aug 30 16:32:25 1990 Karl Berry (karl at hayley)
+
+ * file-misc.c (same_file_p): new function.
+
+Wed Aug 29 11:37:24 1990 Karl Berry (karl at hayley)
+
+ * fileio.c: split up into several new files: file-open.c,
+ file-input.c, file-output.c, file-misc.c.
+
+Thu Aug 23 07:26:58 1990 Karl Berry (karl at hayley)
+
+ * filename.c (remove_suffix): new routine.
+ (make_suffix): if the `.' is before a `/', it doesn't start the
+ extension.
+
+Thu Aug 16 07:10:48 1990 Karl Berry (karl at hayley)
+
+ * memory.c (safe_free): use fprintf instead of FATAL, so the core dump
+ will happen.
+
+Thu Jul 26 06:53:33 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (bitmap_find_transitions): new routine (from imgtogf).
+
+Wed Jul 25 08:20:12 1990 Karl Berry (karl at hayley)
+
+ * string.c (concat5): new routine.
+
+Tue Jul 24 10:24:59 1990 Karl Berry (karl at hayley)
+
+ * font.c (get_font): save the design size in points instead of
+ pixels.
+
+ * filename.c: new file.
+ * fileio.c (find_path_filename): move there.
+ * string.c (make_suffix): ditto.
+
+ * font.c (get_char): retrieve the TFM width also.
+
+Mon Jul 16 07:30:33 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (bitmap_to_bb): new routine.
+
+Thu Jul 12 06:01:16 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (copy_bitmap): don't use `new_bitmap', to avoid setting
+ all the bits twice.
+
+Tue Jul 10 06:23:54 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (concat_bitmaps): new routine.
+
+Mon Jul 9 08:27:09 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (get_bitmap_bounding_box): delete this.
+ (print_bitmap): use dimensions_to_bb.
+
+ * bitmap.c (free_bitmap): don't free the bitmap if it's null.
+
+ * bitmap.c (new_bitmap): use memset.
+ (copy_bitmap): use memcpy if the bitmap's size is greater than
+ zero.
+
+Sat Jul 7 18:22:55 1990 Karl Berry (karl at hayley)
+
+ * memory.c (safe_free): dump core if we are freeing a null item.
+
+Fri Jul 6 14:21:07 1990 Karl Berry (karl at hayley)
+
+ * bounding-box.c (bb_to_dimensions): ensure that the dimensions
+ are nonnegative.
+
+Wed Jul 4 12:06:49 1990 Karl Berry (karl at hayley)
+
+ * memory.c (allocate): dump core if we run out of memory.
+ (reallocate): ditto.
+
+ * bounding-box.c (dimensions_to_bb): don't subtract one from the
+ width, so it will work with the GF routines.
+ (bb_to_dimensions): use BB_WIDTH and BB_HEIGHT, instead of doing
+ the subtraction out here.
+
+ * bounding-box.c (update_bounding_box): new routine.
+
+Sun Jul 1 15:11:56 1990 Karl Berry (karl at hayley)
+
+ * font.c (ascender_part): new routine.
+
+Tue Jun 26 11:27:15 1990 Karl Berry (karl at hayley)
+
+ * spline.c (evaluate_spline): use temporaries in the computation
+ to avoid a compiler bug.
+
+ * vector.c (Padd, Pmult_scalar): remove definitions, since they
+ are defined as macros now.
+
+Sun Jun 24 15:31:34 1990 Karl Berry (karl at claude)
+
+ * font.c (get_font): don't check the checksums if either one is
+ zero.
+
+Sat Jun 23 12:11:47 1990 Karl Berry (karl at hayley)
+
+ * font.c (print_char): change precision for printing the row numbers.
+
+Tue Jun 19 11:50:52 1990 Karl Berry (karl at hayley)
+
+ * fileio.c (move_to_byte): delete this.
+
+ * fileio.c (cur_pos): rename to checked_ftell, and take a filename
+ argument for perror.
+
+Mon Jun 18 12:47:17 1990 Karl Berry (karl at hayley)
+
+ * font.c (find_internal_font): return a pointer to an
+ internal_font_type, instead of a structure, and change callers.
+ (get_font): if we have already saved the font, return it, instead
+ of opening the files again.
+
+Mon Jun 4 16:20:32 1990 Karl Berry (karl at hayley)
+
+ * math.c (find_bounds): use MAXDOUBLE and MINDOUBLE, instead of
+ MAXFLOAT and MINFLOAT.
+
+ * spline.c (spline_bounding_box): remove this routine.
+
+Sun Jun 3 10:51:28 1990 Karl Berry (karl at hayley)
+
+ * arith.c, math.c, vector.c: add const declarations.
+
+ * fileio.c (get_two, get_four): don't bother to initialize the
+ variable before we read it.
+
+ * fileio.c (get_n_bytes): improve the error message if the read
+ fails.
+
+Sat Jun 2 07:51:08 1990 Karl Berry (karl at hayley)
+
+ * bounding-box.c (increase_int_bound): remove this.
+
+ * spline.c (print_spline): print different things for lines and
+ splines.
+
+Wed May 30 16:02:26 1990 Karl Berry (karl at hayley)
+
+ * bitmap.c (new_bitmap): if the bitmap is going to be zero bits,
+ don't try to allocate it.
+
+ * font.c (get_font): figure out how many characters are in the
+ font by testing the `exists' member of the TFM structure.
+
+ * font.c (get_font): don't try to open the GF file if we couldn't
+ find it.
+
+Tue May 22 09:51:20 1990 Karl Berry (karl at hayley)
+
+ * fileio.c (find_path_filename): close the directories in the path.
+
+Sat May 19 10:30:39 1990 Karl Berry (karl at hayley)
+
+ * fileio.c (find_path_filename): return NULL if we can't find the
+ file, instead of the original name.
+ * font.c (get_font): rewrite the file-opening code.
+
+Wed May 16 18:02:54 1990 Karl Berry (karl at aten)
+
+ * font.c (string_to_bitmap): if the character doesn't exist in the
+ font, don't crash.
+
+ * fileio.c (find_path_filename): don't get a fatal error when a
+ directory in the path doesn't exist.
+
+Sun May 13 13:45:12 1990 Karl Berry (karl at hayley)
+
+ * dirio.c (is_dir): new routine.
+
+ * fileio.c (find_path_filename): just return the name we're given
+ if the path is relative; move the suffix concatenation out of the
+ loop; search in subdirectories.
+
+Tue May 8 12:08:57 1990 Karl Berry (karl at hayley)
+
+ * math.c: doc fix.
+
+Thu May 3 10:45:05 1990 Karl Berry (karl at hayley)
+
+ * line.c (read_line): use VS_CHARS.
+
+Wed May 2 12:25:08 1990 Karl Berry (karl at claude)
+
+ * font.c (string_to_bitmap): don't close the font when we're done.
+
+Wed Apr 25 13:16:28 1990 Karl Berry (karl at aten)
+
+ * font.c (string_to_bitmap): don't asked for chars[x] when x is a
+ character that isn't there.
+
+Tue Apr 24 18:35:08 1990 Karl Berry (karl at hayley)
+
+ * math.c (real_to_int_coord): new routine.
+
+Sun Apr 22 06:42:37 1990 Karl Berry (karl at hayley)
+
+ * font.c (string_to_bitmap): initialize char_y properly.
+ [whoops, I mean test it properly, and initialize y.]
+ Pass the row and column to BITMAP_PIXEL in the right order.
+ Give the row and column to the constructor in the right order,
+ too. Use MAX to find the depth, not MIN.
+
+ * font.c (print_char): print the bitmap here, so we can print out
+ the Cartesian row number, instead of calling `print_bitmap'.
+
+Sat Apr 21 09:49:42 1990 Karl Berry (karl at hayley)
+
+ * fileio.c (get_n_bytes): use fread to read the whole block,
+ instead of getting them one byte at a time.
+
+Thu Apr 19 16:19:33 1990 Karl Berry (karl at hayley)
+
+ * font.c (get_font): do checksum test before getting the
+ postamble.
+
+Tue Apr 17 16:53:31 1990 Karl Berry (karl at hayley)
+
+ * font.c (print_char): new routine to print a text representation
+ of a character.
+
+Mon Apr 16 11:12:28 1990 Karl Berry (karl at hayley)
+
+ * font.c (get_font): get the design size from the TFM file,
+ instead of the bitmap file.
+
+Sun Apr 15 07:34:19 1990 Karl Berry (karl at hayley)
+
+ * font.c (get_font): do not set the font bounding box.
+
+Sat Apr 14 15:11:19 1990 Karl Berry (karl at hayley)
+
+ * fileio.c (checked_fseek): make argument type be
+ seek_direction_type.
+
+ * fileio.c (checked_fclose): new (trivial) routine.
+
+Thu Apr 12 12:06:17 1990 Karl Berry (karl at hayley)
+
+ * GNUmakefile: do not define USG and USGr3.
+
+ * time.c: include <sys/types.h> and declare time(2) and ctime(3)
+ using time_t.
+
+ * fileio.c (find_path_filename): use access(2) instead of
+ fopen(3); pass the default path to find_components.
+ (find_components): use a default path if the environment variable
+ doesn't exist.
+
+Mon Apr 9 08:19:53 1990 Karl Berry (karl at hayley)
+
+ * math.c (distance): remove this, I came across hypot(3).
+
+ * all files: upcase macro names.
+
+Sun Mar 18 14:58:23 1990 Kathy Hargreaves (kathy at hayley)
+
+ * bounding_box.[hc] (increase_int_bound): added this to increase a
+ bounding boxes bounds nicely, i.e., if the bound is negative, it
+ gets decreased, and increased otherwise.
+
+Tue Feb 27 21:01:24 1990 Kathy Hargreaves (kathy at hayley)
+
+ * fileio.c (get_n_bytes): don't try to read zero bytes.
+
+Wed Feb 7 17:00:47 1990 Karl Berry (karl at hayley)
+
+ * time.c (now): chop off the trailing space.
+
+Mon Jan 29 12:46:56 1990 Karl Berry (karl at hayley)
+
+ * bounding-box.c (bb_to_dimensions): new routine.
+
+ * math.c (atou): like atoi but < 0 is a fatal error.
+
+Sun Jan 21 09:55:14 1990 Karl Berry (karl at hayley)
+
+ * Makefile: rename to GNUmakefile.
+
+ * bounding_box.c (dimensions_to_bounding_box): rename to
+ dimensions_bb. Remove other conversion routines. And rename to
+ bounding-box.c.
+
+Tue Oct 31 07:24:05 1989 Karl Berry (karl at hayley)
+
+ * math.c (int_to_real_coordinate): remove this.
+
+Mon Oct 30 14:03:57 1989 Karl Berry (karl at hayley)
+
+ * all files: add the copyleft.
+
+ * string.c (concat4): define this.
+
+Sun Oct 29 18:37:33 1989 Karl Berry (karl at claude)
+
+ * math.c (undefined_real_coordinate): remove this.
+
+Sat Oct 28 15:55:59 1989 Karl Berry (karl at hayley)
+
+ * arith.c (real_to_scaled, real_to_fix): multiply the integer part
+ by scaled_one and fix_one, respectively.
+
+ * fileio.c (put_three): define this.
+ (put_three, put_four): had the mask wrong for the
+ low-order byte.
+ (put_two, put_three, put_four): a & b >> c is
+ a & (b >> c), not (a & b) >> c.
+
+Fri Oct 27 22:14:05 1989 Karl Berry (karl at hayley)
+
+ * bitmap.c (new_bitmap): use the bitmap_dimensions macro.
+
+Sun Oct 8 15:41:01 1989 Karl Berry (karl at hayley)
+
+ * math.c (epsilon_equal): new function to test if two values are
+ within epsilon of each other.
+ (acosd): changed to call that one.
+
+ * bitmap.c (free_bitmap): new function to deallocate storage
+ used in a bitmap_type.
+
+ * math.c (acosd): normalize to 1.0 or -1.0 if the argument is
+ within an epsilon of that anyway.
+
+Fri Oct 6 22:12:05 1989 Karl Berry (karl at hayley)
+
+ * line.c (read_line): overwrite the newline at the end of the
+ string with a null.
diff --git a/lib/GNUmakefile b/lib/GNUmakefile
new file mode 100644
index 0000000..ed258fa
--- /dev/null
+++ b/lib/GNUmakefile
@@ -0,0 +1,38 @@
+# Makefile for the fontutils library.
+#
+# Copyright (C) 1992, 93 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+library = lib
+
+# If this gives you trouble, just remove it. The system malloc will
+# probably work well enough.
+#malloc = gmalloc
+
+# The headers are in the `include' directory, so don't use `c_and_h'.
+
+c_only = $(malloc) bb-list bb-outline bitmap bounding-box \
+charcode charspec cmdline concat concat3 concat4 concat5 dlsym edge \
+encoding float-ok fmod file-input file-output filename fix-num font \
+getopt getopt1 hexify identity integer-ok libfile line list logreport \
+make-prefix math now numtoa pathsrch rand report safe-free scaled-num \
+spline statistics str-lcase str-to-bit substring varstring vector \
+xmessage xopendir xrename
+
+include ../data/defs.make
+include ../data/defslib.make
+
+include M.depend
diff --git a/lib/README b/lib/README
new file mode 100644
index 0000000..4d0c220
--- /dev/null
+++ b/lib/README
@@ -0,0 +1,73 @@
+This library contains many miscellanous functions that are used by the
+other programs we have written.
+
+The declarations for the functions are in ../include. config.h must be
+included first in a .c file; that includes global.h, which declares a
+few of the most commonly used functions here. The rest have their own
+include files, e.g., line.h.
+
+Some functions merely call a C library routine or make a system call,
+check the return status, and abort if the function failed. (In the
+programs this has been used for, that was all that we ever wanted.)
+
+Here is a brief description of what's here (aside from the files which
+have just one function in them and other ``obvious'' ones):
+
+bb-outline find the outlines in a bitmap character.
+
+bitmap operations on bitmaps, with each pixel represented by a
+ byte in memory.
+
+bounding-box conversions to and from bounding boxes, both integer
+ and real.
+
+cmdline standard things for reading option lists.
+
+dirio directory operations.
+
+encoding read a font encoding specification in a .enc file.
+
+file-input read BigEndian values.
+
+file-open wrappers for fopen and fclose.
+
+file-output write BigEndian values.
+
+filename operations on filenames.
+
+fix-num conversions for the `fix_word' fixed-point fraction
+ type, used in TFM files et al.
+
+font read a bitmap font, or a bitmap font and its metrics.
+
+hexify convert a sequence of binary data to its hex representation.
+
+libfile read a `library', i.e., an auxiliary data, file.
+
+line read an arbitrarily long line from a file, returning a string.
+
+list generic list operations. It is a tossup as to whether
+ it is easier to repeat this code for the particular
+ lists you desire, or to use these, often with an extra
+ level of pointers. Unfortunately, C does not support
+ generic types.
+
+math distance, slope, etc., between two points; operations on
+ arrays as a collection of numeric data.
+
+now the current time as in date(1).
+
+pathsearch look up a filename along a path in an environment variable.
+
+report online progress reporting.
+
+scaled-num routines for the `scaled' fixed-point fraction
+ type, used in GF files et al.
+
+spline operations on Bezier splines.
+
+statistics find the mean/standard deviation of an array of numbers.
+
+varstring variable-length strings.
+
+vector operations on vectors and point/vector combinations.
diff --git a/lib/atou.o b/lib/atou.o
new file mode 100644
index 0000000..d15e642
--- /dev/null
+++ b/lib/atou.o
Binary files differ
diff --git a/lib/basename.o b/lib/basename.o
new file mode 100644
index 0000000..8242dd6
--- /dev/null
+++ b/lib/basename.o
Binary files differ
diff --git a/lib/bb-list.c b/lib/bb-list.c
new file mode 100644
index 0000000..e3df94e
--- /dev/null
+++ b/lib/bb-list.c
@@ -0,0 +1,76 @@
+/* bb-list.c: operations on bounding box lists.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "bb-list.h"
+
+
+/* This routine returns an initialized empty list. */
+
+bb_list_type
+bb_list_init ()
+{
+ bb_list_type bb_list;
+
+ BB_LIST_LENGTH (bb_list) = 0;
+ BB_LIST_DATA (bb_list) = NULL;
+
+ return bb_list;
+}
+
+/* Append BB to BB_LIST. */
+
+void
+bb_list_append (bb_list_type *bb_list, bounding_box_type bb)
+{
+ BB_LIST_LENGTH (*bb_list)++;
+ XRETALLOC (BB_LIST_DATA (*bb_list), BB_LIST_LENGTH (*bb_list),
+ bounding_box_type);
+
+ BB_LIST_ELT (*bb_list, BB_LIST_LENGTH (*bb_list) - 1) = bb;
+}
+
+/* Append the elements in the list B2 onto the end of B1. */
+
+void
+bb_list_splice (bb_list_type *b1, bb_list_type b2)
+{
+ unsigned new_length;
+ unsigned this_bb;
+
+ if (BB_LIST_LENGTH (b2) == 0)
+ return;
+
+ assert (b1 != NULL);
+
+ new_length = BB_LIST_LENGTH (*b1) + BB_LIST_LENGTH (b2);
+ XRETALLOC (BB_LIST_DATA (*b1), new_length, bounding_box_type);
+
+ for (this_bb = 0; this_bb < BB_LIST_LENGTH (b2); this_bb++)
+ BB_LIST_ELT (*b1, BB_LIST_LENGTH (*b1)++) = BB_LIST_ELT (b2, this_bb);
+}
+
+/* Free the memory in a list. */
+
+void
+bb_list_free (bb_list_type *bb_list)
+{
+ if (BB_LIST_DATA (*bb_list) != NULL)
+ safe_free ((address *) &BB_LIST_DATA (*bb_list));
+}
diff --git a/lib/bb-outline.c b/lib/bb-outline.c
new file mode 100644
index 0000000..1f0e3fa
--- /dev/null
+++ b/lib/bb-outline.c
@@ -0,0 +1,114 @@
+/* bb-outline.c: find the bounding boxes enclosing outlines.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "bb-outline.h"
+#include "edge.h"
+
+
+static bounding_box_type find_one_bb
+ (bitmap_type, edge_type, unsigned, unsigned, bitmap_type *);
+
+/* A character is made up of a list of one or more outlines. Here, we
+ go through a character's bitmap marking edges on pixels, top to
+ bottom, left to right, looking for the next pixel with an unmarked
+ edge that is also on the character's outline. Each one of these
+ pixels we find is the starting place for one outline. We then get the
+ bounding boxes of the outlines, and put them in a list to return. We
+ don't look at pixels that are at or after the column LEFT_MARK or
+ before RIGHT_MARK. If FIND_INNER is false, we return only outside
+ outlines; otherwise, we return both inside and outside. */
+
+bb_list_type
+find_outline_bbs (bitmap_type b, boolean find_inner,
+ int left_mark, int right_mark)
+{
+ unsigned row, col;
+ bb_list_type bb_list = bb_list_init ();
+ bitmap_type marked = new_bitmap (BITMAP_DIMENSIONS (b));
+
+ /* By looking through the bitmap in column-major order, we preserve
+ the original ordering of the characters in the image. Otherwise,
+ `b' would be found before `a' (for example), because of the
+ ascender. */
+ for (col = 0; col < BITMAP_WIDTH (b); col++)
+ if (col < left_mark || col >= right_mark)
+ for (row = 0; row < BITMAP_HEIGHT (b); row++)
+ {
+ edge_type edge;
+
+ if (BITMAP_PIXEL (b, row, col) == WHITE
+ || BITMAP_INTERIOR_PIXEL (b, row, col))
+ continue;
+
+ /* Get the next unmarked edge on this pixel, if there is one. */
+ edge = next_unmarked_outline_edge (row, col, START_EDGE, b, marked);
+
+ /* If there is an unmarked outline edge on this pixel... */
+ if (edge != no_edge)
+ {
+ /* Want to mark edges in inner boxes, too. */
+ bounding_box_type bb = find_one_bb (b, edge, row, col, &marked);
+
+ /* If edge != START_EDGE, it's on an inner bounding box. */
+ if (find_inner || edge == START_EDGE)
+ {
+ /* The numbers in BB, as it comes in, refer to pixels;
+ we have to change the maximum row so that it refers
+ to the edge beyond the last pixel. */
+ MAX_COL (bb)++;
+
+ bb_list_append (&bb_list, bb);
+ }
+ }
+ }
+
+ free_bitmap (&marked);
+ return bb_list;
+}
+
+/* Here we find one of a character's outlines. We're passed the
+ position (ORIGINAL_ROW and ORIGINAL_COL) of a starting pixel and one
+ of its unmarked edges, ORIGINAL_EDGE. We traverse the adjacent edges
+ of the outline pixels but keep the bounding box in pixel coordinates.
+ We keep track of the marked edges in MARKED, which should be
+ initialized to zeros before we get it. */
+
+static bounding_box_type
+find_one_bb (bitmap_type b, edge_type original_edge,
+ unsigned original_row, unsigned original_col,
+ bitmap_type *marked)
+{
+ bounding_box_type bb = { INT_MAX, INT_MIN, INT_MAX, INT_MIN };
+ unsigned row = original_row, col = original_col;
+ edge_type edge = original_edge;
+
+ do
+ {
+ coordinate_type p = { col, row };
+ update_bounding_box (&bb, p);
+
+ mark_edge (edge, row, col, marked);
+ next_outline_edge (b, &edge, &row, &col);
+ }
+ while (!(row == original_row && col == original_col
+ && edge == original_edge));
+
+ return bb;
+}
diff --git a/lib/bitmap.c b/lib/bitmap.c
new file mode 100644
index 0000000..9223c66
--- /dev/null
+++ b/lib/bitmap.c
@@ -0,0 +1,258 @@
+/* bitmap.c: operations on bitmaps.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "bitmap.h"
+#include "bounding-box.h"
+
+static void bb_ensure_bounds (bounding_box_type *, bitmap_type, string);
+
+/* Make sure the bitmap is entirely white to begin with. */
+
+bitmap_type
+new_bitmap (dimensions_type d)
+{
+ bitmap_type answer;
+ unsigned size = DIMENSIONS_WIDTH (d) * DIMENSIONS_HEIGHT (d);
+
+ BITMAP_DIMENSIONS (answer) = d;
+ BITMAP_BITS (answer) = size > 0 ? xcalloc (size, 1) : NULL;
+
+ return answer;
+}
+
+
+/* Free the storage that is allocated for a bitmap. On the other hand,
+ the bitmap might not have any storage allocated for it if it is zero
+ in either dimension; in that case, don't free it. */
+
+void
+free_bitmap (bitmap_type *b)
+{
+ if (BITMAP_BITS (*b) != NULL)
+ safe_free ((address *) &BITMAP_BITS (*b));
+}
+
+
+/* Copy an existing bitmap into new memory. We don't want to use
+ `new_bitmap' here, since that routine clears the bitmap's bits, and
+ we are going to set all the bits ourselves, anyway. */
+
+bitmap_type
+copy_bitmap (bitmap_type bitmap)
+{
+ bitmap_type answer;
+ unsigned size = BITMAP_WIDTH (bitmap) * BITMAP_HEIGHT (bitmap);
+
+ BITMAP_DIMENSIONS (answer) = BITMAP_DIMENSIONS (bitmap);
+ BITMAP_BITS (answer) = size > 0 ? xmalloc (size) : NULL;
+
+ if (size > 0)
+ memcpy (BITMAP_BITS (answer), BITMAP_BITS (bitmap), size);
+
+ return answer;
+}
+
+
+/* Return the part of the bitmap SOURCE enclosed by the bounding box BB.
+ BB is interpreted in bitmap coordinates, with y increasing downwards;
+ for example, if MIN_ROW (BB) == 10, the subimage will start in the
+ tenth row from the top of SOURCE. */
+
+bitmap_type
+extract_subbitmap (bitmap_type source, bounding_box_type bb)
+{
+ unsigned this_row;
+ bitmap_type sub = new_bitmap (bb_to_dimensions (bb));
+
+ /* Move to the bit at which we want to start copying. */
+ BITMAP_BITS (source) += MIN_ROW (bb) * BITMAP_WIDTH (source) + MIN_COL (bb);
+
+ bb_ensure_bounds (&bb, source, "extract_subbitmap");
+
+ for (this_row = MIN_ROW (bb); this_row <= MAX_ROW (bb); this_row++)
+ {
+ one_byte *target = BITMAP_ROW (sub, this_row - MIN_ROW (bb));
+
+ memcpy (target, BITMAP_BITS (source), BITMAP_WIDTH (sub));
+ BITMAP_BITS (source) += BITMAP_WIDTH (source);
+ }
+
+ return sub;
+}
+
+
+/* If any of the elements of BB (taken to be in bitmap coordinates) are
+ outside the bounds of the bitmap SOURCE, give a warning (using NAME)
+ and update them. */
+
+static void
+bb_ensure_bounds (bounding_box_type *bb, bitmap_type source, string name)
+{
+ if (MIN_COL (*bb) < 0)
+ {
+ WARNING2 ("%s: min col=%d outside source image", name, MIN_COL (*bb));
+ MIN_COL (*bb) = 0;
+ }
+
+ if (MIN_ROW (*bb) < 0)
+ {
+ WARNING2 ("%s: min row=%d outside source image", name, MIN_ROW (*bb));
+ MIN_COL (*bb) = 0;
+ }
+
+ /* See comments at `get_character_bitmap' in gf_input.c for why the
+ width and height are treated asymetrically. */
+ if (MAX_COL (*bb) > BITMAP_WIDTH (source))
+ {
+ WARNING2 ("%s: max col=%d outside source image", name, MAX_COL (*bb));
+ MAX_COL (*bb) = BITMAP_WIDTH (source) - 1;
+ }
+
+ if (MAX_ROW (*bb) >= BITMAP_HEIGHT (source))
+ {
+ WARNING2 ("%s: max row=%d outside source image", name, MAX_ROW (*bb));
+ MAX_COL (*bb) = BITMAP_HEIGHT (source) - 1;
+ }
+}
+
+/* The bounding boxes that we make in this routine are unlike the
+ bounding boxes used elsewhere. These are in bitmap coordinates, not
+ Cartesian, and they refer to pixels, not edges. So we have to adjust
+ the maximum column by one. */
+
+const bounding_box_type
+bitmap_to_bb (const bitmap_type b)
+{
+ bounding_box_type bb = dimensions_to_bb (BITMAP_DIMENSIONS (b));
+ if (MAX_COL (bb) != 0) MAX_COL (bb)--;
+
+ return bb;
+}
+
+/* Return the (zero-based) column numbers in which ROW changes from
+ black to white or white to black. The first element marks a
+ white-to-black transition, and the last element marks a
+ black-to-white transition, imagining that ROW is surrounded by white.
+ (In other words, there is always an even number of transitions.) We
+ mark the end of the vector with an element WIDTH + 1. */
+
+/* We use `length - 2' because we need to save one element at the end
+ for our sentinel. */
+#define INSERT_TRANSITION(e) \
+ do { \
+ XRETALLOC (vector, ++length, unsigned); \
+ vector[length - 2] = e; \
+ } while (0)
+
+unsigned *
+bitmap_find_transitions (const one_byte *row, unsigned width)
+{
+ unsigned col;
+ unsigned start;
+ one_byte color = BLACK;
+ unsigned length = 1;
+
+ /* We want to make sure we start at a column with some black. */
+ char *start_ptr = memchr (row, BLACK, width);
+
+ /* Save the last element for the sentinel. */
+ unsigned *vector = XTALLOC1 (unsigned);
+
+ if (start_ptr == NULL)
+ start = width; /* Don't go through the loop. */
+ else
+ {
+ INSERT_TRANSITION (start_ptr - (char *) row);
+ start = vector[0] + 1; /* Don't look at this pixel again. */
+ }
+
+ for (col = start; col < width - 1; col++)
+ {
+ if (row[col] != color)
+ {
+ INSERT_TRANSITION (col);
+ color = row[col];
+ }
+ }
+
+ /* We have to treat the last pixel in ROW specially. There are
+ several cases:
+ 1) if it's white, and the previous pixel is white, or the row is
+ one pixel long, do nothing;
+ 2) if it's white, and the previous pixel is black,
+ insert one element in `vector' (marking the end of a run);
+ 3) if it's black, and either the previous pixel is black or this was the
+ first black pixel in the row, insert one element (marking the
+ end of a run because we're at the end of the row);
+ 4) if it's black, and the previous pixel is white and there was a
+ previous black pixel, or the row was one pixel long, insert
+ two elements (marking the start and end of this one-pixel run).
+ */
+ if (row[width - 1] == WHITE)
+ {
+ if (width > 1 && row[width - 2] == BLACK)
+ INSERT_TRANSITION (width - 1);
+ }
+ else
+ { /* Last pixel is black. If previous pixel was also black, just
+ finish off the run. */
+ if (width > 1 && row[width - 2] == BLACK)
+ INSERT_TRANSITION (width);
+ else
+ { /* Last pixel is black, previous pixel was white. If this was
+ the only black pixel in the row, we've already inserted the
+ start of the run via `start' above, so just insert the end of
+ the run. Otherwise, insert both the start and end of this
+ one-pixel run. */
+ if (start != width)
+ INSERT_TRANSITION (width - 1);
+ INSERT_TRANSITION (width);
+ }
+ }
+
+ vector[length - 1] = width + 1; /* Sentinel for the end of the vector. */
+ return vector;
+}
+
+/* Print a part of the bitmap in human-readable form. */
+
+void
+print_bounded_bitmap (FILE *f, bitmap_type bitmap, bounding_box_type bb)
+{
+ unsigned this_row, this_col;
+
+ fprintf (f, "Printing bitmap between (%u,%u) and (%u,%u):\n",
+ MIN_COL (bb), MIN_ROW (bb),
+ MAX_COL (bb), MAX_ROW (bb));
+ for (this_row = MIN_ROW (bb); this_row <= MAX_ROW (bb); this_row++)
+ {
+ for (this_col = MIN_COL (bb); this_col <= MAX_COL (bb); this_col++)
+ putc (BITMAP_PIXEL (bitmap, this_row, this_col) ? '*' : ' ', f);
+
+ fprintf (f, "%u\n", this_row);
+ }
+}
+
+
+void
+print_bitmap (FILE *f, bitmap_type b)
+{
+ print_bounded_bitmap (f, b, bitmap_to_bb (b));
+}
diff --git a/lib/bounding-box.c b/lib/bounding-box.c
new file mode 100644
index 0000000..25f0b74
--- /dev/null
+++ b/lib/bounding-box.c
@@ -0,0 +1,78 @@
+/* bounding-box.c: definitions for bounding box operations.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "bounding-box.h"
+
+
+/* See the comments at `get_character_bitmap' in gf_input.c for why the
+ width and height are treated asymmetrically. */
+
+const bounding_box_type
+dimensions_to_bb (dimensions_type dimensions)
+{
+ bounding_box_type answer;
+
+ MIN_ROW (answer) = 0;
+ MIN_COL (answer) = 0;
+ MAX_ROW (answer) = MAX ((int) DIMENSIONS_HEIGHT (dimensions) - 1, 0);
+ MAX_COL (answer) = MAX (DIMENSIONS_WIDTH (dimensions), 0);
+
+ return answer;
+}
+
+
+/* Dimensions can't be negative, even though bounding boxes can, so we
+ have to check. */
+
+const dimensions_type
+bb_to_dimensions (bounding_box_type bb)
+{
+ dimensions_type d;
+
+ DIMENSIONS_WIDTH (d) = MAX (BB_WIDTH (bb), 0);
+ DIMENSIONS_HEIGHT (d) = MAX (BB_HEIGHT (bb), 0);
+
+ return d;
+}
+
+
+/* If the point P lies outside of any of the current bounds in BB,
+ update BB. */
+
+void
+update_real_bounding_box (real_bounding_box_type *bb, real_coordinate_type p)
+{
+ if (p.x < MIN_COL (*bb)) MIN_COL (*bb) = p.x;
+ if (p.x > MAX_COL (*bb)) MAX_COL (*bb) = p.x;
+ if (p.y < MIN_ROW (*bb)) MIN_ROW (*bb) = p.y;
+ if (p.y > MAX_ROW (*bb)) MAX_ROW (*bb) = p.y;
+
+}
+
+
+void
+update_bounding_box (bounding_box_type *bb, coordinate_type p)
+{
+ if (p.x < MIN_COL (*bb)) MIN_COL (*bb) = p.x;
+ if (p.x > MAX_COL (*bb)) MAX_COL (*bb) = p.x;
+ if (p.y < MIN_ROW (*bb)) MIN_ROW (*bb) = p.y;
+ if (p.y > MAX_ROW (*bb)) MAX_ROW (*bb) = p.y;
+
+}
diff --git a/lib/charcode.c b/lib/charcode.c
new file mode 100644
index 0000000..931928f
--- /dev/null
+++ b/lib/charcode.c
@@ -0,0 +1,85 @@
+/* charcode.c: parse character code strings into their values.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* This routine parses the string CHARCODE as a character code (see the
+ .h file). If CHARCODE cannot be parsed, *VALID is set to false and
+ the value returned is unpredictable; otherwise, it is set to true and
+ the value returned is the character code. */
+
+charcode_type
+parse_charcode (string charcode, boolean *valid)
+{
+ int code = 75; /* OK, it's not *really* unpredictable. */
+ unsigned length = strlen (charcode);
+
+ if (charcode == NULL || length == 0)
+ *valid = false;
+ else
+ { /* We need this to ensure that there are no extra characters after
+ the character code. */
+ char dummy;
+
+ /* If a single character, return its value. */
+ if (length == 1)
+ {
+ *valid = true;
+ code = *charcode;
+ }
+
+ else if (*charcode == '0')
+ { /* Either octal or hex. */
+ if (*(charcode + 1) == 'x' || *(charcode + 1) == 'X')
+ /* It seems not all scanf's ignore a leading `0x'. */
+ *valid = sscanf (charcode + 2, "%x%c", &code, &dummy) == 1;
+ else
+ /* octal */
+ *valid = sscanf (charcode, "%o%c", &code, &dummy) == 1;
+ }
+
+ else
+ /* decimal */
+ *valid = sscanf (charcode, "%d%c", &code, &dummy) == 1;
+
+ /* Since our return type can only hold numbers up to 255 (typically),
+ we are justified in using the numeric constant here, instead of
+ `MAX_CHARCODE'. */
+ if (*valid)
+ *valid = 0 <= code && code <= 255;
+ }
+
+ return code;
+}
+
+
+/* This routine calls `parse_charcode', and, if the character code is
+ invalid, gives a fatal error. */
+
+charcode_type
+xparse_charcode (string charcode)
+{
+ boolean valid;
+ charcode_type code = parse_charcode (charcode, &valid);
+
+ if (!valid)
+ FATAL1 ("xparse_charcode: Invalid character code `%s'", charcode);
+
+ return code;
+}
diff --git a/lib/charspec.c b/lib/charspec.c
new file mode 100644
index 0000000..cf7c407
--- /dev/null
+++ b/lib/charspec.c
@@ -0,0 +1,63 @@
+/* charspec.c: parse a character code or name.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/c-ctype.h>
+#include "charspec.h"
+#include "encoding.h"
+
+
+charcode_type
+xparse_charspec (string spec, encoding_info_type *enc)
+{
+ int code;
+
+ /* It's an error to call this with SPEC == NULL or the empty string. */
+ assert (spec != NULL && *spec);
+
+ if (ISDIGIT (*spec))
+ code = xparse_charcode (spec);
+
+ else if (enc == NULL)
+ {
+ /* If ENC is null, and SPEC is longer than a single character, we
+ don't know what to do. */
+ if (spec[1] != 0)
+ FATAL1 ("%s: Unparseable character specification", spec);
+ else
+ code = *spec;
+ }
+
+ else
+ {
+ int code = encoding_number (*enc, spec);
+
+ /* If SPEC is not in the encoding, and it's one character long,
+ just use its value as a C integer. */
+ if (code == -1)
+ {
+ if (spec[1] == 0)
+ code = spec[0];
+ else
+ FATAL1 ("%s: Undefined character name", spec);
+ }
+ }
+
+ return (charcode_type) code;
+}
diff --git a/lib/cmdline.c b/lib/cmdline.c
new file mode 100644
index 0000000..3552fae
--- /dev/null
+++ b/lib/cmdline.c
@@ -0,0 +1,63 @@
+/* cmdline.c: routines to help in parsing command lines.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "cmdline.h"
+
+
+/* This routine takes a string L consisting of unsigned integers
+ separated by commas and returns a vector of the integers, as numbers.
+ A element is appended to the vector. */
+
+int *
+scan_unsigned_list (string l)
+{
+ string map;
+ unsigned length = 1;
+ int *vector = xmalloc (sizeof (int));
+
+ for (map = strtok (l, ","); map != NULL; map = strtok (NULL, ","))
+ {
+ length++;
+ vector = xrealloc (vector, length * sizeof (int));
+ vector[length - 2] = atou (map);
+ if (vector[length - 2] < 0)
+ WARNING1 ("Unsigned number %u is too large", vector[length - 2]);
+ }
+
+ vector[length - 1] = -1;
+ return vector;
+}
+
+
+/* Return the <number> substring in `<name>.<number><stuff>', if S has
+ that form. If it doesn't, return NULL. */
+
+string
+find_dpi (string s)
+{
+ unsigned dpi_number;
+ string extension = strrchr (s, '.');
+
+ if (extension != NULL)
+ if (sscanf (extension + 1, "%u", &dpi_number) == 1)
+ return utoa (dpi_number);
+
+ return NULL;
+}
diff --git a/lib/concat.c b/lib/concat.c
new file mode 100644
index 0000000..946ed19
--- /dev/null
+++ b/lib/concat.c
@@ -0,0 +1,41 @@
+/* concat.c: dynamic string concatenation.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+/* Return the concatenation of S1 and S2. This would be a prime place
+ to use varargs. */
+
+string
+concat P2C(const_string, s1, const_string, s2)
+{
+ string answer = NULL;
+
+ assert (s1 != NULL);
+ assert (s2 != NULL);
+
+ if (s1 != NULL && s2 != NULL)
+ {
+ answer = (string) xmalloc (strlen (s1) + strlen (s2) + 1);
+
+ strcpy (answer, s1);
+ strcat (answer, s2);
+ }
+
+ return answer;
+}
diff --git a/lib/concat3.c b/lib/concat3.c
new file mode 100644
index 0000000..383a54c
--- /dev/null
+++ b/lib/concat3.c
@@ -0,0 +1,40 @@
+/* concat3.c: concatenate three strings.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+string
+concat3 P3C(const_string, s1, const_string, s2, const_string, s3)
+{
+ string answer = NULL;
+
+ assert (s1 != NULL);
+ assert (s2 != NULL);
+ assert (s3 != NULL);
+
+ if (s1 != NULL && s2 != NULL && s3 != NULL)
+ {
+ answer = (string) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
+
+ strcpy (answer, s1);
+ strcat (answer, s2);
+ strcat (answer, s3);
+ }
+
+ return answer;
+}
diff --git a/lib/concat4.c b/lib/concat4.c
new file mode 100644
index 0000000..f8b3d06
--- /dev/null
+++ b/lib/concat4.c
@@ -0,0 +1,43 @@
+/* concat4.c: concatenate four strings.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+string
+concat4 P4C(const_string, s1, const_string, s2, const_string, s3,
+ const_string, s4)
+{
+ string answer = NULL;
+
+ assert (s1 != NULL);
+ assert (s2 != NULL);
+ assert (s3 != NULL);
+ assert (s4 != NULL);
+
+ if (s1 != NULL && s2 != NULL && s3 != NULL && s4 != NULL)
+ {
+ answer = (string) xmalloc (strlen (s1) + strlen (s2)
+ + strlen (s3) + strlen (s4) + 1);
+ strcpy (answer, s1);
+ strcat (answer, s2);
+ strcat (answer, s3);
+ strcat (answer, s4);
+ }
+
+ return answer;
+}
diff --git a/lib/concat5.c b/lib/concat5.c
new file mode 100644
index 0000000..fbf9601
--- /dev/null
+++ b/lib/concat5.c
@@ -0,0 +1,45 @@
+/* concat5.c: concatenate five strings.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+string
+concat5 P5C(const_string, s1, const_string, s2, const_string, s3,
+ const_string, s4, const_string, s5)
+{
+ string answer = NULL;
+
+ assert (s1 != NULL);
+ assert (s2 != NULL);
+ assert (s3 != NULL);
+ assert (s4 != NULL);
+ assert (s5 != NULL);
+
+ if (s1 != NULL && s2 != NULL && s3 != NULL && s4 != NULL && s5 != NULL)
+ {
+ answer = (string) xmalloc (strlen (s1) + strlen (s2) + strlen (s3)
+ + strlen (s4) + strlen (s5) + 1);
+ strcpy (answer, s1);
+ strcat (answer, s2);
+ strcat (answer, s3);
+ strcat (answer, s4);
+ strcat (answer, s5);
+ }
+
+ return answer;
+}
diff --git a/lib/dlsym.c b/lib/dlsym.c
new file mode 100644
index 0000000..c14ffdd
--- /dev/null
+++ b/lib/dlsym.c
@@ -0,0 +1,28 @@
+/*
+ * Stub interface to dynamic linker routines
+ * that SunOS uses but didn't ship with 4.1.
+ *
+ * The C library routine wcstombs in SunOS 4.1 tries to dynamically
+ * load some routines using the dlsym interface, described in dlsym(3x).
+ * Unfortunately SunOS 4.1 does not include the necessary library, libdl.
+ *
+ * The R5 Xlib uses wcstombs. If you link dynamcally, your program can
+ * run even with the unresolved reference to dlsym. However, if you
+ * link statically, you will encounter this bug. One workaround
+ * is to include these stub routines when you link.
+ */
+
+void *dlopen()
+{
+ return 0;
+}
+
+void *dlsym()
+{
+ return 0;
+}
+
+int dlclose()
+{
+ return -1;
+}
diff --git a/lib/edge.c b/lib/edge.c
new file mode 100644
index 0000000..7bec506
--- /dev/null
+++ b/lib/edge.c
@@ -0,0 +1,265 @@
+/* edge.c: operations on edges in bitmaps.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "edge.h"
+
+
+/* We can move in any of eight directions as we are traversing
+ the outline. These numbers are not arbitrary; TRY_PIXEL depends on
+ them. */
+
+typedef enum
+{
+ north = 0, northwest = 1, west = 2, southwest = 3, south = 4,
+ southeast = 5, east = 6, northeast = 7
+} direction_type;
+
+
+static boolean is_marked_edge (edge_type, unsigned, unsigned, bitmap_type);
+static boolean is_outline_edge (edge_type, bitmap_type, unsigned, unsigned);
+static edge_type next_edge (edge_type);
+
+/* The following macros are used (directly or indirectly) by the
+ `next_outline_edge' routine. */
+
+/* Given the direction DIR of the pixel to test, decide which edge on
+ that pixel we are supposed to test. Because we've chosen the mapping
+ from directions to numbers carefully, we don't have to do much. */
+
+#define FIND_TEST_EDGE(dir) ((dir) / 2)
+
+
+/* Find how to move in direction DIR on the axis AXIS (either `ROW' or
+ `COL'). We are in the ``display'' coordinate system, with y
+ increasing downward and x increasing to the right. Therefore, we are
+ implementing the following table:
+
+ direction row delta col delta
+ north -1 0
+ south +1 0
+ east 0 +1
+ west 0 +1
+
+ with the other four directions (e.g., northwest) being the sum of
+ their components (e.g., north + west).
+
+ The first macro, `COMPUTE_DELTA', handles splitting up the latter
+ cases, all of which have been assigned odd numbers. */
+
+#define COMPUTE_DELTA(axis, dir) \
+ ((dir) % 2 != 0 \
+ ? COMPUTE_##axis##_DELTA ((dir) - 1) \
+ + COMPUTE_##axis##_DELTA (((dir) + 1) % 8) \
+ : COMPUTE_##axis##_DELTA (dir) \
+ )
+
+/* Now it is trivial to implement the four cardinal directions. */
+#define COMPUTE_ROW_DELTA(dir) \
+ ((dir) == north ? -1 : (dir) == south ? +1 : 0)
+
+#define COMPUTE_COL_DELTA(dir) \
+ ((dir) == west ? -1 : (dir) == east ? +1 : 0)
+
+
+/* See if the appropriate edge on the pixel from (row,col) in direction
+ DIR is on the outline. If so, update `row', `col', and `edge', and
+ break. We also use the variable `character' as the bitmap in which
+ to look. */
+
+#define TRY_PIXEL(dir) \
+ { \
+ int delta_r = COMPUTE_DELTA (ROW, dir); \
+ int delta_c = COMPUTE_DELTA (COL, dir); \
+ int test_row = *row + delta_r; \
+ int test_col = *col + delta_c; \
+ edge_type test_edge = FIND_TEST_EDGE (dir); \
+ \
+ if (BITMAP_VALID_PIXEL (character, test_row, test_col) \
+ && is_outline_edge (test_edge, character, test_row, test_col)) \
+ { \
+ *row = test_row; \
+ *col = test_col; \
+ *edge = test_edge; \
+ break; \
+ } \
+ }
+
+/* Finally, we are ready to implement the routine that finds the next
+ edge on the outline. We look first for an adjacent edge that is not
+ on the current pixel. We want to go around outside outlines
+ counterclockwise, and inside outlines clockwise (because that is how
+ both Metafont and Adobe Type 1 format want their curves to be drawn).
+
+ The very first outline (an outside one) on each character starts on a
+ top edge (STARTING_EDGE in edge.h defines this); so, if we're at a
+ top edge, we want to go only to the left (on the pixel to the west)
+ or down (on the same pixel), to begin with. Then, when we're on a
+ left edge, we want to go to the top edge (on the southwest pixel) or
+ to the left edge (on the south pixel).
+
+ All well and good. But if you draw a rasterized circle (or whatever),
+ eventually we have to come back around to the beginning; at that
+ point, we'll be on a top edge, and we'll have to go to the right edge
+ on the northwest pixel. Draw pictures.
+
+ The upshot is, if we find an edge on another pixel, we return (in ROW
+ and COL) the position of the new pixel, and (in EDGE) the kind of
+ edge it is. If we don't find such an edge, we return (in EDGE) the
+ next (in a counterclockwise direction) edge on the current pixel. */
+
+void
+next_outline_edge (bitmap_type character, edge_type *edge,
+ unsigned *row, unsigned *col)
+{
+ unsigned original_row = *row;
+ unsigned original_col = *col;
+
+ switch (*edge)
+ {
+ case right:
+ TRY_PIXEL (north);
+ TRY_PIXEL (northeast);
+ break;
+
+ case top:
+ TRY_PIXEL (west);
+ TRY_PIXEL (northwest);
+ break;
+
+ case left:
+ TRY_PIXEL (south);
+ TRY_PIXEL (southwest);
+ break;
+
+ case bottom:
+ TRY_PIXEL (east);
+ TRY_PIXEL (southeast);
+ break;
+
+ default:
+ FATAL1 ("next_outline_edge: Bad edge value (%d)", *edge);
+
+ }
+
+ /* If we didn't find an adjacent edge on another pixel, return the
+ next edge on the current pixel. */
+ if (*row == original_row && *col == original_col)
+ *edge = next_edge (*edge);
+}
+
+/* We return the next edge on the pixel at position ROW and COL which is
+ an unmarked outline edge. By ``next'' we mean either the one sent in
+ in STARTING_EDGE, if it qualifies, or the next such returned by
+ `next_edge'. Otherwise, it returns NO_EDGE. */
+
+edge_type
+next_unmarked_outline_edge (unsigned row, unsigned col,
+ edge_type starting_edge, bitmap_type character,
+ bitmap_type marked)
+{
+ edge_type edge = starting_edge;
+
+ assert (edge != no_edge);
+
+ while (is_marked_edge (edge, row, col, marked)
+ || !is_outline_edge (edge, character, row, col))
+ {
+ edge = next_edge (edge);
+ if (edge == starting_edge)
+ return no_edge;
+ }
+
+ return edge;
+}
+
+
+/* We check to see if the edge EDGE of the pixel at position ROW and COL
+ is an outline edge; i.e., that it is a black pixel which shares that
+ edge with a white pixel. The position ROW and COL should be inside
+ the bitmap CHARACTER. */
+
+boolean
+is_outline_edge (edge_type edge, bitmap_type character,
+ unsigned row, unsigned col)
+{
+ /* If this pixel isn't black, it's not part of the outline. */
+ if (BITMAP_PIXEL (character, row, col) == WHITE)
+ return false;
+
+ switch (edge)
+ {
+ case left:
+ return col == 0 || BITMAP_PIXEL (character, row, col - 1) == WHITE;
+
+ case top:
+ return row == 0 || BITMAP_PIXEL (character, row - 1, col) == WHITE;
+
+ case right:
+ return col == BITMAP_WIDTH (character) - 1
+ || BITMAP_PIXEL (character, row, col + 1) == WHITE;
+
+ case bottom:
+ return row == BITMAP_HEIGHT (character) - 1
+ || BITMAP_PIXEL (character, row + 1, col) == WHITE;
+
+ case no_edge:
+ default:
+ FATAL1 ("is_outline_edge: Bad edge value(%d)", edge);
+ }
+
+ return 0; /* NOTREACHED */
+}
+
+/* If EDGE is not already marked, we mark it; otherwise, it's a fatal error.
+ The position ROW and COL should be inside the bitmap MARKED. EDGE can
+ be `no_edge'; we just return false. */
+
+void
+mark_edge (edge_type edge, unsigned row, unsigned col, bitmap_type *marked)
+{
+ assert (!is_marked_edge (edge, row, col, *marked));
+
+ if (edge != no_edge)
+ BITMAP_PIXEL (*marked, row, col) |= 1 << edge;
+}
+
+
+/* Test if the edge EDGE at ROW/COL in MARKED is marked. */
+
+static boolean
+is_marked_edge (edge_type edge, unsigned row, unsigned col, bitmap_type marked)
+{
+ return
+ edge == no_edge ? false : BITMAP_PIXEL (marked, row, col) & (1 << edge);
+}
+
+
+/* Return the edge which is counterclockwise-adjacent to EDGE. This
+ code makes use of the ``numericness'' of C enumeration constants;
+ sorry about that. */
+
+#define NUM_EDGES no_edge
+
+static edge_type
+next_edge (edge_type edge)
+{
+ return edge == no_edge ? edge : (edge + 1) % NUM_EDGES;
+}
+
diff --git a/lib/encoding.c b/lib/encoding.c
new file mode 100644
index 0000000..a40d281
--- /dev/null
+++ b/lib/encoding.c
@@ -0,0 +1,191 @@
+/* encoding.c: read a font encoding (.enc) file.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "encoding.h"
+#include "libfile.h"
+#include "str-lcase.h"
+#include "tfm.h"
+
+
+static encoding_char_type parse_encoding_line (string);
+static tfm_ligature_type parse_ligature (void);
+
+/* Look through INFO for NAME. */
+
+int
+encoding_number (encoding_info_type info, string name)
+{
+ unsigned code;
+
+ if (name == NULL)
+ return -1;
+
+ for (code = 0; code <= MAX_CHARCODE; code++)
+ if (ENCODING_CHAR_NAME (info, code) != NULL
+ && STREQ (ENCODING_CHAR_NAME (info, code), name))
+ return code;
+
+ return -1;
+}
+
+/* Return the basename for the encoding file in which the encoding
+ CODING_SCHEME can be found. If we can't find CODING_SCHEME, return
+ DEFAULT_ENCODING. */
+
+string
+coding_scheme_to_filename (string coding_scheme)
+{
+ string mapping_line, enc_name;
+ string lc_coding_scheme = str_to_lower (coding_scheme);
+
+ libfile_start ("encoding", "map");
+
+ while ((mapping_line = libfile_line ()) != NULL)
+ {
+ string test_coding_scheme, lc_test_coding_scheme;
+
+ enc_name = strtok (mapping_line, " \t");
+ test_coding_scheme = strtok (NULL, "\t");
+ lc_test_coding_scheme = str_to_lower (test_coding_scheme);
+
+ if (STREQ (lc_coding_scheme, lc_test_coding_scheme))
+ break;
+
+ free (lc_test_coding_scheme);
+ free (mapping_line);
+ }
+
+ libfile_close ();
+
+ if (mapping_line == NULL)
+ {
+ WARNING3 ("%s: unknown encoding `%s'; using default `%s'",
+ "encoding.map", coding_scheme, DEFAULT_ENCODING);
+ enc_name = DEFAULT_ENCODING;
+ }
+
+ free (lc_coding_scheme);
+
+ return enc_name;
+}
+
+/* Parse the encoding file `FILENAME.enc' and return a structure
+ describing what we read. If the file doesn't exist, give a fatal
+ error. */
+
+encoding_info_type
+read_encoding_file (string filename)
+{
+ encoding_info_type info;
+ string line;
+ unsigned code;
+
+ /* Prepare to read from FILENAME. */
+ libfile_start (filename, "enc");
+
+ /* Start with an empty encoding. */
+ for (code = 0; code <= MAX_CHARCODE; code++)
+ ENCODING_CHAR_NAME (info, code) = NULL;
+
+ /* The entire first line is the TFM `CODINGSCHEME'. */
+ ENCODING_SCHEME_NAME (info) = libfile_line ();
+
+ /* Each remaining line defines one character. */
+ code = 0;
+ while ((line = libfile_line ()) != NULL)
+ {
+ ENCODING_CHAR_ELT (info, code) = parse_encoding_line (line);
+ code++;
+ free (line);
+ }
+
+ return info;
+}
+
+/* Parse one line of the encoding file; this specifies one character.
+ The BNF is:
+
+ <line> ::= <word> <ligatures>
+
+ <ligatures> ::= <ligature> [<ligature>]?
+ | <empty>
+
+ <ligature> ::= lig <charcode> =: <charcode>
+
+ Whitespace must be between all elements.
+
+ If the line is malformed, we give a fatal error. */
+
+#define WORD_SEPARATOR " \t"
+#define GET_WORD() strtok (NULL, WORD_SEPARATOR)
+
+static encoding_char_type
+parse_encoding_line (string line)
+{
+ encoding_char_type c;
+
+ c.name = xstrdup (strtok (line, WORD_SEPARATOR));
+ c.ligature = list_init ();
+
+ do
+ {
+ tfm_ligature_type *lig;
+ string t = GET_WORD ();
+
+ if (t == NULL) /* Do we have more ligature specs? */
+ break;
+
+ if (!STREQ (t, "lig"))
+ LIBFILE_ERROR1 ("Expected `lig', found `%s'", t);
+
+ lig = LIST_TAPPEND (&c.ligature, tfm_ligature_type);
+ *lig = parse_ligature ();
+ }
+ while (true);
+
+ return c;
+}
+
+
+/* Parse a single ligature: <charcode> =: <charcode>. */
+
+static tfm_ligature_type
+parse_ligature ()
+{
+ tfm_ligature_type lig;
+ boolean valid;
+ string t = GET_WORD ();
+
+ lig.character = parse_charcode (t, &valid);
+
+ if (!valid)
+ LIBFILE_ERROR1 ("Invalid right character code `%s'", t);
+
+ t = GET_WORD ();
+ if (!STREQ (t, "=:"))
+ LIBFILE_ERROR1 ("Expected `=:', found `%s'", t);
+
+ t = GET_WORD ();
+ lig.ligature = parse_charcode (t, &valid);
+ if (!valid)
+ LIBFILE_ERROR1 ("Invalid ligature character code `%s'", t);
+
+ return lig;
+}
diff --git a/lib/file-input.c b/lib/file-input.c
new file mode 100644
index 0000000..1bc138b
--- /dev/null
+++ b/lib/file-input.c
@@ -0,0 +1,158 @@
+/* file-input.c: file reading routines for binary files in BigEndian
+ order, 2's complement representation.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "file-input.h"
+
+
+one_byte
+get_byte (FILE *f, string filename)
+{
+ one_byte b;
+
+ if (fread (&b, 1, 1, f) != 1)
+ FATAL_PERROR (concat3 ("get_byte (", filename, ")"));
+
+ return b;
+}
+
+
+two_bytes
+get_two (FILE *f, string filename)
+{
+ two_bytes b;
+
+ b = get_byte (f, filename) << 8;
+ b |= get_byte (f, filename);
+
+ return b;
+}
+
+
+four_bytes
+get_four (FILE *f, string filename)
+{
+ four_bytes b;
+
+ b = get_byte (f, filename) << 24;
+ b |= get_byte (f, filename) << 16;
+ b |= get_byte (f, filename) << 8;
+ b |= get_byte (f, filename);
+
+ return b;
+}
+
+
+/* In order to get a signed value, we merely read an unsigned value and
+ cast it; the value in the file is assumed to be 2's complement. */
+
+signed_4_bytes
+get_signed_four (FILE *f, string filename)
+{
+ return (signed_4_bytes) get_four (f, filename);
+}
+
+
+/* Return the next N bytes in the file F as an array. */
+
+address
+get_n_bytes (unsigned n, FILE *f, string filename)
+{
+ one_byte *b;
+
+ if (n == 0)
+ FATAL1 ("get_n_bytes (%s): can't get zero bytes", filename);
+
+ b = xmalloc (n);
+
+ if (fread (b, n, 1, f) != 1)
+ FATAL2 ("get_n_bytes (%s): fread of %u bytes failed", filename, n);
+
+ return b;
+}
+
+
+
+/* Reading backwards. This macro is shared among all the routines by assuming
+ the name `f' for the file pointer. */
+
+#define MOVE_BACK(size) xfseek (f, (long) -size, SEEK_CUR, filename)
+
+one_byte
+get_previous_byte (FILE *f, string filename)
+{
+ one_byte b;
+
+ MOVE_BACK (1);
+ b = get_byte (f, filename);
+ MOVE_BACK (1);
+ return b;
+}
+
+
+two_bytes
+get_previous_two (FILE *f, string filename)
+{
+ two_bytes b;
+
+ MOVE_BACK (2);
+ b = get_two (f, filename);
+ MOVE_BACK (2);
+
+ return b;
+}
+
+
+
+four_bytes
+get_previous_four (FILE *f, string filename)
+{
+ four_bytes b;
+
+ MOVE_BACK (4);
+ b = get_four (f, filename);
+ MOVE_BACK (4);
+
+ return b;
+}
+
+
+
+/* Looking for specific values in the input. */
+
+void
+match_byte (one_byte expected, FILE *f, string filename)
+{
+ one_byte b = get_byte (f, filename);
+
+ if (b != expected)
+ FATAL3 ("%s: Expected byte value %u, found %u", filename, expected, b);
+}
+
+
+void
+match_previous_byte (one_byte expected, FILE *f, string filename)
+{
+ one_byte b = get_previous_byte (f, filename);
+
+ if (b != expected)
+ FATAL3 ("%s: Expected previous byte value %u, found %u", filename,
+ expected, b);
+}
diff --git a/lib/file-output.c b/lib/file-output.c
new file mode 100644
index 0000000..94559ec
--- /dev/null
+++ b/lib/file-output.c
@@ -0,0 +1,73 @@
+/* file-output.c: file writing routines for binary files in BigEndian
+ order, 2's complement representation.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "file-output.h"
+
+
+/* Output in BigEndian order. We could do these more efficiently by
+ checking if the hardware already uses BigEndian order, but it's not
+ worth it. These routines are never the bottleneck (in the ways
+ they've been used so far, anyway). We assume that we write negative
+ numbers in 2's complement, also. */
+
+void
+put_byte (one_byte b, FILE *f, string filename)
+{
+ if (fwrite (&b, 1, 1, f) != 1)
+ FATAL2 ("%s: Could not write byte %u", filename, b);
+}
+
+
+void
+put_two (two_bytes b, FILE *f, string filename)
+{
+ put_byte ((b & 0xff00) >> 8, f, filename); /* High-order byte. */
+ put_byte (b & 0x00ff, f, filename); /* And low-order. */
+}
+
+
+void
+put_three (four_bytes b, FILE *f, string filename)
+{
+ put_byte ((b & 0x00ff0000) >> 16, f, filename);
+ put_byte ((b & 0x0000ff00) >> 8, f, filename);
+ put_byte (b & 0x000000ff, f, filename);
+}
+
+
+void
+put_four (four_bytes b, FILE *f, string filename)
+{
+ put_byte ((b & 0xff000000) >> 24, f, filename);
+ put_byte ((b & 0x00ff0000) >> 16, f, filename);
+ put_byte ((b & 0x0000ff00) >> 8, f, filename);
+ put_byte (b & 0x000000ff, f, filename);
+}
+
+
+void
+put_n_bytes (unsigned n, address b, FILE *f, string filename)
+{
+ one_byte *data_b = b; /* We can't dereference a pure `address'. */
+
+ if (fwrite (data_b, n, 1, f) != 1)
+ FATAL2 ("%s: Could not write %u-byte block", filename, n);
+}
diff --git a/lib/filename.c b/lib/filename.c
new file mode 100644
index 0000000..b85d095
--- /dev/null
+++ b/lib/filename.c
@@ -0,0 +1,99 @@
+/* filename.c: routines to manipulate filenames.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+#include "paths.h"
+
+#include "filename.h"
+#include "pathsrch.h"
+
+
+/* Try to find the PK font FONT_NAME at resolution DPI, using various
+ paths (see `filename.h'). The filename must have the resolution as
+ part of the extension, e.g., `cmr10.300pk', for it to be found. */
+
+string
+find_pk_filename (string font_name, unsigned dpi)
+{
+ static string *dirs = NULL;
+ string pk_var, pk_name, name;
+ char suffix[MAX_INT_LENGTH + sizeof ".pk"];
+
+ sprintf (suffix, ".%dpk", dpi);
+
+ pk_var = getenv ("PKFONTS") ? "PKFONTS"
+ : getenv ("TEXPKS") ? "TEXPKS" : "TEXFONTS";
+
+ if (dirs == NULL)
+ dirs = initialize_path_list (pk_var, DEFAULT_PK_PATH);
+
+ name = concat (font_name, suffix);
+ pk_name = find_path_filename (name, dirs);
+
+ if (name != pk_name)
+ free (name);
+
+ return pk_name;
+}
+
+
+/* Like `find_pk_filename', but search for a font in GF format. */
+
+string
+find_gf_filename (string font_name, unsigned dpi)
+{
+ static string *dirs = NULL;
+ string gf_var, gf_name, name;
+ char suffix[MAX_INT_LENGTH + sizeof ".pk"];
+
+ sprintf (suffix, ".%dgf", dpi);
+
+ gf_var = getenv ("GFFONTS") ? "GFFONTS" : "TEXFONTS";
+
+ if (dirs == NULL)
+ dirs = initialize_path_list (gf_var, DEFAULT_GF_PATH);
+
+ name = concat (font_name, suffix);
+ gf_name = find_path_filename (name, dirs);
+
+ if (name != gf_name)
+ free (name);
+
+ return gf_name;
+}
+
+
+/* Like `find_pk_filename', except search for a TFM file. */
+
+string
+find_tfm_filename (string font_name)
+{
+ static string *dirs = NULL;
+ string tfm_name, name;
+
+ if (dirs == NULL)
+ dirs = initialize_path_list ("TEXFONTS", DEFAULT_TFM_PATH);
+
+ name = extend_filename (font_name, "tfm");
+ tfm_name = find_path_filename (name, dirs);
+
+ if (name != tfm_name)
+ free (name);
+
+ return tfm_name;
+}
diff --git a/lib/fix-num.c b/lib/fix-num.c
new file mode 100644
index 0000000..2827d2c
--- /dev/null
+++ b/lib/fix-num.c
@@ -0,0 +1,43 @@
+/* fix-num.c: conversions on ``fixnums'', which are a 32-bit
+ word with 20 bits of fraction.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "fix-num.h"
+
+
+#define FIX_UNITY (1 << 20)
+
+
+const real
+fix_to_real (fix_word f)
+{
+ real r = f / FIX_UNITY + ((real) (f % FIX_UNITY) / (real) FIX_UNITY);
+
+ return r;
+}
+
+
+const fix_word
+real_to_fix (real r)
+{
+ fix_word f = floor (r) * FIX_UNITY + (r - floor (r)) * FIX_UNITY;
+
+ return f;
+}
diff --git a/lib/float-ok.c b/lib/float-ok.c
new file mode 100644
index 0000000..b3e81d6
--- /dev/null
+++ b/lib/float-ok.c
@@ -0,0 +1,60 @@
+/* float-ok.c: test if a string is a valid floating-point number.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/c-ctype.h>
+
+
+/* Actually, we don't worry about a trailing exponent. */
+
+boolean
+float_ok (string str)
+{
+ boolean found_digit = false;
+
+ if (str == NULL)
+ return false;
+
+ /* Allow leading `-' or `+' sign (but digits must follow). */
+ if (*str == '-' || *str == '+')
+ {
+ str++;
+ }
+
+ /* Skip decimal digits. */
+ while (ISDIGIT (*str))
+ {
+ str++;
+ found_digit = true;
+ }
+
+ /* If a `.' follows, can have more digits. */
+ if (*str == '.')
+ {
+ str++;
+ while (ISDIGIT (*str))
+ {
+ str++;
+ found_digit = true;
+ }
+ }
+
+ return *str == 0 && found_digit;
+}
+
diff --git a/lib/fmod.c b/lib/fmod.c
new file mode 100644
index 0000000..0c78f52
--- /dev/null
+++ b/lib/fmod.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)fmod.c 5.2 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/* fmod.c
+ *
+ * SYNOPSIS
+ *
+ * #include <math.h>
+ * double fmod(double x, double y)
+ *
+ * DESCRIPTION
+ *
+ * The fmod function computes the floating-point remainder of x/y.
+ *
+ * RETURNS
+ *
+ * The fmod function returns the value x-i*y, for some integer i
+ * such that, if y is nonzero, the result has the same sign as x and
+ * magnitude less than the magnitude of y.
+ *
+ * On a VAX or CCI,
+ *
+ * fmod(x,0) traps/faults on floating-point divided-by-zero.
+ *
+ * On IEEE-754 conforming machines with "isnan()" primitive,
+ *
+ * fmod(x,0), fmod(INF,y) are invalid operations and NaN is returned.
+ *
+ */
+#include <math.h> /* changed from "mathimpl.h" --karl */
+
+#if !defined(vax) && !defined(tahoe)
+extern int isnan(),finite();
+#endif /* !defined(vax) && !defined(tahoe) */
+extern double frexp(),ldexp(),fabs();
+
+#ifdef TEST_FMOD
+static double
+_fmod(x,y)
+#else /* TEST_FMOD */
+double
+fmod(x,y)
+#endif /* TEST_FMOD */
+double x,y;
+{
+ int ir,iy;
+ double r,w;
+
+ if (y == (double)0
+#if 0 /* removed this --karl */
+#if !defined(vax) && !defined(tahoe) /* per "fmod" manual entry, SunOS 4.0 */
+ || isnan(y) || !finite(x)
+#endif /* !defined(vax) && !defined(tahoe) */
+#endif
+ )
+ return (x*y)/(x*y);
+
+ r = fabs(x);
+ y = fabs(y);
+ (void)frexp(y,&iy);
+ while (r >= y) {
+ (void)frexp(r,&ir);
+ w = ldexp(y,ir-iy);
+ r -= w <= r ? w : w*(double)0.5;
+ }
+ return x >= (double)0 ? r : -r;
+}
+
+#ifdef TEST_FMOD
+extern long random();
+extern double fmod();
+
+#define NTEST 10000
+#define NCASES 3
+
+static int nfail = 0;
+
+static void
+doit(x,y)
+double x,y;
+{
+ double ro = fmod(x,y),rn = _fmod(x,y);
+ if (ro != rn) {
+ (void)printf(" x = 0x%08.8x %08.8x (%24.16e)\n",x,x);
+ (void)printf(" y = 0x%08.8x %08.8x (%24.16e)\n",y,y);
+ (void)printf(" fmod = 0x%08.8x %08.8x (%24.16e)\n",ro,ro);
+ (void)printf("_fmod = 0x%08.8x %08.8x (%24.16e)\n",rn,rn);
+ (void)printf("\n");
+ }
+}
+
+main()
+{
+ register int i,cases;
+ double x,y;
+
+ srandom(12345);
+ for (i = 0; i < NTEST; i++) {
+ x = (double)random();
+ y = (double)random();
+ for (cases = 0; cases < NCASES; cases++) {
+ switch (cases) {
+ case 0:
+ break;
+ case 1:
+ y = (double)1/y; break;
+ case 2:
+ x = (double)1/x; break;
+ default:
+ abort(); break;
+ }
+ doit(x,y);
+ doit(x,-y);
+ doit(-x,y);
+ doit(-x,-y);
+ }
+ }
+ if (nfail)
+ (void)printf("Number of failures: %d (out of a total of %d)\n",
+ nfail,NTEST*NCASES*4);
+ else
+ (void)printf("No discrepancies were found\n");
+ exit(0);
+}
+#endif /* TEST_FMOD */
diff --git a/lib/font.c b/lib/font.c
new file mode 100644
index 0000000..e2b9a71
--- /dev/null
+++ b/lib/font.c
@@ -0,0 +1,466 @@
+/* font.c: define (more or less) format-independent font operations.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/tex-file.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/paths.h>
+#include <kpathsea/c-ctype.h>
+
+#include "filename.h"
+#include "font.h"
+#include "gf.h"
+#include "list.h"
+#include "pk.h"
+#include "tfm.h"
+
+
+/* We want to allow reading of multiple fonts, so we keep some
+ information around for each font we read. */
+
+typedef struct
+{
+ bitmap_format_type bitmap_format;
+ boolean bitmap_only;
+ font_info_type info;
+} internal_font_type;
+
+/* The format of the bitmap file for this font. */
+#define INTERNAL_BITMAP_FORMAT(i) ((i).bitmap_format)
+
+/* If the font was opened with `get_bitmap_font', this field is true;
+ if with `get_font', false. */
+#define INTERNAL_BITMAP_ONLY(i) ((i).bitmap_only)
+
+/* The filename for the bitmap font. */
+#define INTERNAL_BITMAP_NAME(i) ((i).bitmap_name)
+
+/* The fontwide information. The parts of this that are found in the
+ TFM file are garbage if INTERNAL_BITMAP_ONLY (I) is true. */
+#define INTERNAL_FONT_INFO(i) ((i).info)
+
+
+static void delete_internal_font (string filename);
+static internal_font_type *find_internal_font (string font_name);
+static void save_internal_font (string font_name, internal_font_type);
+
+/* Starting with FONT_NAME as the base filename, e.g., `cmr10', we try
+ various extensions to find a PK or GF file at resolution DPI. This
+ bitmap font defines the shapes of the characters. */
+
+bitmap_font_type
+get_bitmap_font (string font_name, unsigned dpi)
+{
+ bitmap_font_type font;
+ internal_font_type internal_f;
+ internal_font_type *internal_font_ptr;
+ string pk_name, gf_name;
+ boolean found_pk = false, found_gf = false;
+
+ /* If we are passed a null pointer or the empty string, it's got to be
+ a mistake. */
+ assert (font_name && *font_name);
+
+ /* If we already have the font saved, we just return it, thus (1) saving
+ going out to the file system, and (2) causing multiple calls with
+ the same FONT_NAME not to open more and more bitmap files. */
+ internal_font_ptr = find_internal_font (font_name);
+ if (internal_font_ptr != NULL)
+ return FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*internal_font_ptr));
+
+ pk_name = find_pk_filename (font_name, dpi);
+ if (pk_name != NULL)
+ { /* Found the PK file, so unless something strange is happening
+ (like the file being removed between the `find_path_filename'
+ call and the `pk_open_input_file' call), we will be able to
+ open it. */
+ found_pk = pk_open_input_file (pk_name);
+ if (!found_pk)
+ FATAL_PERROR (pk_name);
+ }
+ else if ((gf_name = find_gf_filename (font_name, dpi)) != NULL)
+ {
+ found_gf = gf_open_input_file (gf_name);
+ if (!found_gf)
+ {
+ perror (gf_name);
+ FATAL1 ("(I couldn't find the PK file `%s', either.)", pk_name);
+ }
+ }
+ else
+ FATAL2 ("%s.%d{gf,pk}: Nowhere in path", font_name, dpi);
+
+
+ /* We've opened the files; get the information we need to return. */
+ if (found_pk)
+ {
+ pk_preamble_type preamble = pk_get_preamble (pk_name);
+
+ BITMAP_FONT_DESIGN_SIZE (font)
+ = fix_to_real (PK_DESIGN_SIZE (preamble));
+ BITMAP_FONT_COMMENT (font) = PK_COMMENT (preamble);
+ BITMAP_FONT_CHECKSUM (font) = PK_CHECKSUM (preamble);
+ BITMAP_FONT_FILENAME (font) = pk_name;
+
+ INTERNAL_BITMAP_FORMAT (internal_f) = pk_format;
+ }
+ else if (found_gf)
+ {
+ gf_postamble_type postamble = gf_get_postamble ();
+
+ BITMAP_FONT_DESIGN_SIZE (font)
+ = fix_to_real (GF_DESIGN_SIZE (postamble));
+ BITMAP_FONT_COMMENT (font) = gf_get_preamble ();
+ BITMAP_FONT_CHECKSUM (font) = GF_CHECKSUM (postamble);
+ BITMAP_FONT_FILENAME (font) = gf_name;
+
+ INTERNAL_BITMAP_FORMAT (internal_f) = gf_format;
+ }
+ else
+ FATAL ("No bitmap file found, but I must have found one");
+
+ FONT_BITMAP_FONT (INTERNAL_FONT_INFO (internal_f)) = font;
+ INTERNAL_BITMAP_ONLY (internal_f) = true;
+
+ save_internal_font (font_name, internal_f);
+
+ return font;
+}
+
+
+/* Look for both a bitmap font named FONT_NAME, and for the TFM file
+ FONT_NAME.tfm. We call `get_bitmap_font' to find the bitmap font.
+ For the TFM file, we use the path in the environment variable
+ TEXFONTS; if TEXFONTS isn't set, we use the default defined above.
+
+ If FONT_NAME was previously opened with `get_bitmap_font', we give a
+ fatal error. */
+
+font_info_type
+get_font (string font_name, unsigned dpi)
+{
+ unsigned bitmap_checksum;
+ font_info_type font;
+ internal_font_type internal_f;
+ internal_font_type *internal_font_ptr;
+ unsigned tfm_checksum;
+ string tfm_name;
+
+ /* If we are passed a null pointer or the empty string, it's got to be
+ a mistake. */
+ assert (font_name != NULL && *font_name);
+
+ /* If we already have the font saved, we just return it, thus (1) saving
+ going out to the file system, and (2) causing multiple calls with
+ the same FONT_NAME not to open more and more bitmap files. */
+ internal_font_ptr = find_internal_font (font_name);
+ if (internal_font_ptr != NULL)
+ if (INTERNAL_BITMAP_ONLY (*internal_font_ptr))
+ FATAL1 ("get_font: `%s' was opened with get_bitmap_font", font_name);
+ else
+ return INTERNAL_FONT_INFO (*internal_font_ptr);
+
+ /* If we don't have the font saved, we have to look for the TFM file. */
+ tfm_name = kpse_find_tfm (font_name);
+
+ if (tfm_name == NULL)
+ FATAL1 ("%s.tfm: Nowhere in path", font_name);
+
+ if (!tfm_open_input_file (tfm_name))
+ FATAL_PERROR (tfm_name);
+
+
+ /* The TFM file is opened. Save some global information. */
+ FONT_TFM_FONT (font) = tfm_get_global_info ();
+ FONT_TFM_FILENAME (font) = tfm_name;
+
+ /* Read the (we hope) corresponding bitmap file. */
+ FONT_BITMAP_FONT (font) = get_bitmap_font (font_name, dpi);
+
+ /* We have found the bitmap font on the filesystem, so it should be in
+ our internal list now. We will overwrite it below. */
+ internal_font_ptr = find_internal_font (font_name);
+ assert (internal_font_ptr != NULL);
+
+ /* We've opened the files; now get the information we're supposed to
+ return. */
+
+ /* Let's check the checksums. */
+ tfm_checksum = tfm_get_checksum ();
+ bitmap_checksum = BITMAP_FONT_CHECKSUM (FONT_BITMAP_FONT (font));
+
+ if (tfm_checksum != 0 && bitmap_checksum != 0
+ && tfm_checksum != bitmap_checksum)
+ WARNING1 ("%s: TFM and bitmap checksums don't match", font_name);
+
+ INTERNAL_FONT_INFO (internal_f) = font;
+ INTERNAL_BITMAP_ONLY (internal_f) = false;
+ INTERNAL_BITMAP_FORMAT (internal_f)
+ = INTERNAL_BITMAP_FORMAT (*internal_font_ptr);
+ save_internal_font (font_name, internal_f);
+
+ return font;
+}
+
+/* Close the files we have opened, for tidiness. */
+
+void
+close_font (string font_name)
+{
+ internal_font_type *f = find_internal_font (font_name);
+
+ if (f == NULL)
+ FATAL1 ("close_font: Font `%s' not open", font_name);
+
+ switch (INTERNAL_BITMAP_FORMAT (*f))
+ {
+ case pk_format:
+ {
+ string pk_name
+ = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
+ pk_close_input_file (pk_name);
+ }
+ break;
+
+ case gf_format:
+ gf_close_input_file ();
+ break;
+
+ default:
+ FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
+ }
+
+ if (!INTERNAL_BITMAP_ONLY (*f))
+ tfm_close_input_file ();
+
+ delete_internal_font (font_name);
+}
+
+/* Look for the character numbered CODE in the font FONT_NAME. If it
+ doesn't exist, return NULL. Otherwise, fill in a `char_info_type'
+ structure and return a pointer to it.
+
+ This merely calls the get-a-character routine in the appropriate
+ library. */
+
+char_info_type *
+get_char (string font_name, one_byte code)
+{
+ char_info_type *c;
+ internal_font_type *f = find_internal_font (font_name);
+
+ if (f == NULL)
+ FATAL1 ("get_char: Font `%s' not open", font_name);
+
+ switch (INTERNAL_BITMAP_FORMAT (*f))
+ {
+ case pk_format:
+ {
+ string pk_name
+ = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
+ pk_char_type *pk_char = pk_get_char (code, pk_name);
+ if (pk_char == NULL) return NULL;
+
+ c = XTALLOC1 (char_info_type);
+ CHARCODE (*c) = PK_CHARCODE (*pk_char);
+ CHAR_SET_WIDTH (*c) = PK_H_ESCAPEMENT (*pk_char);
+ CHAR_TFM_WIDTH (*c) = PK_TFM_WIDTH (*pk_char);
+ CHAR_BB (*c) = PK_CHAR_BB (*pk_char);
+ CHAR_BITMAP (*c) = PK_BITMAP (*pk_char);
+ }
+ break;
+
+ case gf_format:
+ {
+ gf_char_type *gf_char = gf_get_char (code);
+ if (gf_char == NULL) return NULL;
+
+ c = XTALLOC1 (char_info_type);
+ CHARCODE (*c) = GF_CHARCODE (*gf_char);
+ CHAR_SET_WIDTH (*c) = GF_H_ESCAPEMENT (*gf_char);
+ CHAR_TFM_WIDTH (*c) = GF_TFM_WIDTH (*gf_char);
+ CHAR_BB (*c) = GF_CHAR_BB (*gf_char);
+ CHAR_BITMAP (*c) = GF_BITMAP (*gf_char);
+ }
+ break;
+
+ default:
+ FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
+ }
+
+ return c;
+}
+
+/* Look for the character numbered CODE in the font FONT_NAME. If it
+ doesn't exist, return NULL. Otherwise, fill in a `raw_char_type'
+ structure and return a pointer to it.
+
+ This merely calls the corresponding routine in the appropriate
+ library. */
+
+raw_char_type *
+get_raw_char (string font_name, one_byte code)
+{
+ raw_char_type *c;
+ internal_font_type *f = find_internal_font (font_name);
+
+ if (f == NULL)
+ FATAL1 ("get_raw_char: Font `%s' not open", font_name);
+
+ switch (INTERNAL_BITMAP_FORMAT (*f))
+ {
+ case pk_format:
+ c = NULL;
+ break;
+
+ case gf_format:
+ c = gf_get_raw_char (code);
+ break;
+
+ default:
+ FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
+ }
+
+ if (c != NULL)
+ RAW_CHAR_BITMAP_FORMAT (*c) = INTERNAL_BITMAP_FORMAT (*f);
+ return c;
+}
+
+
+/* Free the information in the raw character RAW_CHAR, including the
+ character itself. */
+
+void
+free_raw_char (raw_char_type *raw_char)
+{
+ free (RAW_CHAR_BYTES (*raw_char));
+ free (raw_char);
+}
+
+/* Print the character C to the file F, using ordinary characters. */
+
+void
+print_char (FILE *f, char_info_type c)
+{
+ unsigned this_row, this_col;
+ bitmap_type b = CHAR_BITMAP (c);
+
+ fprintf (f, "Character 0x%x=%u", CHARCODE (c), CHARCODE (c));
+ if (ISPRINT (CHARCODE (c)))
+ fprintf (f, " (%c)", CHARCODE (c));
+
+ fprintf (f, ":\n");
+
+ fprintf (f, " min/max col %d/%d, min/max row %d/%d, set width %d.\n",
+ CHAR_MIN_COL (c), CHAR_MAX_COL (c),
+ CHAR_MIN_ROW (c), CHAR_MAX_ROW (c), CHAR_SET_WIDTH (c));
+
+ /* We don't call `print_bitmap' because we want to print the Cartesian
+ row number, as well as the bitmap row number. */
+
+ for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++)
+ {
+ for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++)
+ putc (BITMAP_PIXEL (b, this_row, this_col) ? '*' : ' ', f);
+
+ fprintf (f, "%3d\t%u\n", CHAR_MAX_ROW (c) - this_row, this_row);
+ }
+}
+
+/* We want to implement a typical key/value setup: here we are given the
+ key (FONT_NAME) and the value (F). We assign an index number to
+ FONT_NAME, and store it and F in parallel lists. If we are passed a
+ FONT_NAME that is already in the list, we overwrite the old value. */
+
+static list_type font_name_list, internal_font_list;
+
+static void
+save_internal_font (string font_name, internal_font_type f)
+{
+ string *new_name;
+ internal_font_type *new_font;
+ static boolean first_call = true;
+
+ if (first_call)
+ { /* Have to construct our lists. */
+ font_name_list = list_init ();
+ internal_font_list = list_init ();
+ first_call = false;
+ }
+
+ new_font = find_internal_font (font_name);
+ if (new_font == NULL)
+ {
+ /* Add another pointer to the end of the lists. */
+ new_name = LIST_TAPPEND (&font_name_list, string);
+ new_font = LIST_TAPPEND (&internal_font_list, internal_font_type);
+
+ /* Save the information. */
+ *new_name = xstrdup (font_name);
+ }
+
+ /* Either update the existing font, or save the new one. */
+ *new_font = f;
+}
+
+
+/* This routine returns the font information previously stored with
+ FONT_NAME. If FONT_NAME hasn't been saved, we return NULL. */
+
+static internal_font_type *
+find_internal_font (string font_name)
+{
+ unsigned e;
+
+ for (e = 0; e < LIST_SIZE (font_name_list); e++)
+ if (STREQ (*(string *) LIST_ELT (font_name_list, e), font_name))
+ return (internal_font_type *) LIST_ELT (internal_font_list, e);
+
+ return NULL;
+}
+
+
+/* Remove FILENAME from `font_name_list', by setting the name in
+ `font_name_list' to the empty string, so that the element is useless.
+ (We don't have any actual memory to free.) What a kludge. */
+
+static void
+delete_internal_font (string filename)
+{
+ unsigned e;
+
+ /* We can't use `find_internal_font', since we need to know the list
+ element index, not just the internal font information. */
+ for (e = 0; e < LIST_SIZE (font_name_list); e++)
+ if (STREQ (*(string *) LIST_ELT (font_name_list, e), filename))
+ {
+ string *name = LIST_ELT (font_name_list, e);
+ internal_font_type *i
+ = (internal_font_type *) LIST_ELT (internal_font_list, e);
+
+ free (*name);
+ *name = "";
+
+ free (i);
+
+ return;
+ }
+
+ FATAL1 ("The font `%s' hasn't been saved", filename);
+}
diff --git a/lib/fontmap.c b/lib/fontmap.c
new file mode 100644
index 0000000..2b4f0b7
--- /dev/null
+++ b/lib/fontmap.c
@@ -0,0 +1,210 @@
+/* fontmap.c: read a file for additional font names.
+
+Copyright (C) 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "c-pathmx.h"
+#include "fontmap.h"
+
+
+
+/* Fontname mapping. We use a straightforward hash table. */
+
+#define MAP_SIZE 199
+
+
+/* The hash function. We go for simplicity here. */
+
+static unsigned
+map_hash (key)
+ char *key;
+{
+ unsigned n = 0;
+
+ /* There are very few font names which are anagrams of each other (I
+ think), so no point in weighting the characters. */
+ while (*key != 0)
+ n += *key++;
+
+ n %= MAP_SIZE;
+
+ return n;
+}
+
+/* Look up STR in MAP. Return the corresponding `value' or NULL. */
+
+static char *
+map_lookup_str (map, key)
+ map_type map;
+ char *key;
+{
+ map_element_type *p;
+ unsigned n = map_hash (key);
+
+ for (p = map[n]; p != NULL; p = p->next)
+ if (STREQ (key, p->key))
+ return p->value;
+
+ return NULL;
+}
+
+
+/* Look up KEY in MAP; if it's not found, remove any suffix from KEY and
+ try again. */
+
+char *
+map_lookup (map, key)
+ map_type map;
+ char *key;
+{
+ extern string extend_filename ();
+ string suffix = find_suffix (key);
+ string ret = map_lookup_str (map, key);
+
+ if (!ret)
+ {
+ /* OK, the original KEY didn't work. Let's check for the KEY without
+ an extension -- perhaps they gave foobar.tfm, but the mapping only
+ defines `foobar'. */
+ if (suffix)
+ {
+ string base_key = remove_suffix (key);
+
+ ret = map_lookup_str (map, base_key);
+
+ free (base_key);
+ }
+ }
+
+ /* Append the same suffix we took off, if necessary. */
+ if (ret && suffix)
+ ret = extend_filename (ret, suffix);
+
+ return ret;
+}
+
+/* If KEY is not already in MAP, insert it and VALUE. */
+
+static void
+map_insert (map, key, value)
+ map_type map;
+ char *key;
+ char *value;
+{
+ unsigned n = map_hash (key);
+ map_element_type **p = &map[n];
+ map_element_type ***trailer = &p;
+
+ while (*p != NULL && !STREQ (key, (*p)->key))
+ {
+ *p = (*p)->next;
+ trailer = &p;
+ }
+
+ if (*p == NULL)
+ {
+ **trailer = XTALLOC (MAP_SIZE, map_element_type);
+ (**trailer)->key = xstrdup (key);
+ (**trailer)->value = xstrdup (value);
+ (**trailer)->next = NULL;
+ }
+}
+
+/* Open and read the mapping file FILENAME, putting its entries into
+ MAP. Comments begin with % and continue to the end of the line. Each
+ line of the file defines an entry: the first word is the real
+ filename (e.g., `ptmr'), the second word is the alias (e.g.,
+ `Times-Roman'), and any subsequent words are ignored. .tfm is added
+ if either the filename or the alias have no extension. This is the
+ same order as in Dvips' psfonts.map; unfortunately, we can't have TeX
+ read that same file, since most of the real filenames start with an
+ `r', because of the virtual fonts Dvips uses. */
+
+static void
+map_file_parse (map, map_filename)
+ map_type map;
+ char *map_filename;
+{
+ extern FILE *xfopen (); /* In xfopen.c. */
+ extern char *read_line (); /* In line.c. */
+ char *l;
+ unsigned map_lineno = 0;
+ FILE *f = xfopen (map_filename, FOPEN_R_MODE);
+
+ while ((l = read_line (f)) != NULL)
+ {
+ string filename;
+ string comment_loc = strrchr (l, '%');
+
+ map_lineno++;
+
+ /* Ignore anything after a %. */
+ if (comment_loc)
+ *comment_loc = 0;
+
+ /* If we don't have any filename, that's ok, the line is blank. */
+ filename = strtok (l, " \t");
+ if (filename)
+ {
+ string alias = strtok (NULL, " \t");
+
+ /* But if we have a filename and no alias, something's wrong. */
+ if (alias == NULL || *alias == 0)
+ fprintf (stderr, "%s:%u: Alias missing for filename `%s'.\n",
+ map_filename, map_lineno, filename);
+ else
+ {
+ /* We've got everything. Insert the new entry. */
+ map_insert (map, alias, filename);
+ }
+ }
+
+ free (l);
+ }
+
+ xfclose (f, map_filename);
+}
+
+
+/* Look for the file `texfonts.map' in each of the directories in
+ DIR_LIST. Entries in earlier files override later files. */
+
+map_type
+map_create (dir_list)
+ string *dir_list;
+{
+ map_type map = (map_type) xcalloc (MAP_SIZE, sizeof (map_element_type *));
+
+ while (*dir_list)
+ {
+ char filename[PATH_MAX];
+
+ /* We don't bother with the filename truncation that `readable' in
+ `pathsrch.c' does, since we ourselves are giving the filename,
+ and I don't think it's worth worrying about too-long
+ intermediate directory names in the path. */
+ strcpy (filename, *dir_list);
+ strcat (filename, "texfonts.map");
+
+ if (access (filename, R_OK) == 0)
+ map_file_parse (map, filename);
+
+ dir_list++;
+ }
+ return map;
+}
diff --git a/lib/gmalloc.c b/lib/gmalloc.c
new file mode 100644
index 0000000..bf4c70f
--- /dev/null
+++ b/lib/gmalloc.c
@@ -0,0 +1,1172 @@
+/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */
+
+#define _MALLOC_INTERNAL
+
+/* The malloc headers and source files from the C library follow here. */
+
+/* Declarations for `malloc' and friends.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H 1
+
+#ifdef _MALLOC_INTERNAL
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#ifndef memset
+#define memset(s, zero, n) bzero ((s), (n))
+#endif
+#ifndef memcpy
+#define memcpy(d, s, n) bcopy ((s), (d), (n))
+#endif
+#ifndef memmove
+#define memmove(d, s, n) bcopy ((s), (d), (n))
+#endif
+#endif
+
+#if defined(__GNU_LIBRARY__) || defined(__STDC__)
+#include <limits.h>
+#else
+#define CHAR_BIT 8
+#endif
+
+#endif /* _MALLOC_INTERNAL. */
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define __P(args) args
+#undef __ptr_t
+#define __ptr_t void *
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __P(args) ()
+#undef const
+#define const
+#undef __ptr_t
+#define __ptr_t char *
+#endif /* C++ or ANSI C. */
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+#undef size_t
+#define size_t unsigned int
+#undef ptrdiff_t
+#define ptrdiff_t int
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+
+/* Allocate SIZE bytes of memory. */
+extern __ptr_t malloc __P ((size_t __size));
+/* Re-allocate the previously allocated block
+ in __ptr_t, making the new block SIZE bytes long. */
+extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
+/* Free a block allocated by `malloc', `realloc' or `calloc'. */
+extern void free __P ((__ptr_t __ptr));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */
+extern __ptr_t memalign __P ((size_t __alignment, size_t __size));
+
+/* Allocate SIZE bytes on a page boundary. */
+extern __ptr_t valloc __P ((size_t __size));
+
+
+#ifdef _MALLOC_INTERNAL
+
+/* The allocator divides the heap into blocks of fixed size; large
+ requests receive one or more whole blocks, and small requests
+ receive a fragment of a block. Fragment sizes are powers of two,
+ and all fragments of a block are the same size. When all the
+ fragments in a block have been freed, the block itself is freed. */
+#define INT_BIT (CHAR_BIT * sizeof(int))
+#define BLOCKLOG (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE (1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+ (not an absolute limit). */
+#define HEAP (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+ memory before they will be returned to the system. */
+#define FINAL_FREE_BLOCKS 8
+
+/* Data structure giving per-block information. */
+typedef union
+ {
+ /* Heap information for a busy block. */
+ struct
+ {
+ /* Zero for a large block, or positive giving the
+ logarithm to the base two of the fragment size. */
+ int type;
+ union
+ {
+ struct
+ {
+ size_t nfree; /* Free fragments in a fragmented block. */
+ size_t first; /* First free fragment of the block. */
+ } frag;
+ /* Size (in blocks) of a large cluster. */
+ size_t size;
+ } info;
+ } busy;
+ /* Heap information for a free block
+ (that may be the first of a free cluster). */
+ struct
+ {
+ size_t size; /* Size (in blocks) of a free cluster. */
+ size_t next; /* Index of next free cluster. */
+ size_t prev; /* Index of previous free cluster. */
+ } free;
+ } malloc_info;
+
+/* Pointer to first block of the heap. */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information. */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa. */
+#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table. */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices. */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments. */
+struct list
+ {
+ struct list *next;
+ struct list *prev;
+ };
+
+/* Free list headers for each fragment size. */
+extern struct list _fraghead[];
+
+/* List of blocks allocated with `memalign' (or `valloc'). */
+struct alignlist
+ {
+ struct alignlist *next;
+ __ptr_t aligned; /* The address that memaligned returned. */
+ __ptr_t exact; /* The address that malloc returned. */
+ };
+extern struct alignlist *_aligned_blocks;
+
+/* Instrumentation. */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of `free' used in `morecore' (malloc.c). */
+extern void _free_internal __P ((__ptr_t __ptr));
+
+#endif /* _MALLOC_INTERNAL. */
+
+/* Underlying allocation function; successive calls should
+ return contiguous pieces of memory. */
+extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
+
+/* Default value of `__morecore'. */
+extern __ptr_t __default_morecore __P ((ptrdiff_t __size));
+
+/* If not NULL, this function is called after each time
+ `__morecore' is called to increase the data size. */
+extern void (*__after_morecore_hook) __P ((void));
+
+/* Nonzero if `malloc' has been called and done its initialization. */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions. */
+extern void (*__free_hook) __P ((__ptr_t __ptr));
+extern __ptr_t (*__malloc_hook) __P ((size_t __size));
+extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Activate a standard collection of debugging hooks. */
+extern int mcheck __P ((void (*__func) __P ((void))));
+
+/* Activate a standard collection of tracing hooks. */
+extern void mtrace __P ((void));
+
+/* Statistics available to the user. */
+struct mstats
+ {
+ size_t bytes_total; /* Total size of the heap. */
+ size_t chunks_used; /* Chunks allocated by the user. */
+ size_t bytes_used; /* Byte total of user-allocated chunks. */
+ size_t chunks_free; /* Chunks in the free list. */
+ size_t bytes_free; /* Byte total of chunks in the free list. */
+ };
+
+/* Pick up the current statistics. */
+extern struct mstats mstats __P ((void));
+
+/* Call WARNFUN with a warning message when memory usage is high. */
+extern void memory_warnings __P ((__ptr_t __start,
+ void (*__warnfun) __P ((__const char *))));
+
+
+/* Relocating allocator. */
+
+/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */
+extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+/* Free the storage allocated in HANDLEPTR. */
+extern void r_alloc_free __P ((__ptr_t *__handleptr));
+
+/* Adjust the block at HANDLEPTR to be SIZE bytes long. */
+extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* malloc.h */
+/* Memory allocator `malloc'.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* How to really get more memory. */
+__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'. */
+__ptr_t (*__malloc_hook) __P ((size_t __size));
+
+/* Pointer to the base of the first block. */
+char *_heapbase;
+
+/* Block information table. Allocated with align/__free (not malloc/free). */
+malloc_info *_heapinfo;
+
+/* Number of info entries. */
+static size_t heapsize;
+
+/* Search index in the info table. */
+size_t _heapindex;
+
+/* Limit of valid info table indices. */
+size_t _heaplimit;
+
+/* Free lists for each fragment size. */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation. */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced? */
+int __malloc_initialized;
+
+void (*__after_morecore_hook) __P ((void));
+
+/* Aligned allocation. */
+static __ptr_t align __P ((size_t));
+static __ptr_t
+align (size)
+ size_t size;
+{
+ __ptr_t result;
+ unsigned long int adj;
+
+ result = (*__morecore) (size);
+ adj = (unsigned long int) ((unsigned long int) ((char *) result -
+ (char *) NULL)) % BLOCKSIZE;
+ if (adj != 0)
+ {
+ adj = BLOCKSIZE - adj;
+ (void) (*__morecore) (adj);
+ result = (char *) result + adj;
+ }
+
+ if (__after_morecore_hook)
+ (*__after_morecore_hook) ();
+
+ return result;
+}
+
+/* Set everything up and remember that we have. */
+static int initialize __P ((void));
+static int
+initialize ()
+{
+ heapsize = HEAP / BLOCKSIZE;
+ _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
+ if (_heapinfo == NULL)
+ return 0;
+ memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
+ _heapinfo[0].free.size = 0;
+ _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+ _heapindex = 0;
+ _heapbase = (char *) _heapinfo;
+ __malloc_initialized = 1;
+ return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+ growing the heap info table as necessary. */
+static __ptr_t morecore __P ((size_t));
+static __ptr_t
+morecore (size)
+ size_t size;
+{
+ __ptr_t result;
+ malloc_info *newinfo, *oldinfo;
+ size_t newsize;
+
+ result = align (size);
+ if (result == NULL)
+ return NULL;
+
+ /* Check if we need to grow the info table. */
+ if ((size_t) BLOCK ((char *) result + size) > heapsize)
+ {
+ newsize = heapsize;
+ while ((size_t) BLOCK ((char *) result + size) > newsize)
+ newsize *= 2;
+ newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
+ if (newinfo == NULL)
+ {
+ (*__morecore) (-size);
+ return NULL;
+ }
+ memset (newinfo, 0, newsize * sizeof (malloc_info));
+ memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
+ oldinfo = _heapinfo;
+ newinfo[BLOCK (oldinfo)].busy.type = 0;
+ newinfo[BLOCK (oldinfo)].busy.info.size
+ = BLOCKIFY (heapsize * sizeof (malloc_info));
+ _heapinfo = newinfo;
+ _free_internal (oldinfo);
+ heapsize = newsize;
+ }
+
+ _heaplimit = BLOCK ((char *) result + size);
+ return result;
+}
+
+/* Allocate memory from the heap. */
+__ptr_t
+malloc (size)
+ size_t size;
+{
+ __ptr_t result;
+ size_t block, blocks, lastblocks, start;
+ register size_t i;
+ struct list *next;
+
+ /* ANSI C allows `malloc (0)' to either return NULL, or to return a
+ valid address you can realloc and free (though not dereference).
+
+ It turns out that some extant code (sunrpc, at least Ultrix's version)
+ expects `malloc (0)' to return non-NULL and breaks otherwise.
+ Be compatible. */
+
+#if 0
+ if (size == 0)
+ return NULL;
+#endif
+
+ if (__malloc_hook != NULL)
+ return (*__malloc_hook) (size);
+
+ if (!__malloc_initialized)
+ if (!initialize ())
+ return NULL;
+
+ if (size < sizeof (struct list))
+ size = sizeof (struct list);
+
+ /* Determine the allocation policy based on the request size. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ /* Small allocation to receive a fragment of a block.
+ Determine the logarithm to base two of the fragment size. */
+ register size_t log = 1;
+ --size;
+ while ((size /= 2) != 0)
+ ++log;
+
+ /* Look in the fragment lists for a
+ free fragment of the desired size. */
+ next = _fraghead[log].next;
+ if (next != NULL)
+ {
+ /* There are free fragments of this size.
+ Pop a fragment out of the fragment list and return it.
+ Update the block's nfree and first counters. */
+ result = (__ptr_t) next;
+ next->prev->next = next->next;
+ if (next->next != NULL)
+ next->next->prev = next->prev;
+ block = BLOCK (result);
+ if (--_heapinfo[block].busy.info.frag.nfree != 0)
+ _heapinfo[block].busy.info.frag.first = (unsigned long int)
+ ((unsigned long int) ((char *) next->next - (char *) NULL)
+ % BLOCKSIZE) >> log;
+
+ /* Update the statistics. */
+ ++_chunks_used;
+ _bytes_used += 1 << log;
+ --_chunks_free;
+ _bytes_free -= 1 << log;
+ }
+ else
+ {
+ /* No free fragments of the desired size, so get a new block
+ and break it into fragments, returning the first. */
+ result = malloc (BLOCKSIZE);
+ if (result == NULL)
+ return NULL;
+
+ /* Link all fragments but the first into the free list. */
+ for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+ {
+ next = (struct list *) ((char *) result + (i << log));
+ next->next = _fraghead[log].next;
+ next->prev = &_fraghead[log];
+ next->prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ }
+
+ /* Initialize the nfree and first counters for this block. */
+ block = BLOCK (result);
+ _heapinfo[block].busy.type = log;
+ _heapinfo[block].busy.info.frag.nfree = i - 1;
+ _heapinfo[block].busy.info.frag.first = i - 1;
+
+ _chunks_free += (BLOCKSIZE >> log) - 1;
+ _bytes_free += BLOCKSIZE - (1 << log);
+ _bytes_used -= BLOCKSIZE - (1 << log);
+ }
+ }
+ else
+ {
+ /* Large allocation to receive one or more blocks.
+ Search the free list in a circle starting at the last place visited.
+ If we loop completely around without finding a large enough
+ space we will have to get more memory from the system. */
+ blocks = BLOCKIFY (size);
+ start = block = _heapindex;
+ while (_heapinfo[block].free.size < blocks)
+ {
+ block = _heapinfo[block].free.next;
+ if (block == start)
+ {
+ /* Need to get more from the system. Check to see if
+ the new core will be contiguous with the final free
+ block; if so we don't need to get as much. */
+ block = _heapinfo[0].free.prev;
+ lastblocks = _heapinfo[block].free.size;
+ if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+ (*__morecore) (0) == ADDRESS (block + lastblocks) &&
+ (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+ {
+ _heapinfo[block].free.size = blocks;
+ _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+ continue;
+ }
+ result = morecore (blocks * BLOCKSIZE);
+ if (result == NULL)
+ return NULL;
+ block = BLOCK (result);
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = blocks;
+ ++_chunks_used;
+ _bytes_used += blocks * BLOCKSIZE;
+ return result;
+ }
+ }
+
+ /* At this point we have found a suitable free list entry.
+ Figure out how to remove what we need from the list. */
+ result = ADDRESS (block);
+ if (_heapinfo[block].free.size > blocks)
+ {
+ /* The block we found has a bit left over,
+ so relink the tail end back into the free list. */
+ _heapinfo[block + blocks].free.size
+ = _heapinfo[block].free.size - blocks;
+ _heapinfo[block + blocks].free.next
+ = _heapinfo[block].free.next;
+ _heapinfo[block + blocks].free.prev
+ = _heapinfo[block].free.prev;
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapindex = block + blocks;
+ }
+ else
+ {
+ /* The block exactly matches our requirements,
+ so just remove it from the list. */
+ _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapinfo[block].free.prev;
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapindex = _heapinfo[block].free.next;
+ --_chunks_free;
+ }
+
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = blocks;
+ ++_chunks_used;
+ _bytes_used += blocks * BLOCKSIZE;
+ _bytes_free -= blocks * BLOCKSIZE;
+ }
+
+ return result;
+}
+/* Free a block of memory allocated by `malloc'.
+ Copyright 1990, 1991, 1992 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Debugging hook for free. */
+void (*__free_hook) __P ((__ptr_t __ptr));
+
+/* List of blocks allocated by memalign. */
+struct alignlist *_aligned_blocks = NULL;
+
+/* Return memory to the heap.
+ Like `free' but don't call a __free_hook if there is one. */
+void
+_free_internal (ptr)
+ __ptr_t ptr;
+{
+ int type;
+ size_t block, blocks;
+ register size_t i;
+ struct list *prev, *next;
+
+ block = BLOCK (ptr);
+
+ type = _heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Get as many statistics as early as we can. */
+ --_chunks_used;
+ _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+ _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+ /* Find the free cluster previous to this one in the free list.
+ Start searching at the last block referenced; this may benefit
+ programs with locality of allocation. */
+ i = _heapindex;
+ if (i > block)
+ while (i > block)
+ i = _heapinfo[i].free.prev;
+ else
+ {
+ do
+ i = _heapinfo[i].free.next;
+ while (i > 0 && i < block);
+ i = _heapinfo[i].free.prev;
+ }
+
+ /* Determine how to link this block into the free list. */
+ if (block == i + _heapinfo[i].free.size)
+ {
+ /* Coalesce this block with its predecessor. */
+ _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+ block = i;
+ }
+ else
+ {
+ /* Really link this block back into the free list. */
+ _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+ _heapinfo[block].free.next = _heapinfo[i].free.next;
+ _heapinfo[block].free.prev = i;
+ _heapinfo[i].free.next = block;
+ _heapinfo[_heapinfo[block].free.next].free.prev = block;
+ ++_chunks_free;
+ }
+
+ /* Now that the block is linked in, see if we can coalesce it
+ with its successor (by deleting its successor from the list
+ and adding in its size). */
+ if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+ {
+ _heapinfo[block].free.size
+ += _heapinfo[_heapinfo[block].free.next].free.size;
+ _heapinfo[block].free.next
+ = _heapinfo[_heapinfo[block].free.next].free.next;
+ _heapinfo[_heapinfo[block].free.next].free.prev = block;
+ --_chunks_free;
+ }
+
+ /* Now see if we can return stuff to the system. */
+ blocks = _heapinfo[block].free.size;
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+ && (*__morecore) (0) == ADDRESS (block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ _heaplimit -= blocks;
+ (*__morecore) (-bytes);
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapinfo[block].free.next;
+ _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapinfo[block].free.prev;
+ block = _heapinfo[block].free.prev;
+ --_chunks_free;
+ _bytes_free -= bytes;
+ }
+
+ /* Set the next search to begin at this block. */
+ _heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ --_chunks_used;
+ _bytes_used -= 1 << type;
+ ++_chunks_free;
+ _bytes_free += 1 << type;
+
+ /* Get the address of the first free fragment in this block. */
+ prev = (struct list *) ((char *) ADDRESS (block) +
+ (_heapinfo[block].busy.info.frag.first << type));
+
+ if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+ {
+ /* If all fragments of this block are free, remove them
+ from the fragment list and free the whole block. */
+ next = prev;
+ for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+ next = next->next;
+ prev->prev->next = next;
+ if (next != NULL)
+ next->prev = prev->prev;
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = 1;
+
+ /* Keep the statistics accurate. */
+ ++_chunks_used;
+ _bytes_used += BLOCKSIZE;
+ _chunks_free -= BLOCKSIZE >> type;
+ _bytes_free -= BLOCKSIZE;
+
+ free (ADDRESS (block));
+ }
+ else if (_heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ /* If some fragments of this block are free, link this
+ fragment into the fragment list after the first free
+ fragment of this block. */
+ next = (struct list *) ptr;
+ next->next = prev->next;
+ next->prev = prev;
+ prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ ++_heapinfo[block].busy.info.frag.nfree;
+ }
+ else
+ {
+ /* No fragments of this block are free, so link this
+ fragment into the fragment list and announce that
+ it is the first free fragment of this block. */
+ prev = (struct list *) ptr;
+ _heapinfo[block].busy.info.frag.nfree = 1;
+ _heapinfo[block].busy.info.frag.first = (unsigned long int)
+ ((unsigned long int) ((char *) ptr - (char *) NULL)
+ % BLOCKSIZE >> type);
+ prev->next = _fraghead[type].next;
+ prev->prev = &_fraghead[type];
+ prev->prev->next = prev;
+ if (prev->next != NULL)
+ prev->next->prev = prev;
+ }
+ break;
+ }
+}
+
+/* Return memory to the heap. */
+void
+free (ptr)
+ __ptr_t ptr;
+{
+ register struct alignlist *l;
+
+ if (ptr == NULL)
+ return;
+
+ for (l = _aligned_blocks; l != NULL; l = l->next)
+ if (l->aligned == ptr)
+ {
+ l->aligned = NULL; /* Mark the slot in the list as free. */
+ ptr = l->exact;
+ break;
+ }
+
+ if (__free_hook != NULL)
+ (*__free_hook) (ptr);
+ else
+ _free_internal (ptr);
+}
+/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#undef cfree
+
+#ifdef _LIBC
+
+#include <ansidecl.h>
+#include <gnu-stabs.h>
+
+function_alias(cfree, free, void, (ptr),
+ DEFUN(cfree, (ptr), PTR ptr))
+
+#else
+
+void
+cfree (ptr)
+ __ptr_t ptr;
+{
+ free (ptr);
+}
+
+#endif
+/* Change the size of a block allocated by `malloc'.
+ Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc. */
+__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+ to the (possibly moved) region. This is optimized for speed;
+ some benchmarks seem to indicate that greater compactness is
+ achieved by unconditionally allocating and copying to a
+ new region. This module has incestuous knowledge of the
+ internals of both free and malloc. */
+__ptr_t
+realloc (ptr, size)
+ __ptr_t ptr;
+ size_t size;
+{
+ __ptr_t result;
+ int type;
+ size_t block, blocks, oldlimit;
+
+ if (size == 0)
+ {
+ free (ptr);
+ return malloc (0);
+ }
+ else if (ptr == NULL)
+ return malloc (size);
+
+ if (__realloc_hook != NULL)
+ return (*__realloc_hook) (ptr, size);
+
+ block = BLOCK (ptr);
+
+ type = _heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Maybe reallocate a large block to a small fragment. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ result = malloc (size);
+ if (result != NULL)
+ {
+ memcpy (result, ptr, size);
+ free (ptr);
+ return result;
+ }
+ }
+
+ /* The new size is a large allocation as well;
+ see if we can hold it in place. */
+ blocks = BLOCKIFY (size);
+ if (blocks < _heapinfo[block].busy.info.size)
+ {
+ /* The new size is smaller; return
+ excess memory to the free list. */
+ _heapinfo[block + blocks].busy.type = 0;
+ _heapinfo[block + blocks].busy.info.size
+ = _heapinfo[block].busy.info.size - blocks;
+ _heapinfo[block].busy.info.size = blocks;
+ free (ADDRESS (block + blocks));
+ result = ptr;
+ }
+ else if (blocks == _heapinfo[block].busy.info.size)
+ /* No size change necessary. */
+ result = ptr;
+ else
+ {
+ /* Won't fit, so allocate a new region that will.
+ Free the old region first in case there is sufficient
+ adjacent free space to grow without moving. */
+ blocks = _heapinfo[block].busy.info.size;
+ /* Prevent free from actually returning memory to the system. */
+ oldlimit = _heaplimit;
+ _heaplimit = 0;
+ free (ptr);
+ _heaplimit = oldlimit;
+ result = malloc (size);
+ if (result == NULL)
+ {
+ /* Now we're really in trouble. We have to unfree
+ the thing we just freed. Unfortunately it might
+ have been coalesced with its neighbors. */
+ if (_heapindex == block)
+ (void) malloc (blocks * BLOCKSIZE);
+ else
+ {
+ __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
+ (void) malloc (blocks * BLOCKSIZE);
+ free (previous);
+ }
+ return NULL;
+ }
+ if (ptr != result)
+ memmove (result, ptr, blocks * BLOCKSIZE);
+ }
+ break;
+
+ default:
+ /* Old size is a fragment; type is logarithm
+ to base two of the fragment size. */
+ if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+ /* The new size is the same kind of fragment. */
+ result = ptr;
+ else
+ {
+ /* The new size is different; allocate a new space,
+ and copy the lesser of the new size and the old. */
+ result = malloc (size);
+ if (result == NULL)
+ return NULL;
+ memcpy (result, ptr, min (size, (size_t) 1 << type));
+ free (ptr);
+ }
+ break;
+ }
+
+ return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+ The entire array is initialized to zeros. */
+__ptr_t
+calloc (nmemb, size)
+ register size_t nmemb;
+ register size_t size;
+{
+ register __ptr_t result = malloc (nmemb * size);
+
+ if (result != NULL)
+ (void) memset (result, 0, nmemb * size);
+
+ return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifndef __GNU_LIBRARY__
+#define __sbrk sbrk
+#endif
+
+extern __ptr_t __sbrk __P ((int increment));
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Allocate INCREMENT more bytes of data space,
+ and return the start of data space, or NULL on errors.
+ If INCREMENT is negative, shrink data space. */
+__ptr_t
+__default_morecore (increment)
+ ptrdiff_t increment;
+{
+ __ptr_t result = __sbrk ((int) increment);
+ if (result == (__ptr_t) -1)
+ return NULL;
+ return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+__ptr_t
+memalign (alignment, size)
+ size_t alignment;
+ size_t size;
+{
+ __ptr_t result;
+ unsigned long int adj;
+
+ size = ((size + alignment - 1) / alignment) * alignment;
+
+ result = malloc (size);
+ if (result == NULL)
+ return NULL;
+ adj = (unsigned long int) ((unsigned long int) ((char *) result -
+ (char *) NULL)) % alignment;
+ if (adj != 0)
+ {
+ struct alignlist *l;
+ for (l = _aligned_blocks; l != NULL; l = l->next)
+ if (l->aligned == NULL)
+ /* This slot is free. Use it. */
+ break;
+ if (l == NULL)
+ {
+ l = (struct alignlist *) malloc (sizeof (struct alignlist));
+ if (l == NULL)
+ {
+ free (result);
+ return NULL;
+ }
+ }
+ l->exact = result;
+ result = l->aligned = (char *) result + alignment - adj;
+ l->next = _aligned_blocks;
+ _aligned_blocks = l;
+ }
+
+ return result;
+}
+/* Allocate memory on a page boundary.
+ Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifdef __GNU_LIBRARY__
+extern size_t __getpagesize __P ((void));
+#else
+#include "getpagesize.h"
+#define __getpagesize() getpagesize()
+#endif
+
+static size_t pagesize;
+
+__ptr_t
+valloc (size)
+ size_t size;
+{
+ if (pagesize == 0)
+ pagesize = __getpagesize ();
+
+ return memalign (pagesize, size);
+}
diff --git a/lib/hexify.c b/lib/hexify.c
new file mode 100644
index 0000000..e3941b2
--- /dev/null
+++ b/lib/hexify.c
@@ -0,0 +1,46 @@
+/* hexify.c: change a binary string to ASCII hex characters.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "hexify.h"
+
+
+/* Convert the number N (assumed to be small enough) to a lowercase hex
+ character. */
+#define HEX_DIGIT(n) ((n) < 10 ? (n) + '0' : (n) - 10 + 'a')
+
+string
+hexify (one_byte *data, unsigned length)
+{
+ unsigned i;
+ /* Each byte in S turns into two hex chars, plus the terminating null. */
+ string h = xmalloc (length * 2 + 1);
+
+ for (i = 0; i < length; i++)
+ {
+ unsigned char n = (data[i] & 0xf0) >> 4;
+ h[i * 2] = HEX_DIGIT (n);
+
+ n = data[i] & 0x0f;
+ h[i * 2 + 1] = HEX_DIGIT (n);
+ }
+ h[i * 2] = 0;
+
+ return h;
+}
diff --git a/lib/identity.c b/lib/identity.c
new file mode 100644
index 0000000..ffe0e1d
--- /dev/null
+++ b/lib/identity.c
@@ -0,0 +1,38 @@
+/* identity.c.
+
+Copyright (C) 1995 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <kpathsea/c-proto.h>
+#include <kpathsea/lib.h>
+#include <kpathsea/progname.h>
+
+/* Return `hostname:pid' as a string. */
+
+string
+get_identity ()
+{
+ char s[1024];
+ int i;
+
+ i = XmuGetHostname (s, sizeof (s));
+ if (i == 0)
+ FATAL ("limn: Could not get hostname");
+
+ sprintf (&s[i], ":%d", getpid ());
+ return (string)xstrdup (s);
+}
diff --git a/lib/integer-ok.c b/lib/integer-ok.c
new file mode 100644
index 0000000..5af9214
--- /dev/null
+++ b/lib/integer-ok.c
@@ -0,0 +1,44 @@
+/* integer-ok.c: test if a string is a valid integer.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/c-ctype.h>
+
+
+boolean
+integer_ok (string str)
+{
+ boolean found_digit = false;
+
+ if (str == NULL)
+ return false;
+
+ /* Allow leading `-' or `+' sign. */
+ if (*str == '-' || *str == '+')
+ str++;
+
+ /* Skip decimal digits. */
+ while (ISDIGIT (*str))
+ {
+ str++;
+ found_digit = true;
+ }
+
+ return *str == 0 && found_digit;
+}
diff --git a/lib/libfile.c b/lib/libfile.c
new file mode 100644
index 0000000..7ce3633
--- /dev/null
+++ b/lib/libfile.c
@@ -0,0 +1,130 @@
+/* libfile.c: open and read a single auxiliary data file.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+#include "paths.h"
+
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/line.h>
+#include "libfile.h"
+#include "pathsrch.h"
+
+
+/* Private variables to hold the auxiliary file we're reading from, and
+ its name. */
+static FILE *lib_file = NULL;
+static string lib_filename;
+static unsigned lib_file_line_number;
+
+
+/* Prepare to read the ``library file'' FILENAME.DEFAULT_SUFFIX (if
+ FILENAME has no suffix), or just FILENAME (if it has). Give a fatal
+ error if it cannot be opened. Return the resulting FILE * (although
+ usually this will just be ignored by the caller). */
+
+FILE *
+libfile_start (string filename, string default_suffix)
+{
+ string *lib_dirs = initialize_path_list (LIB_ENVVAR, DEFAULT_LIB_PATH);
+ string name = extend_filename (filename, default_suffix);
+
+ lib_filename = find_path_filename (name, lib_dirs);
+
+ if (lib_filename == NULL)
+ FATAL1 ("%s: Cannot find library file in path", name);
+
+ lib_file = xfopen (lib_filename, "r");
+ lib_file_line_number = 1;
+
+ return lib_file;
+}
+
+
+/* Close our current open file. If we don't have any file open, give a
+ fatal error. */
+
+void
+libfile_close ()
+{
+ assert (lib_file != NULL);
+
+ fclose (lib_file);
+ lib_file = NULL;
+}
+
+/* Return the name of the currently open file, or NULL if none. */
+
+string
+libfilename ()
+{
+ return lib_file == NULL ? NULL : lib_filename;
+}
+
+
+/* Analogously, for the current line number. */
+
+unsigned
+libfile_linenumber ()
+{
+ return lib_file == NULL ? 0 : lib_file_line_number;
+}
+
+/* Return the next nonblank non-comment line from `lib_file', or NULL if
+ we are at EOF. Also remove any trailing comment on the line. */
+
+string
+libfile_line ()
+{
+ string s;
+ string line;
+ boolean skip = true;
+
+ assert (lib_file != NULL);
+
+ do
+ {
+ line = read_line (lib_file);
+ lib_file_line_number++;
+
+ /* If at EOF, quit the loop. */
+ if (line == NULL)
+ break;
+
+ s = line;
+
+ /* Move ahead to the first nonblank character. */
+ while (*s != 0 && ISSPACE (*s))
+ s++;
+
+ /* Keep going if the line was blank or a comment. */
+ if (*s == 0 || *s == '%')
+ free (line);
+ else
+ skip = false;
+ }
+ while (skip);
+
+ if (line != NULL)
+ {
+ s = strrchr (line, '%');
+ if (s != NULL)
+ *s = 0;
+ }
+
+ return line;
+}
diff --git a/lib/line.c b/lib/line.c
new file mode 100644
index 0000000..6c2e16e
--- /dev/null
+++ b/lib/line.c
@@ -0,0 +1,63 @@
+/* line.c: return the next line from a file, or NULL.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+#define BLOCK_SIZE 40
+
+char *
+read_line (f)
+ FILE *f;
+{
+ int c;
+ unsigned limit = BLOCK_SIZE;
+ unsigned loc = 0;
+ char *line = (char *) xmalloc (limit);
+
+ while ((c = getc (f)) != EOF && c != '\n')
+ {
+ line[loc] = c;
+ loc++;
+
+ /* By testing after the assignment, we guarantee that we'll always
+ have space for the null we append below. We know we always
+ have room for the first char, since we start with BLOCK_SIZE. */
+ if (loc == limit)
+ {
+ limit += BLOCK_SIZE;
+ line = (char *) xrealloc (line, limit);
+ }
+ }
+
+ /* If we read anything, return it. This can't represent a last
+ ``line'' which doesn't end in a newline, but so what. */
+ if (c != EOF)
+ {
+ /* Terminate the string. We can't represent nulls in the file,
+ either. Again, it doesn't matter. */
+ line[loc] = 0;
+ }
+ else /* At end of file. */
+ {
+ free (line);
+ line = NULL;
+ }
+
+ return line;
+}
diff --git a/lib/list.c b/lib/list.c
new file mode 100644
index 0000000..8dcca72
--- /dev/null
+++ b/lib/list.c
@@ -0,0 +1,64 @@
+/* list.c: simple list (represented as arrays) manipulation.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "list.h"
+
+
+list_type
+list_init ()
+{
+ list_type answer;
+
+ LIST_DATA (answer) = NULL;
+ LIST_SIZE (answer) = 0;
+
+ return answer;
+}
+
+
+/* Free the memory for both the elements and the list itself. */
+
+void
+list_free (list_type *list)
+{
+ if (list != NULL && LIST_DATA (*list) != NULL)
+ {
+ unsigned e;
+
+ for (e = 0; e < LIST_SIZE (*list); e++)
+ free (LIST_ELT (*list, e));
+
+ free (LIST_DATA (*list));
+ }
+}
+
+/* The list consists entirely of pointers to objects. We allocate the
+ space for the objects pointed to here, though, and return a pointer to
+ the newly-created final element in the list. */
+
+address
+list_append (list_type *list, unsigned element_size)
+{
+ LIST_SIZE (*list)++;
+ XRETALLOC (LIST_DATA (*list), LIST_SIZE (*list), address);
+ LIST_LAST_ELT (*list) = xmalloc (element_size);
+
+ return LIST_LAST_ELT (*list);
+}
diff --git a/lib/logreport.c b/lib/logreport.c
new file mode 100644
index 0000000..93d2dff
--- /dev/null
+++ b/lib/logreport.c
@@ -0,0 +1,36 @@
+/* logreport.c: showing information to the user.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "logreport.h"
+
+
+/* Says whether to output detailed progress reports, i.e., all the data
+ on the fitting, as we run. (-log) */
+boolean logging = false;
+
+FILE *log_file = NULL;
+
+
+void
+flush_log_output ()
+{
+ if (logging)
+ fflush (log_file);
+}
diff --git a/lib/make-prefix.c b/lib/make-prefix.c
new file mode 100644
index 0000000..fe4fcd4
--- /dev/null
+++ b/lib/make-prefix.c
@@ -0,0 +1,41 @@
+/* make-prefix.c: construct a pathname prefix.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/concatn.h>
+
+
+string
+make_prefix (string prefix, string pathname)
+{
+ string slash_pos = strrchr (pathname, '/');
+
+ if (slash_pos == NULL)
+ return concat (prefix, pathname);
+ else
+ {
+ string answer = NULL;
+ string path_only = xstrdup (pathname);
+ path_only[slash_pos - pathname] = 0;
+ answer = concatn (path_only, "/", prefix, slash_pos + 1, NULL);
+ free (path_only);
+
+ return answer;
+ }
+}
diff --git a/lib/math.c b/lib/math.c
new file mode 100644
index 0000000..0939d8e
--- /dev/null
+++ b/lib/math.c
@@ -0,0 +1,173 @@
+/* math.c: define some simple array operations, and other functions.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* Numerical errors sometimes make a floating point number just slightly
+ larger or smaller than its true value. When it matters, we need to
+ compare with some tolerance, REAL_EPSILON, defined in kbase.h. */
+
+const boolean
+epsilon_equal (real v1, real v2)
+{
+ return
+ v1 == v2 /* Usually they'll be exactly equal, anyway. */
+ || fabs (v1 - v2) <= REAL_EPSILON;
+}
+
+
+/* Return the Euclidean distance between P1 and P2. */
+
+const real
+distance (real_coordinate_type p1, real_coordinate_type p2)
+{
+ return hypot (p1.x - p2.x, p1.y - p2.y);
+}
+
+
+/* Same thing, for integer points. */
+const real
+int_distance (coordinate_type p1, coordinate_type p2)
+{
+ return hypot ((double) p1.x - p2.x, (double) p1.y - p2.y);
+}
+
+
+/* Return the arc cosine of V, in degrees in the range zero to 180. V
+ is taken to be in radians. */
+
+const real
+acosd (real v)
+{
+ real a;
+
+ if (epsilon_equal (v, 1.0))
+ v = 1.0;
+ else if (epsilon_equal (v, -1.0))
+ v = -1.0;
+
+ errno = 0;
+ a = acos (v);
+ if (errno == ERANGE || errno == EDOM)
+ FATAL_PERROR ("acosd");
+
+ return a * 180.0 / M_PI;
+}
+
+
+/* The slope of the line defined by COORD1 and COORD2. */
+
+const real
+slope (real_coordinate_type coord1, real_coordinate_type coord2)
+{
+ assert (coord2.x - coord1.x != 0);
+
+ return (coord2.y - coord1.y) / (coord2.x - coord1.x);
+}
+
+
+/* Turn an integer point into a real one, and vice versa. */
+
+const real_coordinate_type
+int_to_real_coord (coordinate_type int_coord)
+{
+ real_coordinate_type real_coord;
+
+ real_coord.x = int_coord.x;
+ real_coord.y = int_coord.y;
+
+ return real_coord;
+}
+
+
+const coordinate_type
+real_to_int_coord (real_coordinate_type real_coord)
+{
+ coordinate_type int_coord;
+
+ int_coord.x = ROUND (real_coord.x);
+ int_coord.y = ROUND (real_coord.y);
+
+ return int_coord;
+}
+
+
+/* See if two points (described by their row and column) are adjacent. */
+
+const boolean
+points_adjacent_p (int row1, int col1, int row2, int col2)
+{
+ int row_diff = abs (row1 - row2);
+ int col_diff = abs (col1 - col2);
+
+ return
+ (row_diff == 1 && col_diff == 1)
+ || (row_diff == 0 && col_diff == 1)
+ || (row_diff == 1 && col_diff == 0);
+}
+
+
+
+
+/* Find the largest and smallest elements in an array of reals. */
+
+void
+find_bounds (real *values, unsigned value_count, real *min, real *max)
+{
+ unsigned this_value;
+
+ /* We must use FLT_MAX and FLT_MIN, instead of the corresponding
+ values for double, because gcc uses the native atof to parse
+ floating point constants, and many atof's choke on the extremes. */
+ *min = FLT_MAX;
+ *max = FLT_MIN;
+
+ for (this_value = 0; this_value < value_count; this_value++)
+ {
+ if (values[this_value] < *min)
+ *min = values[this_value];
+
+ if (values[this_value] > *max)
+ *max = values[this_value];
+ }
+}
+
+
+
+/* Map a range of numbers, some positive and some negative, into all
+ positive, with the greatest being at one and the least at zero.
+
+ This allocates new memory. */
+
+real *
+map_to_unit (real *values, unsigned value_count)
+{
+ real smallest, largest;
+ int this_value;
+ real *mapped_values = xmalloc (sizeof (real) * value_count);
+
+ find_bounds (values, value_count, &smallest, &largest);
+
+ largest -= smallest; /* We never care about largest itself. */
+
+ for (this_value = 0; this_value < value_count; this_value++)
+ mapped_values[this_value] = (values[this_value] - smallest) / largest;
+
+ return mapped_values;
+}
diff --git a/lib/now.c b/lib/now.c
new file mode 100644
index 0000000..aabf718
--- /dev/null
+++ b/lib/now.c
@@ -0,0 +1,38 @@
+/* time.c: the current date and time.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* Get the current date and time as a string. The 26 here is defined in
+ the manual page for ctime(3). */
+
+string
+now ()
+{
+ extern time_t time (long *);
+ extern string ctime (time_t *);
+
+ string time_string = xmalloc (26);
+ time_t t = time (0);
+
+ strcpy (time_string, ctime (&t));
+ time_string[24] = 0; /* No newline. */
+
+ return time_string;
+}
diff --git a/lib/numtoa.c b/lib/numtoa.c
new file mode 100644
index 0000000..53c1a7d
--- /dev/null
+++ b/lib/numtoa.c
@@ -0,0 +1,50 @@
+/* numtoa.c: change numbers back to strings.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+/* Declarations for these are in global.h. */
+
+string
+itoa (int i)
+{
+ char a[MAX_INT_LENGTH];
+
+ sprintf (a, "%d", i);
+ return xstrdup (a);
+}
+
+string
+utoa (unsigned u)
+{
+ char a[MAX_INT_LENGTH];
+
+ sprintf (a, "%u", u);
+ return xstrdup (a);
+}
+
+string
+xdtoa (double d)
+{
+ /* I'm not sure if this is really enough, but I also don't know how to
+ compute what *would* be enough. */
+ char a[500];
+
+ sprintf (a, "%f", d);
+ return xstrdup (a);
+}
diff --git a/lib/pathsrch.c b/lib/pathsrch.c
new file mode 100644
index 0000000..e513df5
--- /dev/null
+++ b/lib/pathsrch.c
@@ -0,0 +1,509 @@
+/* pathsrch.c: look for files based on paths, i.e., colon-separated
+ lists of directories.
+
+ We should allow % specifiers in the paths for the resolution, mode
+ name, etc.
+
+Copyright (C) 1992, 93 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/c-stat.h>
+#include "c-pathch.h"
+#include "c-namemx.h"
+#include "c-pathmx.h"
+#include "paths.h"
+
+#include <kpathsea/c-ctype.h>
+#if !defined (DOS) && !defined (VMS) && !defined (VMCMS)
+#include <pwd.h>
+#endif
+#include "dirio.h"
+#include "pathsrch.h"
+
+static boolean absolute_p P1H(string filename);
+static void add_directory P3H(string **, unsigned *, string);
+static void expand_subdir P3H(string **, unsigned *, string);
+static string *find_dir_list P1H(string);
+static string readable P1H(string);
+static void save_dir_list P2H(string, string *);
+static string truncate_pathname P1H(string);
+
+/* If FILENAME is absolute or explicitly relative (i.e., starts with
+ `/', `./', or `../'), or if DIR_LIST is null, we return whether
+ FILENAME is readable as-is. Otherwise, we test if FILENAME is in any of
+ the directories listed in DIR_LIST. (The last entry of DIR_LIST must
+ be null.) We return the complete path if found, NULL else.
+
+ In the interests of doing minimal work here, we assume that each
+ element of DIR_LIST already ends with a `/'.
+
+ DIR_LIST is most conveniently made by calling `initialize_path_list'.
+ This is a separate routine because we allow recursive searching, and
+ it may take some time to discover the list of directories.
+ We do not want to incur that overhead every time we want to look for
+ a file.
+
+ (Actually, `/' is not hardwired into this routine; we use PATH_SEP,
+ defined above.) */
+
+string
+find_path_filename P2C(string, filename, string *, dir_list)
+{
+ string found_name = NULL;
+
+ /* Do this before testing for absolute-ness, as a leading ~ will be an
+ absolute pathname. */
+ filename = expand_tilde (filename);
+
+ /* If FILENAME is absolute or explicitly relative, or if DIR_LIST is
+ null, only check if FILENAME is readable. */
+ if (absolute_p (filename) || dir_list == NULL)
+ found_name = readable (filename);
+ else
+ { /* Test if FILENAME is in any of the directories in DIR_LIST. */
+ string save_filename = filename;
+
+ while (*dir_list != NULL)
+ {
+ filename = concat (*dir_list, save_filename);
+ found_name = readable (filename);
+ if (found_name == NULL)
+ {
+ free (filename);
+ dir_list++;
+ }
+ else
+ {
+ if (found_name != filename)
+ free (filename);
+ break;
+ }
+ }
+ }
+
+ return found_name;
+}
+
+
+/* If NAME is readable, return it. If the error is ENAMETOOLONG,
+ truncate any too-long path components and return the result (unless
+ there were no too-long components, i.e., a overall too-long name
+ caused the error, in which case return NULL). On any other error,
+ return NULL.
+
+ POSIX invented this brain-damage of not necessarily truncating
+ pathname components; the system's behavior is defined by the value of
+ the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! */
+
+static string
+readable (name)
+ string name;
+{
+ string ret;
+
+ if (access (name, R_OK) == 0 && !dir_p (name))
+ ret = name;
+#ifdef ENAMETOOLONG
+ else if (errno == ENAMETOOLONG)
+ {
+ ret = truncate_pathname (name);
+
+ /* Perhaps some other error will occur with the truncated name, so
+ let's call access again. */
+ if (!(access (ret, R_OK) == 0 && !dir_p (ret)))
+ { /* Failed. */
+ free (ret);
+ ret = NULL;
+ }
+ }
+#endif
+ else
+ ret = NULL; /* Some other error. */
+
+ return ret;
+}
+
+
+
+/* Truncate any too-long path components in NAME, returning the result. */
+
+static string
+truncate_pathname (name)
+ string name;
+{
+ unsigned c_len = 0; /* Length of current component. */
+ unsigned ret_len = 0; /* Length of constructed result. */
+ string ret = (string) xmalloc (PATH_MAX + 1);
+
+ for (; *name; name++)
+ {
+ if (IS_PATH_SEP (*name))
+ { /* At a directory delimiter, reset component length. */
+ c_len = 0;
+ }
+ else if (c_len > NAME_MAX)
+ { /* If past the max for a component, ignore this character. */
+ continue;
+ }
+
+ /* If we've already copied the max, give up. */
+ if (ret_len == PATH_MAX)
+ {
+ free (ret);
+ return NULL;
+ }
+
+ /* Copy this character. */
+ ret[ret_len++] = *name;
+ c_len++;
+ }
+ ret[ret_len] = 0;
+
+ return ret;
+}
+
+
+/* Return true if FILENAME is absolute or explicitly relative, else false. */
+
+static boolean
+absolute_p P1C(string, filename)
+{
+ boolean absolute = IS_PATH_SEP (*filename)
+#ifdef DOS
+ || ISALPHA (*filename) && filename[1] == ':'
+#endif
+ ;
+ boolean explicit_relative
+ = (*filename == '.'
+ && (IS_PATH_SEP (filename[1])
+ || (filename[1] == '.' && IS_PATH_SEP (filename[2]))));
+
+ return absolute || explicit_relative;
+}
+
+/* Return a NULL-terminated array of directory names, each name ending
+ with PATH_SEP, created by parsing the PATH_DELIMITER-separated list
+ in the value of the environment variable ENV_NAME, or DEFAULT_PATH if
+ the envvar is not set.
+
+ A leading or trailing colon in the value of ENV_NAME is replaced by
+ DEFAULT_PATH.
+
+ Any element of the path that ends with double PATH_SEP characters
+ (e.g., `foo//') is replaced by all its subdirectories.
+
+ If ENV_NAME is null, only parse DEFAULT_PATH. If both are null, do
+ nothing and return NULL. */
+
+string *
+initialize_path_list P2C(string, env_name, string, default_path)
+{
+ string dir, path;
+ string *dir_list;
+ unsigned dir_count = 0;
+ string env_value = env_name ? getenv (env_name) : NULL;
+ string orig_path = expand_default (env_value, default_path);
+
+ if (orig_path == NULL || *orig_path == 0)
+ return NULL;
+
+ /* If we've already seen this colon-separated list, then just get it
+ back instead of going back to the filesystem. */
+ dir_list = find_dir_list (orig_path);
+ if (dir_list != NULL)
+ return dir_list;
+
+ /* Be sure `path' is in writable memory. */
+ path = (orig_path == env_value || orig_path == default_path
+ ? xstrdup (orig_path) : orig_path);
+
+ /* Find each element in the path in turn. */
+ for (dir = strtok (path, PATH_DELIMITER_STRING); dir != NULL;
+ dir = strtok (NULL, PATH_DELIMITER_STRING))
+ {
+ int len;
+ /* If the path starts with ~ or ~user, expand it. Do this
+ before calling `expand_subdir' or `add_directory', so that
+ 1) we don't expand the same ~ for every subdirectory; and
+ 2) pathnames in `expand_subdir' don't have a `~' in them
+ (since the system won't grok `~/foo' as a directory). */
+ dir = expand_tilde (dir);
+ len = strlen (dir);
+
+ /* If `dir' is the empty string, ignore it. */
+ if (len == 0)
+ continue;
+
+ /* If `dir' ends in double slashes, do subdirectories (and remove
+ the second slash, so the final pathnames we return don't look
+ like foo//bar). Because we obviously want to do subdirectories
+ of `dir', we don't check if it is a leaf. This means that if
+ `dir' is `foo//', and `foo' contains only symlinks (so our leaf
+ test below would be true), the symlinks are chased. */
+ if (len > 2 && IS_PATH_SEP (dir[len - 1]) && IS_PATH_SEP (dir[len - 2]))
+ {
+ dir[len - 1] = 0;
+ if (dir_p (dir))
+ {
+ add_directory (&dir_list, &dir_count, dir);
+ expand_subdir (&dir_list, &dir_count, dir);
+ }
+ }
+ else
+ { /* Don't bother to add the directory if it doesn't exist. */
+ if (dir_p (dir))
+ add_directory (&dir_list, &dir_count, dir);
+ }
+ }
+
+ /* Add the terminating null entry to `dir_list'. */
+ dir_count++;
+ XRETALLOC (dir_list, dir_count, string);
+ dir_list[dir_count - 1] = NULL;
+
+ /* Save the directory list we just found. */
+ save_dir_list (orig_path, dir_list);
+
+ return dir_list;
+}
+
+/* Subroutines for `initialize_path_list'. */
+
+/* Add a newly-allocated copy of DIR to the end of the array pointed to
+ by DIR_LIST_PTR. Increment DIR_COUNT_PTR. Append a `/' to DIR if
+ necessary. We assume DIR is a directory, to avoid unnecessary an
+ unnecessary call to `stat'. */
+
+static void
+add_directory (dir_list_ptr, dir_count_ptr, dir)
+ string **dir_list_ptr;
+ unsigned *dir_count_ptr;
+ string dir;
+{
+ /* If `dir' does not end with a `/', add it. We can't just
+ write it in place, since that would overwrite the null that
+ strtok may have put in. So we always make a copy of DIR. */
+ dir = (IS_PATH_SEP (dir[strlen (dir) - 1]) ? xstrdup (dir)
+ : concat (dir, PATH_SEP_STRING));
+
+ /* Add `dir' to the list of the directories. */
+ (*dir_count_ptr)++;
+ XRETALLOC (*dir_list_ptr, *dir_count_ptr, string);
+ (*dir_list_ptr)[*dir_count_ptr - 1] = dir;
+}
+
+
+/* Add DIRNAME to DIR_LIST and look for subdirectories, recursively. We
+ assume DIRNAME is the name of a directory. */
+
+static void
+expand_subdir (dir_list_ptr, dir_count_ptr, dirname)
+ string **dir_list_ptr;
+ unsigned *dir_count_ptr;
+ string dirname;
+{
+ DIR *dir;
+ struct dirent *e;
+ unsigned length;
+ char potential[PATH_MAX];
+ struct stat st;
+
+ /* We will be looking at its contents. */
+ dir = opendir (dirname);
+ if (dir == NULL)
+ return;
+
+ /* Compute the length of DIRNAME, since it's loop-invariant. */
+ length = strlen (dirname);
+
+ /* Construct the part of the pathname that doesn't change. */
+ strcpy (potential, dirname);
+ if (!IS_PATH_SEP (potential[length - 1]))
+ {
+ potential[length] = PATH_SEP;
+ potential[length + 1] = 0;
+ length++;
+ }
+
+ while ((e = readdir (dir)) != NULL)
+ { /* If it's . or .., never mind. */
+ if (!(e->d_name[0] == '.'
+ && (e->d_name[1] == 0
+ || (e->d_name[1] == '.' && e->d_name[2] == 0))))
+ { /* If it's not a directory, we will skip it on the
+ recursive call. */
+ strcat (potential, e->d_name);
+
+ /* If we can't stat it, or if it isn't a directory, continue. */
+ if (stat (potential, &st) == 0 && S_ISDIR (st.st_mode))
+ { /* It's a subdirectory; add `potential' to the list. */
+ add_directory (dir_list_ptr, dir_count_ptr, potential);
+
+ /* If it's not a leaf, quit. Assume that leaf
+ directories have two links (one for . and one for ..).
+ This means that symbolic links to directories do not affect
+ the leaf-ness. This is arguably wrong, but the only
+ alternative I know of is to stat every entry in the
+ directory, and that is unacceptably slow.
+
+ The #ifdef here at least makes this configurable at
+ compile-time, so that if we're using VMS directories or
+ some such, we can still find subdirectories, even if it
+ is much slower. */
+#ifdef UNIX_ST_NLINK
+ if (st.st_nlink > 2)
+#endif
+ { /* All criteria are met; find subdirectories. */
+ expand_subdir (dir_list_ptr, dir_count_ptr, potential);
+ }
+ }
+
+ /* ``Remove'' the directory entry name. */
+ potential[length] = 0;
+ }
+ }
+
+ closedir (dir);
+}
+
+/* These routines, while not strictly needed to be exported, are
+ plausibly useful to be called by outsiders. */
+
+/* Replace a leading or trailing `:' in ENV_PATH with DEFAULT_PATH. If
+ neither is present, return ENV_PATH if that is non-null, else
+ DEFAULT_PATH. */
+
+string
+expand_default (env_path, default_path)
+ string env_path;
+ string default_path;
+{
+ string expansion;
+
+ if (env_path == NULL)
+ expansion = default_path;
+ else if (*env_path == PATH_DELIMITER)
+ expansion = concat (default_path, env_path);
+ else if (env_path[strlen (env_path) - 1] == PATH_DELIMITER)
+ expansion = concat (env_path, default_path);
+ else
+ expansion = env_path;
+
+ return expansion;
+}
+
+
+/* Expand a leading ~ or ~user, Unix-style, unless we are some weirdo
+ operating system. */
+
+string
+expand_tilde P1C(string, name)
+{
+#if defined (DOS) || defined (VMS) || defined (VMCMS)
+ return name;
+#else
+ string expansion;
+ string home;
+
+ /* If no leading tilde, do nothing. */
+ if (*name != '~')
+ expansion = name;
+
+ /* If `~' or `~/', use $HOME if it exists, or `.' if it doesn't. */
+ else if (IS_PATH_SEP (name[1]) || name[1] == 0)
+ {
+ home = getenv ("HOME");
+ if (home == NULL)
+ home = ".";
+
+ expansion
+ = name[1] == 0 ? home : concat3 (home, PATH_SEP_STRING, name + 2);
+ }
+
+ /* If `~user' or `~user/', look up user in the passwd database. */
+ else
+ {
+ struct passwd *p;
+ string user;
+ unsigned c = 2;
+ while (!IS_PATH_SEP (name[c]) && name[c] != 0)
+ c++;
+
+ user = (string) xmalloc (c);
+ strncpy (user, name + 1, c - 1);
+ user[c - 1] = 0;
+
+ /* We only need the cast here for those (old deficient) systems
+ which do not declare `getpwnam' in <pwd.h>. */
+ p = (struct passwd *) getpwnam (user);
+ free (user);
+ /* If no such user, just use `.'. */
+ home = p == NULL ? "." : p->pw_dir;
+
+ expansion = name[c] == 0 ? home : concat (home, name + c);
+ }
+
+ return expansion;
+#endif /* not (DOS or VMS or VM/CMS) */
+}
+
+/* Routines to save and retrieve a directory list keyed by the original
+ colon-separated path. This is useful because 1) it can take a
+ significant amount of time to discover all the subdirectories of a
+ given directory, and 2) many paths all have the same basic default,
+ and thus would recompute the directory list. */
+
+typedef struct
+{
+ string path;
+ string *dir_list;
+} saved_path_entry;
+
+static saved_path_entry *saved_paths = NULL;
+static unsigned saved_paths_length = 0;
+
+
+/* We implement the data structure as a simple linear list, since it's
+ unlikely to ever be more than a dozen or so elements long. We don't
+ bother to check here if PATH has already been saved; we always add it
+ to our list. */
+
+static void
+save_dir_list P2C(string, path, string *, dir_list)
+{
+ saved_paths_length++;
+ XRETALLOC (saved_paths, saved_paths_length, saved_path_entry);
+ saved_paths[saved_paths_length - 1].path = path;
+ saved_paths[saved_paths_length - 1].dir_list = dir_list;
+}
+
+/* When we retrieve, just check the list in order. */
+
+static string *
+find_dir_list P1C(string, path)
+{
+ unsigned p;
+
+ for (p = 0; p < saved_paths_length; p++)
+ {
+ if (strcmp (saved_paths[p].path, path) == 0)
+ return saved_paths[p].dir_list;
+ }
+
+ return NULL;
+}
diff --git a/lib/rand.c b/lib/rand.c
new file mode 100644
index 0000000..78cc7fa
--- /dev/null
+++ b/lib/rand.c
@@ -0,0 +1,70 @@
+/* rand.c: a simple pseudo-random number generator.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "rand.h"
+
+
+/* Current state of the random number generator. ANSI C says that the
+ default should be as if `srand' was called with the value 1. At all
+ times this will be a random number between 1 and RAND_MAX+1. */
+static long rand_state = 2;
+
+
+/* Set the state. It's ok if `seed' doesn't fit in a long, since we
+ check for negative values before we return anything. On the other
+ hand, we cannot allow our state to become zero, since then we will
+ produce zero forever. */
+
+void
+seed_rand (unsigned seed)
+{
+ rand_state = seed + 1;
+}
+
+
+/* Return a pseudo-random number based on `x' in the range [0, RAND_MAX].
+ We use the Ghostscript computation (from the function `zrand' in the
+ file `zmath.c'). */
+
+int
+k_rand ()
+{
+ /* We use an algorithm from CACM 31(10), pp. 1192-1201, October 1988.
+ According to a posting by Ed Taft on comp.lang.postscript, Level 2
+ (Adobe) PostScript interpreters use this algorithm too:
+
+ x[n+1] = (16807 * x[n]) mod (2^31 - 1)
+
+ The complication ensues from the fact that the multiplication may
+ lead to a 46-bit number. */
+
+#define A 16807
+#define M 0x7fffffff
+#define Q 127773 /* M / A */
+#define R 2836 /* M % A */
+ rand_state = A * (rand_state % Q) - R * (rand_state / Q);
+ while ( rand_state <= 0 ) rand_state += M;
+
+ /* OK, `rand_state' is our new random number between 1 and 2^31 - 1.
+ Now we have to subtract one, so that we return a number in the
+ range zero to RAND_MAX (inclusive). We obviously must define our
+ RAND_MAX to be 2^31 - 2, which we do (in `rand.h'). */
+ return rand_state - 1;
+}
diff --git a/lib/report.c b/lib/report.c
new file mode 100644
index 0000000..fc732b2
--- /dev/null
+++ b/lib/report.c
@@ -0,0 +1,27 @@
+/* report.c: showing information to the user online.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* Says whether to output short progress reports as we run. (-verbose) */
+boolean verbose = false;
+
+/* Where to output the reports. If a particular program uses standard
+ output for real output, this gets changed to `stderr'. */
+FILE *report_file = stdout;
diff --git a/lib/safe-free.c b/lib/safe-free.c
new file mode 100644
index 0000000..7c56d0a
--- /dev/null
+++ b/lib/safe-free.c
@@ -0,0 +1,37 @@
+/* safe-free.c: free with error checking.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* `free' itself does not return an error status. So all we can do here
+ is check for nulls. */
+
+void
+safe_free (address *item)
+{
+ if (item == NULL || *item == NULL)
+ {
+ fprintf (stderr, "safe_free: Attempt to free a null item.\n");
+ abort ();
+ }
+
+ free (*item);
+
+ *item = NULL;
+}
diff --git a/lib/scaled-num.c b/lib/scaled-num.c
new file mode 100644
index 0000000..cf4a18f
--- /dev/null
+++ b/lib/scaled-num.c
@@ -0,0 +1,75 @@
+/* scaled-num.c: conversions on ``scaled'' numbers, which are a 32-bit
+ word with 16 bits of fraction.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "scaled-num.h"
+
+
+#define SCALED_UNITY (1 << 16) /* 2^16, represents 1.00000. */
+
+
+/* This prints a scaled number, rounded to five digits. */
+
+void
+print_scaled (scaled s)
+{
+ scaled delta;
+
+ if (s < 0)
+ { /* Print sign, if negative. */
+ putchar ('-');
+ s = -s;
+ }
+
+ printf ("%u", s / SCALED_UNITY); /* Print integer part. */
+ putchar ('.');
+
+ s = 10 * (s % SCALED_UNITY) + 5;
+ delta = 10;
+
+ do
+ {
+ if (delta > SCALED_UNITY)
+ s += 0100000 - (delta / 2); /* Round the last digit. */
+
+ printf ("%c", '0' + (s / SCALED_UNITY));
+ s = 10 * (s % SCALED_UNITY);
+ delta *= 10;
+ }
+ while (s > delta);
+}
+
+
+const real
+scaled_to_real (scaled s)
+{
+ real r = (real) s / SCALED_UNITY;
+
+ return r;
+}
+
+
+const scaled
+real_to_scaled (real r)
+{
+ scaled s = r * SCALED_UNITY;
+
+ return s;
+}
diff --git a/lib/spline.c b/lib/spline.c
new file mode 100644
index 0000000..cdfc25f
--- /dev/null
+++ b/lib/spline.c
@@ -0,0 +1,216 @@
+/* spline.c: spline and spline list (represented as arrays) manipulation.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "bounding-box.h"
+#include "spline.h"
+#include "vector.h"
+
+
+/* Return a new spline structure, initialized with (recognizable)
+ garbage. */
+
+spline_type
+new_spline ()
+{
+ spline_type spline;
+
+ START_POINT (spline)
+ = CONTROL1 (spline)
+ = CONTROL2 (spline)
+ = END_POINT (spline)
+ = (real_coordinate_type) { -100.0, -100.0 };
+ SPLINE_DEGREE (spline) = -1;
+
+ return spline;
+}
+
+
+/* Print a spline in human-readable form. */
+
+void
+print_spline (FILE *f, spline_type s)
+{
+ if (SPLINE_DEGREE (s) == LINEAR)
+ fprintf (f, "(%.3f,%.3f)--(%.3f,%.3f).\n",
+ START_POINT (s).x, START_POINT (s).y,
+ END_POINT (s).x, END_POINT (s).y);
+
+ else if (SPLINE_DEGREE (s) == CUBIC)
+ fprintf (f, "(%.3f,%.3f)..ctrls(%.3f,%.3f)&(%.3f,%.3f)..(%.3f,%.3f).\n",
+ START_POINT (s).x, START_POINT (s).y,
+ CONTROL1 (s).x, CONTROL1 (s).y,
+ CONTROL2 (s).x, CONTROL2 (s).y,
+ END_POINT (s).x, END_POINT (s).y);
+
+ else
+ FATAL1 ("print_spline: strange degree (%d)", SPLINE_DEGREE (s));
+}
+
+
+
+
+/* Evaluate the spline S at a given T value. This is an implementation
+ of de Casteljau's algorithm. See Schneider's thesis (reference in
+ ../limn/README), p.37. The variable names are taken from there. */
+
+real_coordinate_type
+evaluate_spline (spline_type s, real t)
+{
+ spline_type V[4]; /* We need degree+1 splines, but assert degree <= 3. */
+ unsigned i, j;
+ real one_minus_t = 1.0 - t;
+ polynomial_degree degree = SPLINE_DEGREE (s);
+
+ for (i = 0; i <= degree; i++)
+ V[0].v[i] = s.v[i];
+
+ for (j = 1; j <= degree; j++)
+ for (i = 0; i <= degree - j; i++)
+ {
+ real_coordinate_type t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t);
+ real_coordinate_type t2 = Pmult_scalar (V[j - 1].v[i + 1], t);
+ V[j].v[i] = Padd (t1, t2);
+ }
+
+ return V[degree].v[0];
+}
+
+
+
+
+/* Return a new, empty, spline list. */
+
+spline_list_type *
+new_spline_list ()
+{
+ spline_list_type *answer = xmalloc (sizeof (spline_list_type));
+
+ SPLINE_LIST_DATA (*answer) = NULL;
+ SPLINE_LIST_LENGTH (*answer) = 0;
+
+ return answer;
+}
+
+
+/* Return a new spline list with SPLINE as the first element. */
+
+spline_list_type *
+init_spline_list (spline_type spline)
+{
+ spline_list_type *answer = xmalloc (sizeof (spline_list_type));
+
+ SPLINE_LIST_DATA (*answer) = xmalloc (sizeof (spline_type));
+ SPLINE_LIST_ELT (*answer, 0) = spline;
+ SPLINE_LIST_LENGTH (*answer) = 1;
+
+ return answer;
+}
+
+
+/* Free the storage in a spline list. We don't have to free the
+ elements, since they are arrays in automatic storage. And we don't
+ want to free the list if it was empty. */
+
+void
+free_spline_list (spline_list_type *spline_list)
+{
+ if (SPLINE_LIST_DATA (*spline_list) != NULL)
+ safe_free ((address *) &(SPLINE_LIST_DATA (*spline_list)));
+}
+
+
+/* Append the spline S to the list SPLINE_LIST. */
+
+void
+append_spline (spline_list_type *l, spline_type s)
+{
+ assert (l != NULL);
+
+ SPLINE_LIST_LENGTH (*l)++;
+ SPLINE_LIST_DATA (*l) = xrealloc (SPLINE_LIST_DATA (*l),
+ SPLINE_LIST_LENGTH (*l) * sizeof (spline_type));
+ LAST_SPLINE_LIST_ELT (*l) = s;
+}
+
+
+/* Tack the elements in the list S2 onto the end of S1.
+ S2 is not changed. */
+
+void
+concat_spline_lists (spline_list_type *s1, spline_list_type s2)
+{
+ unsigned this_spline;
+ unsigned new_length;
+
+ assert (s1 != NULL);
+
+ new_length = SPLINE_LIST_LENGTH (*s1) + SPLINE_LIST_LENGTH (s2);
+
+ XRETALLOC (SPLINE_LIST_DATA (*s1), new_length, spline_type);
+
+ for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (s2); this_spline++)
+ SPLINE_LIST_ELT (*s1, SPLINE_LIST_LENGTH (*s1)++)
+ = SPLINE_LIST_ELT (s2, this_spline);
+}
+
+
+
+/* Return a new, empty, spline list array. */
+
+spline_list_array_type
+new_spline_list_array ()
+{
+ spline_list_array_type answer;
+
+ SPLINE_LIST_ARRAY_DATA (answer) = NULL;
+ SPLINE_LIST_ARRAY_LENGTH (answer) = 0;
+
+ return answer;
+}
+
+
+/* Free the storage in a spline list array. We don't
+ want to free the list if it is empty. */
+
+void
+free_spline_list_array (spline_list_array_type *spline_list_array)
+{
+ unsigned this_list;
+
+ for (this_list = 0;
+ this_list < SPLINE_LIST_ARRAY_LENGTH (*spline_list_array);
+ this_list++)
+ free_spline_list (&SPLINE_LIST_ARRAY_ELT (*spline_list_array, this_list));
+
+ if (SPLINE_LIST_ARRAY_DATA (*spline_list_array) != NULL)
+ safe_free ((address *) &(SPLINE_LIST_ARRAY_DATA (*spline_list_array)));
+}
+
+
+/* Append the spline S to the list SPLINE_LIST_ARRAY. */
+
+void
+append_spline_list (spline_list_array_type *l, spline_list_type s)
+{
+ SPLINE_LIST_ARRAY_LENGTH (*l)++;
+ XRETALLOC (SPLINE_LIST_ARRAY_DATA (*l),
+ SPLINE_LIST_ARRAY_LENGTH (*l), spline_list_type);
+ LAST_SPLINE_LIST_ARRAY_ELT (*l) = s;
+}
diff --git a/lib/statistics.c b/lib/statistics.c
new file mode 100644
index 0000000..c786ce9
--- /dev/null
+++ b/lib/statistics.c
@@ -0,0 +1,79 @@
+/* statistics.c: find various statistics.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "statistics.h"
+
+
+/* The mean. The array A might have been filtered (for example), in
+ which case it will have many zeros in it that shouldn't be counted
+ when computing the statistics. PERTINENT is the number of elements
+ that are actually valid. COUNT, on the other hand, is the number of
+ elements in the array. */
+
+real
+mean (real *a, unsigned count, unsigned pertinent)
+{
+ unsigned this_variable;
+ real sum = 0.0;
+
+ assert (pertinent > 0);
+
+ for (this_variable = 0; this_variable < count; this_variable++)
+ sum += a[this_variable];
+
+ return sum / pertinent;
+}
+
+
+/* The standard deviation. We have to subtract one from the number of
+ samples, because we lost a degree of freedom because of the mean. */
+
+real
+standard_deviation (real *a, real mean, unsigned count, unsigned pertinent)
+{
+ real sum = 0.0;
+ int this_variable;
+
+ assert (pertinent > 0);
+
+ for (this_variable = 0; this_variable < count; this_variable++)
+ {
+ real x = a[this_variable] - mean;
+ sum += x * x;
+ }
+
+ return sqrt (sum / (pertinent > 1 ? (pertinent - 1) : 1));
+}
+
+
+/* Here's a routine to fill up the statistics structure. */
+
+statistics_type
+statistics (real *data, unsigned data_length, unsigned pertinent)
+{
+ statistics_type s;
+
+ s.mean = mean (data, data_length, pertinent);
+
+ s.variance = standard_deviation (data, s.mean, data_length, pertinent);
+ s.variance *= s.variance;
+
+ return s;
+}
diff --git a/lib/str-lcase.c b/lib/str-lcase.c
new file mode 100644
index 0000000..0c21a4c
--- /dev/null
+++ b/lib/str-lcase.c
@@ -0,0 +1,49 @@
+/* str-casefold.c: make a string either all uppercase or all lowercase.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+This file was part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/c-ctype.h>
+#include "str-lcase.h"
+
+
+/* Return a malloced copy of S with all its uppercase letters replaced
+ with their lowercase counterparts. S must not be NULL. */
+
+string
+str_to_lower (string s)
+{
+ unsigned c;
+ string lc;
+ unsigned length;
+
+ assert (s != NULL);
+
+ length = strlen (s);
+ lc = xmalloc (length + 1);
+
+ for (c = 0; c < length; c++)
+ lc[c] = ISUPPER (s[c]) ? TOLOWER (s[c]) : s[c];
+
+ lc[length] = 0;
+
+ return lc;
+
+}
diff --git a/lib/str-to-bit.c b/lib/str-to-bit.c
new file mode 100644
index 0000000..83ffa42
--- /dev/null
+++ b/lib/str-to-bit.c
@@ -0,0 +1,111 @@
+/* str-to-bit.c: typeset a text string in some font, producing a bitmap.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include <kpathsea/c-ctype.h>
+#include "font.h"
+
+
+/* Turn the C string TEXT into a bitmap, taking the characters from the
+ font FONT_NAME at resolution DPI. Any space characters in TEXT turn
+ into the natural interword space for this font. No escapes are
+ recognized in TEXT. */
+
+bitmap_type
+string_to_bitmap (string text, string font_name, unsigned dpi)
+{
+ bitmap_type b;
+ unsigned this_char;
+ char_info_type *chars[strlen (text)];
+ font_info_type font = get_font (font_name, dpi);
+ int width = 0, height = 0, depth = 0;
+ int x = 0, y = 0; /* Our current position. */
+ real tfm_space
+ = TFM_SAFE_FONTDIMEN (FONT_TFM_FONT (font), TFM_SPACE_PARAMETER, 0);
+ int font_space = POINTS_TO_PIXELS (tfm_space, dpi);
+
+ for (this_char = 0; this_char < strlen (text); this_char++)
+ {
+ /* Turn any kind of space character into a normal interword space. */
+ if (ISSPACE (text[this_char]))
+ width += font_space;
+ else
+ {
+ chars[this_char] = get_char (font_name, text[this_char]);
+
+ /* If the character doesn't exist in this font, just keep
+ going. */
+ if (chars[this_char] == NULL)
+ continue;
+
+ /* The set width should be equal to the left side bearing plus
+ the bitmap width plus the right side bearing. */
+ width += CHAR_SET_WIDTH (*chars[this_char]);
+ height = MAX (height, CHAR_HEIGHT (*chars[this_char]));
+ depth = MAX (depth, CHAR_DEPTH (*chars[this_char]));
+ }
+ }
+
+ /* Unless the image is nonnegative both horizontally and vertically,
+ it is invisible. */
+ if (width <= 0 || (height + depth + 1 <= 0))
+ {
+ BITMAP_WIDTH (b) = 0;
+ BITMAP_HEIGHT (b) = 0;
+ BITMAP_BITS (b) = NULL;
+ return b;
+ }
+
+ /* The image is going to be visible. */
+ b = new_bitmap ((dimensions_type) { height + depth + 1, width });
+
+ for (this_char = 0; this_char < strlen (text); this_char++)
+ {
+ if (ISSPACE (text[this_char]))
+ x += font_space;
+ else
+ {
+ int char_x, char_y;
+ char_info_type c;
+
+ if (chars[this_char] == NULL)
+ continue;
+
+ c = *chars[this_char];
+
+ x += CHAR_LSB (c);
+ x = MAX (x, 0); /* In case the lsb was negative. */
+
+ /* Copy the character image to the bitmap we are building, one
+ column at a time, from top to bottom. */
+ for (char_x = 0; char_x < CHAR_BITMAP_WIDTH (c); char_x++, x++)
+ for (char_y = 0, y = height - CHAR_HEIGHT (c);
+ char_y < CHAR_BITMAP_HEIGHT (c);
+ char_y++, y++)
+ BITMAP_PIXEL (b, y, x)
+ = BITMAP_PIXEL (CHAR_BITMAP (c), char_y, char_x);
+
+ x += CHAR_RSB (c);
+ }
+ }
+
+ close_font (font_name);
+
+ return b;
+}
diff --git a/lib/strstr.o b/lib/strstr.o
new file mode 100644
index 0000000..a882b08
--- /dev/null
+++ b/lib/strstr.o
Binary files differ
diff --git a/lib/substring.c b/lib/substring.c
new file mode 100644
index 0000000..8ef7174
--- /dev/null
+++ b/lib/substring.c
@@ -0,0 +1,50 @@
+/* substring.c: copy a chunk from a string.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* Return a fresh copy of SOURCE[START..LIMIT], or NULL if LIMIT<START.
+ If LIMIT>strlen(START), it is reassigned. */
+
+string
+substring (string source, const unsigned start, const unsigned limit)
+{
+ string result;
+ unsigned this_char;
+ unsigned length = strlen (source);
+ unsigned lim = limit;
+
+ /* Upper bound out of range? */
+ if (lim >= length)
+ lim = length - 1;
+
+ /* Null substring? */
+ if (start > limit)
+ return "";
+
+ /* The `2' here is one for the null and one for limit - start inclusive. */
+ result = xmalloc (limit - start + 2);
+
+ for (this_char = start; this_char <= limit; this_char++)
+ result[this_char - start] = source[this_char];
+
+ result[this_char - start] = 0;
+
+ return result;
+}
diff --git a/lib/varstring.c b/lib/varstring.c
new file mode 100644
index 0000000..0107abd
--- /dev/null
+++ b/lib/varstring.c
@@ -0,0 +1,97 @@
+/* varstring.c: variable-length strings.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "varstring.h"
+
+
+/* You use variable-length stringsd by calling `init_string' first, then
+ assigning to particular elements via `set_string_element'. The string
+ will initially be `INITIAL_SIZE' characters, and be incremented in
+ blocks of size `INCREMENT_SIZE'. */
+
+#define INITIAL_SIZE 16
+#define INCREMENT_SIZE 64
+
+variable_string
+vs_init ()
+{
+ variable_string vs;
+
+ VS_CHARS (vs) = xmalloc (INITIAL_SIZE);
+ *VS_CHARS (vs) = 0;
+ VS_ALLOCATED (vs) = INITIAL_SIZE;
+ VS_USED (vs) = 0;
+
+ return vs;
+}
+
+
+/* Free the data we've allocated for VS. */
+
+void
+vs_free (variable_string *vs)
+{
+ free (VS_CHARS (*vs));
+ VS_CHARS (*vs) = NULL;
+}
+
+
+/* We do not put a NULL after we insert NEW_CHAR at the (zero-based)
+ index LOC. The caller is responsible for that. */
+
+void
+vs_set_char (variable_string *vs, unsigned loc, char new_char)
+{
+ /* Do we need more space? */
+ if (loc >= VS_ALLOCATED (*vs))
+ { /* Yes. Make sure to allocate enough. */
+ unsigned extra = MAX (INCREMENT_SIZE, loc - VS_ALLOCATED (*vs) + 1);
+ VS_CHARS (*vs) = xrealloc (VS_CHARS (*vs), VS_ALLOCATED (*vs) + extra);
+ VS_ALLOCATED (*vs) += extra;
+ }
+
+ VS_CHARS (*vs)[loc] = new_char;
+ VS_USED (*vs) = loc + 1;
+}
+
+
+/* Append NEW_CHAR to VS. */
+
+void
+vs_append_char (variable_string *vs, char new_char)
+{
+ vs_set_char (vs, VS_USED (*vs), new_char);
+}
+
+
+variable_string
+vs_concat (variable_string vs1, variable_string vs2)
+{
+ variable_string vs;
+ unsigned used = VS_USED (vs1) + VS_USED (vs2);
+
+ VS_CHARS (vs) = xmalloc (used + 1);
+ memcpy (VS_CHARS (vs), VS_CHARS (vs1), VS_USED (vs1));
+ memcpy (VS_CHARS (vs) + VS_USED (vs1), VS_CHARS (vs2), VS_USED (vs2));
+ VS_ALLOCATED (vs) = used + 1;
+ VS_USED (vs) = used;
+
+ return vs;
+}
diff --git a/lib/vector.c b/lib/vector.c
new file mode 100644
index 0000000..354af2d
--- /dev/null
+++ b/lib/vector.c
@@ -0,0 +1,272 @@
+/* vector.c: vector/point operations.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "vector.h"
+
+
+/* Given the point COORD, return the corresponding vector. */
+
+const vector_type
+make_vector (const real_coordinate_type c)
+{
+ vector_type v;
+
+ v.dx = c.x;
+ v.dy = c.y;
+
+ return v;
+}
+
+
+/* And the converse: given a vector, return the corresponding point. */
+
+const real_coordinate_type
+vector_to_point (const vector_type v)
+{
+ real_coordinate_type coord;
+
+ coord.x = v.dx;
+ coord.y = v.dy;
+
+ return coord;
+}
+
+
+
+const real
+magnitude (const vector_type v)
+{
+ return hypot (v.dx, v.dy);
+}
+
+
+const vector_type
+normalize (const vector_type v)
+{
+ vector_type new_v;
+ real m = magnitude (v);
+
+ assert (m > 0.0);
+
+ new_v.dx = v.dx / m;
+ new_v.dy = v.dy / m;
+
+ return new_v;
+}
+
+
+const vector_type
+Vadd (const vector_type v1, const vector_type v2)
+{
+ vector_type new_v;
+
+ new_v.dx = v1.dx + v2.dx;
+ new_v.dy = v1.dy + v2.dy;
+
+ return new_v;
+}
+
+
+const real
+Vdot (const vector_type v1, const vector_type v2)
+{
+ return v1.dx * v2.dx + v1.dy * v2.dy;
+}
+
+
+const vector_type
+Vmult_scalar (const vector_type v, const real r)
+{
+ vector_type new_v;
+
+ new_v.dx = v.dx * r;
+ new_v.dy = v.dy * r;
+
+ return new_v;
+}
+
+
+/* Given the IN_VECTOR and OUT_VECTOR, return the angle between them in
+ degrees, in the range zero to 180. */
+
+const real
+Vangle (const vector_type in_vector, const vector_type out_vector)
+{
+ vector_type v1 = normalize (in_vector);
+ vector_type v2 = normalize (out_vector);
+
+ return acosd (Vdot (v2, v1));
+}
+
+
+const real_coordinate_type
+Vadd_point (const real_coordinate_type c, const vector_type v)
+{
+ real_coordinate_type new_c;
+
+ new_c.x = c.x + v.dx;
+ new_c.y = c.y + v.dy;
+ return new_c;
+}
+
+
+const real_coordinate_type
+Vsubtract_point (const real_coordinate_type c, const vector_type v)
+{
+ real_coordinate_type new_c;
+
+ new_c.x = c.x - v.dx;
+ new_c.y = c.y - v.dy;
+ return new_c;
+}
+
+
+const coordinate_type
+Vadd_int_point (const coordinate_type c, const vector_type v)
+{
+ coordinate_type a;
+
+ a.x = ROUND ((real) c.x + v.dx);
+ a.y = ROUND ((real) c.y + v.dy);
+ return a;
+}
+
+
+const vector_type
+Vabs (const vector_type v)
+{
+ vector_type new_v;
+
+ new_v.dx = fabs (v.dx);
+ new_v.dy = fabs (v.dy);
+ return new_v;
+}
+
+
+
+/* Operations on points. */
+
+/* This is a macro now. */
+#if 0
+const real_coordinate_type
+Padd (real_coordinate_type coord1, real_coordinate_type coord2)
+{
+ real_coordinate_type sum;
+
+ sum.x = coord1.x + coord2.x;
+ sum.y = coord1.y + coord2.y;
+
+ return sum;
+}
+
+
+const real_coordinate_type
+Pmult_scalar (const real_coordinate_type coord, const real r)
+{
+ real_coordinate_type answer;
+
+ answer.x = coord.x * r;
+ answer.y = coord.y * r;
+
+ return answer;
+}
+#endif /* 0 */
+
+
+const vector_type
+Psubtract (const real_coordinate_type c1, const real_coordinate_type c2)
+{
+ vector_type v;
+
+ v.dx = c1.x - c2.x;
+ v.dy = c1.y - c2.y;
+
+ return v;
+}
+
+
+
+/* Operations on integer points. */
+
+const vector_type
+IPsubtract (const coordinate_type coord1, const coordinate_type coord2)
+{
+ vector_type v;
+
+ v.dx = coord1.x - coord2.x;
+ v.dy = coord1.y - coord2.y;
+
+ return v;
+}
+
+
+const coordinate_type
+IPsubtractP (const coordinate_type c1, const coordinate_type c2)
+{
+ coordinate_type c;
+
+ c.x = c1.x - c2.x;
+ c.y = c1.y - c2.y;
+
+ return c;
+}
+
+
+const coordinate_type
+IPadd (const coordinate_type c1, const coordinate_type c2)
+{
+ coordinate_type c;
+
+ c.x = c1.x + c2.x;
+ c.y = c1.y + c2.y;
+
+ return c;
+}
+
+
+const coordinate_type
+IPmult_scalar (const coordinate_type c, const int i)
+{
+ coordinate_type a;
+
+ a.x = c.x * i;
+ a.y = c.y * i;
+
+ return a;
+}
+
+
+const real_coordinate_type
+IPmult_real (const coordinate_type c, const real r)
+{
+ real_coordinate_type a;
+
+ a.x = c.x * r;
+ a.y = c.y * r;
+
+ return a;
+}
+
+
+const boolean
+IPequal (const coordinate_type c1, const coordinate_type c2)
+{
+ return c1.x == c2.x && c1.y == c2.y;
+}
diff --git a/lib/xchdir.c b/lib/xchdir.c
new file mode 100644
index 0000000..9831663
--- /dev/null
+++ b/lib/xchdir.c
@@ -0,0 +1,29 @@
+/* xchdir.c: chdir with error checking.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "dirio.h"
+
+
+void
+xchdir (string dirname)
+{
+ if (chdir (dirname) != 0)
+ FATAL_PERROR (dirname);
+}
diff --git a/lib/xfseek.o b/lib/xfseek.o
new file mode 100644
index 0000000..fc2e725
--- /dev/null
+++ b/lib/xfseek.o
Binary files differ
diff --git a/lib/xftell.o b/lib/xftell.o
new file mode 100644
index 0000000..0dfe6f8
--- /dev/null
+++ b/lib/xftell.o
Binary files differ
diff --git a/lib/xgetcwd.c b/lib/xgetcwd.c
new file mode 100644
index 0000000..8f3e4a9
--- /dev/null
+++ b/lib/xgetcwd.c
@@ -0,0 +1,104 @@
+/* xgetcwd.c: a from-scratch version of getwd. Based on the tcsh 5.20
+ source, apparently uncopyrighted.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+#include "c-pathmx.h"
+
+#include "dirio.h"
+#include "xstat.h"
+
+/* Return the pathname of the current directory, or give a fatal error. */
+
+string
+xgetcwd ()
+{
+ /* If the system provides getwd, use it. But don't use getcwd;
+ forking a process is even more expensive than all the stat calls we
+ make figuring out the cwd. */
+#ifdef GETWD_MISSING /* whole function */
+ struct stat root_stat, cwd_stat;
+ string cwd_path = xmalloc (1);
+
+ *cwd_path = 0;
+
+ /* Find the inodes of the root and current directories. */
+ root_stat = xstat ("/");
+ cwd_stat = xstat (".");
+
+ /* Go up the directory hierarchy until we get to root, prepending each
+ directory we pass through to `cwd_path'. */
+ while (!SAME_FILE_P (root_stat, cwd_stat))
+ {
+ struct dirent *e;
+ DIR *parent_dir;
+ boolean found = false;
+
+ xchdir ("..");
+ parent_dir = xopendir (".");
+
+ /* Look through the parent directory for the entry with the same
+ inode, so we can get its name. */
+ while ((e = readdir (parent_dir)) != NULL && !found)
+ {
+ struct stat test_stat = xlstat (e->d_name);
+
+ if (SAME_FILE_P (test_stat, cwd_stat))
+ {
+ /* We've found it. Prepend the pathname. */
+ string temp = cwd_path;
+ cwd_path = concat3 ("/", e->d_name, cwd_path);
+ free (temp);
+
+ /* Set up to test the next parent. */
+ cwd_stat = xstat (".");
+
+ /* Stop reading this directory. */
+ found = true;
+ }
+ }
+ if (!found)
+ FATAL2 ("No inode %d/device %d in parent directory",
+ cwd_stat.st_ino, cwd_stat.st_dev);
+
+ xclosedir (parent_dir);
+ }
+
+ /* If the current directory is the root, cwd_path will be the empty
+ string, and we will have not gone through the loop. */
+ if (*cwd_path == 0)
+ cwd_path = "/";
+ else
+ /* Go back to where we were. */
+ xchdir (cwd_path);
+
+ return cwd_path;
+
+#else /* not GETWD_MISSING */
+
+ string path = xmalloc (PATH_MAX + 1);
+
+ if (getwd (path) == 0)
+ {
+ fprintf (stderr, "getwd: %s", path);
+ exit (1);
+ }
+
+ return path;
+#endif /* not GETWD_MISSING */
+}
diff --git a/lib/xmessage.c b/lib/xmessage.c
new file mode 100644
index 0000000..1b8331a
--- /dev/null
+++ b/lib/xmessage.c
@@ -0,0 +1,101 @@
+/* xmessage.c: pop up a message for five seconds and then go away.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef X_DISPLAY_MISSING /* whole file */
+
+#include "config.h"
+
+#include "xt-common.h"
+#include <X11/Shell.h>
+#include <X11/Xaw/Label.h>
+
+#include "xmessage.h"
+
+static void message_over (XtPointer, XtIntervalId *);
+
+
+
+/* Make a popup child of the widget PARENT displaying the string S. We
+ pass the ARGS and N_ARGS parameters to the creation routine. */
+
+void
+x_message (Widget parent, string s, ArgList args, Cardinal n_args)
+{
+ Dimension parent_height;
+ Position popup_x, popup_y;
+ Widget popup;
+
+ XtAppContext app_con = XtWidgetToApplicationContext (parent);
+ Arg parent_args[]
+ = { { XtNheight, (XtArgVal) &parent_height },
+ };
+ Arg popup_args[]
+ = { { XtNx, 0 }, /* We assign to the position below. */
+ { XtNy, 0 },
+ { XtNgeometry, (XtArgVal) NULL }, /* Don't use parent's geometry. */
+ };
+
+ Arg default_args[] = { { XtNlabel, (XtArgVal) s } };
+ ArgList all_args
+ = XtMergeArgLists (args, n_args, default_args, XtNumber (default_args));
+
+ /* Put the message at the left edge of and about halfway down PARENT's
+ window. We pass the address of true Position variables rather
+ than the address of the Arg values; in the latter case, the
+ endianness of the computer determines which half of the word the
+ answers get stored in, which is clearly bad. */
+ XtGetValues (parent, parent_args, XtNumber (parent_args));
+ XtTranslateCoords (parent, 0, parent_height / 2, &popup_x, &popup_y);
+ popup_args[0].value = popup_x;
+ popup_args[1].value = popup_y;
+
+ popup = XtCreatePopupShell ("message shell", transientShellWidgetClass,
+ parent, popup_args, XtNumber (popup_args));
+
+ /* We can't use XtNumber on `all_args', since it's a pointer. */
+ (void)
+ XtCreateManagedWidget ("message", labelWidgetClass, popup, all_args,
+ n_args + XtNumber (default_args));
+
+ /* XtPopup realizes the window, etc. */
+ XtPopup (popup, XtGrabNone);
+
+ /* Leave the message there for five seconds. */
+ (void) XtAppAddTimeOut (app_con, 5000, message_over, popup);
+}
+
+
+/* Just a convenient interface to the above. */
+
+void
+x_warning (Widget parent, string s)
+{
+ x_message (parent, concat (s, "."), NULL, 0);
+}
+
+
+
+static void
+message_over (XtPointer client_data, XtIntervalId *interval_id)
+{
+ Widget popup = (Widget) client_data;
+
+ XtPopdown (popup);
+}
+
+#endif /* not X_DISPLAY_MISSING */
diff --git a/lib/xopendir.c b/lib/xopendir.c
new file mode 100644
index 0000000..02709ac
--- /dev/null
+++ b/lib/xopendir.c
@@ -0,0 +1,47 @@
+/* xopendir.c: opendir and closedir with error checking.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+#include "dirio.h"
+
+
+DIR *
+xopendir P1C(string, dirname)
+{
+ DIR *d = opendir (dirname);
+
+ if (d == NULL)
+ FATAL_PERROR (dirname);
+
+ return d;
+}
+
+
+void
+xclosedir P1C(DIR *, d)
+{
+#ifdef VOID_CLOSEDIR
+ closedir (d);
+#else
+ int ret = closedir (d);
+
+ if (ret != 0)
+ FATAL ("closedir failed");
+#endif
+}
diff --git a/lib/xrename.c b/lib/xrename.c
new file mode 100644
index 0000000..c840805
--- /dev/null
+++ b/lib/xrename.c
@@ -0,0 +1,44 @@
+/* xrename.c: conceptually rename with error checking.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* Copy FROM to TO, then unlink FROM. It would probably be faster to
+ read and write buffers, but the files we use this for aren't big
+ enough for it to make a substantial difference. */
+
+void
+xrename (string from, string to)
+{
+ int c;
+ FILE *input = xfopen (from, "r");
+ FILE *output = xfopen (to, "w");
+
+ while ((c = getc (input)) != EOF || !feof (input))
+ putc (c, output);
+
+ xfclose (input, from);
+ xfclose (output, to);
+
+ if (unlink (from) != 0)
+ {
+ fprintf (stderr, "warning: Could not unlink ");
+ perror (from);
+ }
+}
diff --git a/lib/xstrdup.c b/lib/xstrdup.c
new file mode 100644
index 0000000..3ce69e9
--- /dev/null
+++ b/lib/xstrdup.c
@@ -0,0 +1,29 @@
+/* xstrdup.c: strdup with error checking.
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+
+
+/* Return a copy of S in new storage. */
+
+string
+xstrdup P1C(string, s)
+{
+ string new_string = (string) xmalloc (strlen (s) + 1);
+ return strcpy (new_string, s);
+}