summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@cygnus.com>2000-06-16 07:49:23 +0000
committerUlrich Drepper <drepper@cygnus.com>2000-06-16 07:49:23 +0000
commit60d2084de5dc3b65e6657f695f0f26df24b0f565 (patch)
tree224f21c30351570d6d7f06a385e829d5ab320f67 /lib
downloadexternal_gettext-60d2084de5dc3b65e6657f695f0f26df24b0f565.zip
external_gettext-60d2084de5dc3b65e6657f695f0f26df24b0f565.tar.gz
external_gettext-60d2084de5dc3b65e6657f695f0f26df24b0f565.tar.bz2
Initial revision
Diffstat (limited to 'lib')
-rw-r--r--lib/.deps/.P1
-rw-r--r--lib/.deps/alloca.P1
-rw-r--r--lib/.deps/error.P1
-rw-r--r--lib/.deps/fstrcmp.P2
-rw-r--r--lib/.deps/getline.P1
-rw-r--r--lib/.deps/getopt.P1
-rw-r--r--lib/.deps/getopt1.P1
-rw-r--r--lib/.deps/hash.P1
-rw-r--r--lib/.deps/obstack.P1
-rw-r--r--lib/.deps/printf-prs.P1
-rw-r--r--lib/.deps/xgetcwd.P1
-rw-r--r--lib/.deps/xmalloc.P1
-rw-r--r--lib/.deps/xstrdup.P1
-rw-r--r--lib/ChangeLog503
-rw-r--r--lib/Makefile.am36
-rw-r--r--lib/Makefile.in371
-rw-r--r--lib/alloca.c513
-rw-r--r--lib/basename.c41
-rw-r--r--lib/error.c248
-rw-r--r--lib/error.h78
-rw-r--r--lib/fstrcmp.c636
-rw-r--r--lib/fstrcmp.h25
-rw-r--r--lib/getline.c155
-rw-r--r--lib/getline.h36
-rw-r--r--lib/getopt.c1052
-rw-r--r--lib/getopt.h133
-rw-r--r--lib/getopt1.c190
-rw-r--r--lib/hash.c385
-rw-r--r--lib/hash.h53
-rw-r--r--lib/memmove.c108
-rw-r--r--lib/memset.c90
-rw-r--r--lib/obstack.c593
-rw-r--r--lib/obstack.h593
-rw-r--r--lib/pathmax.h53
-rw-r--r--lib/po-mode.el2599
-rw-r--r--lib/printf-parse.h421
-rw-r--r--lib/printf-prs.c120
-rw-r--r--lib/printf.h108
-rw-r--r--lib/stpcpy.c51
-rw-r--r--lib/stpncpy.c101
-rw-r--r--lib/strcasecmp.c77
-rw-r--r--lib/strcspn.c52
-rw-r--r--lib/strncasecmp.c80
-rw-r--r--lib/strstr.c125
-rw-r--r--lib/strtol.c445
-rw-r--r--lib/strtoul.c23
-rw-r--r--lib/system.h139
-rw-r--r--lib/vasprintf.c0
-rw-r--r--lib/xgetcwd.c79
-rw-r--r--lib/xmalloc.c129
-rw-r--r--lib/xstrdup.c42
51 files changed, 10497 insertions, 0 deletions
diff --git a/lib/.deps/.P b/lib/.deps/.P
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/lib/.deps/.P
@@ -0,0 +1 @@
+
diff --git a/lib/.deps/alloca.P b/lib/.deps/alloca.P
new file mode 100644
index 0000000..c2fbdb8
--- /dev/null
+++ b/lib/.deps/alloca.P
@@ -0,0 +1 @@
+alloca.o: alloca.c
diff --git a/lib/.deps/error.P b/lib/.deps/error.P
new file mode 100644
index 0000000..e033d68
--- /dev/null
+++ b/lib/.deps/error.P
@@ -0,0 +1 @@
+error.o: error.c
diff --git a/lib/.deps/fstrcmp.P b/lib/.deps/fstrcmp.P
new file mode 100644
index 0000000..9bbd4da
--- /dev/null
+++ b/lib/.deps/fstrcmp.P
@@ -0,0 +1,2 @@
+fstrcmp.o: fstrcmp.c ../config.h system.h \
+ fstrcmp.h
diff --git a/lib/.deps/getline.P b/lib/.deps/getline.P
new file mode 100644
index 0000000..abe097b
--- /dev/null
+++ b/lib/.deps/getline.P
@@ -0,0 +1 @@
+getline.o: ../lib/getline.c
diff --git a/lib/.deps/getopt.P b/lib/.deps/getopt.P
new file mode 100644
index 0000000..51f06c0
--- /dev/null
+++ b/lib/.deps/getopt.P
@@ -0,0 +1 @@
+getopt.o: getopt.c
diff --git a/lib/.deps/getopt1.P b/lib/.deps/getopt1.P
new file mode 100644
index 0000000..1acc5d2
--- /dev/null
+++ b/lib/.deps/getopt1.P
@@ -0,0 +1 @@
+getopt1.o: getopt1.c getopt.h
diff --git a/lib/.deps/hash.P b/lib/.deps/hash.P
new file mode 100644
index 0000000..1701cf4
--- /dev/null
+++ b/lib/.deps/hash.P
@@ -0,0 +1 @@
+hash.o: hash.c system.h hash.h
diff --git a/lib/.deps/obstack.P b/lib/.deps/obstack.P
new file mode 100644
index 0000000..525e862
--- /dev/null
+++ b/lib/.deps/obstack.P
@@ -0,0 +1 @@
+obstack.o: ../lib/obstack.c ../lib/obstack.h
diff --git a/lib/.deps/printf-prs.P b/lib/.deps/printf-prs.P
new file mode 100644
index 0000000..63851aa
--- /dev/null
+++ b/lib/.deps/printf-prs.P
@@ -0,0 +1 @@
+printf-prs.o: ../lib/printf-prs.c ../lib/printf-parse.h
diff --git a/lib/.deps/xgetcwd.P b/lib/.deps/xgetcwd.P
new file mode 100644
index 0000000..12c1491
--- /dev/null
+++ b/lib/.deps/xgetcwd.P
@@ -0,0 +1 @@
+xgetcwd.o: xgetcwd.c pathmax.h
diff --git a/lib/.deps/xmalloc.P b/lib/.deps/xmalloc.P
new file mode 100644
index 0000000..5325ac3
--- /dev/null
+++ b/lib/.deps/xmalloc.P
@@ -0,0 +1 @@
+xmalloc.o: xmalloc.c error.h
diff --git a/lib/.deps/xstrdup.P b/lib/.deps/xstrdup.P
new file mode 100644
index 0000000..df89dff
--- /dev/null
+++ b/lib/.deps/xstrdup.P
@@ -0,0 +1 @@
+xstrdup.o: xstrdup.c
diff --git a/lib/ChangeLog b/lib/ChangeLog
new file mode 100644
index 0000000..2c760b1
--- /dev/null
+++ b/lib/ChangeLog
@@ -0,0 +1,503 @@
+2000-05-06 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile.am (EXTRA_DIST): Add basename.c.
+ (libnlsut_a_SOURCES): Add basename.c.
+
+1998-06-01 Ulrich Drepper <drepper@cygnus.com>
+
+ * printf-parse.h: Change back from using `unsigned char' to `char'.
+
+1998-04-29 Ulrich Drepper <drepper@cygnus.com>
+
+ * printf-parse.h: Use unsigned char for parameters to read_int and
+ parse_one_spec (for loosing Solaris systems).
+ Patch by Jim Meyering.
+
+1998-04-28 11:42 Ulrich Drepper <drepper@cygnus.com>
+
+ * hash.c: Include malloc.h if stdlib.h is not available.
+ Include either string.h or strings.h.
+
+ * system.h: Include limits.h before defining MAX to prevent
+ redefinitions.
+
+ * Makefile.am: Move basename.c from EXTRA_DIST to libnlsut_a_SOURCES.
+
+1998-04-27 20:51 Ulrich Drepper <drepper@cygnus.com>
+
+ * Makefile (EXTRA_DIST): Remove obstack.c here.
+ (libnlsut_a_SOURCES): Add obstack.c here.
+
+ * alloca.c: Include string.h and stdlib.h if available. Fix typos.
+
+ * getopt.c: Update from glibc version.
+
+ * hash.c: Include stdlib.h. Use #if instead of #ifdef while testing
+ HAVE_* macros. Don't include system.h.
+
+ * printf-parse.h: Use #if instead of #ifdef.
+
+1997-08-18 13:47 Philippe De Muyter <phdm@info.ucl.ac.be>
+
+ * xstrdup.c (sys/types.h): File included.
+ * system.h (strstr): Function prototype added.
+
+1997-08-15 03:01 Ulrich Drepper <drepper@cygnus.com>
+
+ * stpcpy.c, stpncpy.c: Copy version from glibc to fix severe bugs.
+
+1997-08-01 15:47 Ulrich Drepper <drepper@cygnus.com>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Require version 1.2.
+
+Mon Mar 10 06:52:59 1997 Ulrich Drepper <drepper@cygnus.com>
+
+ * xstrdup.c: Add more compatibility handling. Pretty-print
+ preprocessor directives.
+
+ * printf-parse.h: Define _GNU_SOURCE not __USE_GNU.
+
+ * Makefile.am: Change for use with automake-1.1.
+
+1997-02-08 04:26 Ulrich Drepper <drepper@cygnus.com>
+
+ * stpncpy.c: Update from version in GNU libc 2.0. This corrects
+ a long standing bug in xgettext.
+
+Fri Dec 6 04:20:56 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * system.h: Use PARAMS not __P for basename prototype.
+ Reported by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>.
+
+Tue Dec 3 17:50:34 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * system.h: Add prototype for basename.
+
+ * Makefile.am (EXTRA_DIST): Add basename.c.
+
+Fri Nov 22 03:32:34 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * Makefile.am (EXTRA_DIST): Rename strncase.c to strncasecmp.c.
+
+Sat Aug 31 04:52:56 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * Makefile.am (nlsut_SOURCES): Move error.c to EXTRA_DIST.
+
+Wed Jun 19 02:45:02 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * system.h: Add prototypes for stpncpy, strcasecmp, and
+ strncasecmp.
+
+ * Makefile.am (EXTRA_DIST): Add strncase and stpncpy.
+
+Fri Jun 14 03:56:23 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * getline.c (_GNU_SOURCE): Define this macro, not __USE_GNU.
+
+ * Makefile.am (nlsut_SOURCES): Move getline.c and printf-prs.c to
+ EXTRA_DIST. Reported by Kaveh R. Ghazi.
+
+Tue Jun 11 15:28:17 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * printf-prs.c: Add some casts for `n'.
+
+ * printf-parse.h: Add prototypes and __USE_GNU definition.
+
+ * getline.c: Define __USE_GNU to get prototype.
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Add variable. Must be defined
+ in all subdirs.
+
+Wed Jun 5 16:54:43 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * Makefile.am (INCLUDES): Define include paths to intl/ dir for
+ <libintl.h> file.
+
+Mon Jun 3 19:13:36 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * getopt.c: Update from latest GNU libc source. We don't need
+ the AC_REPLACE_GNU_GETOPT anymore.
+
+ * Makefile.am (EXTRA_DIST): Remove files mentioned in
+ nlsut_SOURCES from EXTRA_DIST.
+ (nlsut_SOURCES): Add getopt.c and getopt1.c.
+
+Wed Apr 24 23:48:42 1996 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (GETOPT): Remove variable.
+ (OBJECTS): Don't use $(GETOPT). If not present the getopt are now
+ listed in @LIBOBJS@.
+
+Fri Apr 5 12:00:51 1996 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (SOURCES): Remove whoami.c.
+ (OBJECTS): Remove whoami.o.
+
+ * system.h: Remove prototype for `get_submitter'.
+
+Thu Apr 4 21:14:51 1996 Ulrich Drepper <drepper@myware>
+
+ * system.h: Add prototype for asprintf.
+
+Tue Apr 2 18:53:38 1996 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (all-gettext): New goal. Same as all.
+
+Tue Apr 2 12:57:44 1996 Ulrich Drepper <drepper@myware>
+
+ * error.c, error.h: Update from version in GNU libc.
+
+Tue Mar 26 12:35:56 1996 Ulrich Drepper <drepper@myware>
+
+ * error.c, error.h: Applied François' patches for more
+ portability.
+
+Mon Mar 25 01:21:31 1996 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (SOURCES): Add strstr.c.
+
+Sun Mar 24 18:41:42 1996 Ulrich Drepper <drepper@myware>
+
+ * error.c (error_with_loc): In `one error per line' mode check for
+ old_file_name to be NULL first. Reported by François Pinard.
+
+Fri Mar 1 13:38:26 1996 Ulrich Drepper <drepper@myware>
+
+ * getopt.c: Update from latest version in GNU C Library.
+ * getopt1.c: Ditto.
+ * getopt.h: Ditto.
+
+ * error.c (error_with_loc): Not simply compare string pointers to
+ test for same file name.
+ (error_with_loc): file_name parameter is really const.
+
+ * error.c (error_one_per_line): New variable.
+ (error_with_loc): If error_one_per_line != 0, print at most one
+ error per line.
+
+ * error.h: Declare new variable error_one_per_line.
+
+Mon Jan 1 03:12:08 1996 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (GETOPTSRC): Remove this variable.
+
+Sat Dec 30 16:26:07 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (ERROR, ERRORSRC): New variables. error.c is now
+ part of GNU libc and will not be needed on systems running this
+ lib.
+ (SOURCES): Replace error.c with $(ERRORSRC).
+ (OBJECTS): Replace error.o with $(ERROR).
+
+Tue Dec 19 22:08:10 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (Makefile): Explicitly use $(SHELL) for running
+ shell scripts.
+
+Sat Dec 9 16:40:49 1995 Ulrich Drepper <drepper@myware>
+
+ * whoami.c, system.h, printf.h, printf-parse.h, hash.h, hash.c,
+ getline.h, fstrcmp.h, fstrcmp.c, error.h, error.c:
+ Use PARAMS instead of __P. Suggested by Roland McGrath.
+
+Wed Dec 6 16:07:27 1995 ghazi@caip.rutgers.edu <Kaveh R. Ghazi>
+
+ * system.h: Fix alloca declaration so that it matches the one
+ generated by bison on HPUX.
+
+Sat Nov 25 16:13:50 1995 Ulrich Drepper <drepper@myware>
+
+ * whoami.c: Don't use #ifdef, prefer #if.
+
+ * error.c: Capitalize arguments of macros. Patch by Franc,ois Pinard.
+
+Thu Nov 16 22:41:32 1995 Ulrich Drepper <drepper@myware>
+
+ * whoami.c: Correct prototype declarations.
+
+ * xmalloc.c: Include "error.h" instead of defining error ourself.
+
+ * system.h: Include <stdio.h> to get FILE definition.
+
+ * hash.c: Peter Miller suggested not to use `div' as a variable name.
+
+ * error.c (error_print_progname): For ANSI C provide complete type.
+ Include error.h. Patches by Peter Miller.
+
+Sun Nov 12 12:34:12 1995 Ulrich Drepper <drepper@myware>
+
+ * whoami.c: Add prototypes.
+ (get_submitter): Use stpcpy if available.
+
+Sat Nov 11 00:26:31 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (HEADERS):
+ Add missing pathmax.h file. Reported by Franc,ois Pinard.
+
+Fri Nov 10 09:59:06 1995 Ulrich Drepper <drepper@myware>
+
+ * error.h (error_print_progname):
+ Provide real prototype, i.e. with argument types.
+ Patch by Peter Miller.
+
+Wed Nov 8 23:25:00 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h: Add prototype for xgetcwd.
+
+ * Makefile.in (SOURCES): Add xgetcwd.c.
+ (OBJECTS): Add xgetcwd.o.
+
+Tue Nov 7 11:44:32 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (intldir):
+ New variable. Use its value instead of ../intl.
+
+Sun Nov 5 19:40:03 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (dist-gettext): Make synonym for dist.
+
+Sun Nov 5 18:04:11 1995 Ulrich Drepper <drepper@myware>
+
+ * hash.c (find_entry): Remove unused variable retval.
+
+Sun Nov 5 11:38:19 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (dist): Suppress error message when ln failed.
+ Get files from $(srcdir) explicitly.
+
+Sat Oct 28 14:25:13 1995 Ulrich Drepper <drepper@myware>
+
+ * fstrcmp.c:
+ Revised version by Peter Miller. Now based on GNU diff's version
+ of this algorithm.
+
+Wed Sep 27 20:18:44 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h: Include sys/types.h for those old SysV systems out there.
+ Reported by Francesco Potorti`.
+
+Mon Sep 25 22:26:28 1995 Ulrich Drepper <drepper@myware>
+
+ * obstack.h (ptrdiff_t):
+ Don't define unless HAVE_PTRDIFF_T is not defined. This
+ solves problems with Sun's compiler. Reported by Marcus Daniels.
+
+Mon Sep 18 10:45:48 1995 Ulrich Drepper <drepper@myware>
+
+ * fstrcmp.h, fstrcmp.c: Initial revision
+
+Sun Sep 17 23:37:15 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in: Add fstrcmp.[ch] to libgettext.
+
+ * system.h (open_po_file): Remove unused `use_path' parameter.
+
+ * hash.c:
+ Rewrite for uniform return values: < 0 for error cases, else >= 0.
+
+ * Makefile.in: hash.[ch] moved from src/ to lib/ subdirectory.
+
+Mon Aug 28 10:05:31 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in: Remove Emacs hints.
+
+ * Makefile.in (libnlsut.a): Use $@ instead of full name.
+
+Sat Aug 19 17:37:24 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (install-src): Make depend on `all'.
+
+Tue Aug 15 05:51:25 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h (xgetcwd): Remove prototype.
+
+Mon Aug 14 23:52:41 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (install-src): New no-op goal.
+
+Wed Aug 9 10:05:09 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h (MAX):
+ Mark GCC variant with __extension__ and change typeof to __typeof__.
+
+Tue Aug 8 21:02:28 1995 Ulrich Drepper <drepper@myware>
+
+ * strcasecmp.c: Initial revision.
+
+ * Makefile.in (SOURCES): Add strcasecmp.c.
+
+Mon Aug 7 21:17:51 1995 Ulrich Drepper <drepper@myware>
+
+ * strcspn.c: Initial revision.
+
+ * Makefile.in (SOURCES): Add strcspn.c.
+
+Fri Aug 4 15:44:00 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (dist): Remove `copying instead' message.
+
+Wed Aug 2 18:51:33 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (ID, TAGS): Do not use $^.
+
+Tue Aug 1 20:07:40 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (distclean): Remove ID file.
+
+ * Makefile.in (TAGS, ID): Use $^ as command argument.
+ (TAGS): Give etags -o option t write to current directory,
+ not $(srcdir).
+ (ID): Use $(srcdir) instead os $(top_srcdir)/src.
+
+Wed Jul 19 23:54:32 1995 Ulrich Drepper <drepper@myware>
+
+ * strtol.c: Change copyright from LGPL to GPL.
+
+Tue Jul 18 20:09:04 1995 Ulrich Drepper <drepper@myware>
+
+ * strtol.c (ULONG_MAX): Define if not defined in system header.
+ Reported by Francesco Potorti`.
+
+ * printf-parse.h (parse_one_spec): Define prototype.
+
+ * obstack.h: Put stddef.h include statement back in.
+
+Tue Jul 18 00:19:54 1995 Ulrich Drepper <drepper@myware>
+
+ * vasprintf.c, strtol.c, obstack.c, getopt1.c, getopt.c, system.h,
+ printf.h, obstack.h, getline.h: Uniform test for __STDC__.
+
+Mon Jul 17 01:13:09 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h (HAVE_MALLOC_H):
+ Remove obsolete #else case. Was needed when we tried
+ to define free ourself.
+
+ * system.h, error.h, strtoul.c, printf-parse.h, memmove.c,
+ getline.h: Add `Free' to Software Foundation.
+
+ * getline.h:
+ Remove unneeded comment after #endif. We now use indentation.
+
+ * getline.c: Indent preprocessor directives.
+
+ * strtol.c (NULL): Define manualy if not defined in any included file.
+
+Sat Jul 15 23:59:26 1995 Ulrich Drepper <drepper@myware>
+
+ * obstack.h: Add accidently removed #endif.
+
+Sat Jul 15 23:31:45 1995 Ulrich Drepper <drepper@myware>
+
+ * vasprintf.c, printf-prs.c, obstack.h, obstack.c, memmove.c,
+ printf.h, printf-parse.h:
+ Exchange old LGPL against new GPL (no LGPL code in normal packages).
+
+ * getline.h: Add copyright.
+
+ * strtoul.c, strtol.c: Initial revision
+
+ * obstack.h (ptrdiff_t):
+ Don't include stddef.h. Try to get it with sys/types.h and
+ if _PTRDIFF_T and ptrdiff_t are not defined, define it to off_t
+ (which is at least defined in config.h).
+
+ * system.h (HAVE_STDLIB_H):
+ Is not useful if STDC_HEADERS is not also defined.
+
+Sat Jul 15 00:49:22 1995 Ulrich Drepper <drepper@myware>
+
+ * error.h: Correct definition of size_t: don't try to include
+ stddef.h, but instead use sys/types. If it is not found here,
+ the config.h file will define it.
+
+ * system.h: Load <stdlib.h> before defining prototypes. This
+ avoids problems with size_t not defined in the prototypes.
+
+ * printf-parse.h (find_spec): Handle missing mblen function.
+
+Thu Jul 13 22:28:38 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h (MAX):
+ Move definition to end to reduce possibility of redefinition.
+
+ * whoami.c (get_username, get_hostname, get_submitter):
+ Use K&R prototypes.
+
+ * vasprintf.c: Include config.h.
+
+ * printf.h (printf_info):
+ Use `char' and `unsigned' instead of `unsigned char' and
+ `unsigned int' resp. to help these dumb K&R compilers.
+
+ * printf-parse.h:
+ Compilers other than GCC don't have `long long', K&R compiler
+ even don't have `long double'.
+
+Thu Jul 13 01:41:41 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (check): New goal.
+
+Tue Jul 11 21:37:19 1995 Ulrich Drepper <drepper@myware>
+
+ * vasprintf.c (HAVE_STRTOUL):
+ Not needed anymore because we substitute strtoul if not present.
+
+Tue Jul 11 01:34:06 1995 Ulrich Drepper <drepper@myware>
+
+ * whoami.c: Define NULL is necessary.
+
+ * obstack.h: Protect inclusion of stddef and define ptrdiff_t if
+ necessary.
+
+ * memmove.c: Include sys/types.h and perhaps stdlib.h instead of
+ stddef.h for getting size_t defined.
+
+ * system.h: Don't define free, qsort, and strtol when no header
+ file is available.
+ Define EXIT_{FAILURE,SUCCESS} after stdlib.h is included.
+
+ * printf.h: Protect non-ANSI header inclusion.
+ Protect __P definition.
+ Don't use __const in prototypes.
+
+ * printf-prs.c: Include config.h.
+ Protect stdlib.h inclusion.
+
+ * printf-parse.h: Protect header inclusion for non-ANSI environments.
+ Protect and de-GCC-ify MAX/MIN definition.
+
+ * Makefile.in (SOURCES): New files: strtol.c and strtoul.c.
+ Depend $(OBJECT) on config.h,, instead of $(LIBOBJS).
+ Better dependency for printf-prs.o.
+
+Tue Jul 4 22:09:00 1995 Ulrich Drepper <drepper@myware>
+
+ * Makefile.in (SOURCES): add memmove.c.
+
+ * memmove.c: Initial revision.
+
+ * error.h: Make size_t definition correct for !__STDC__.
+ Include <stddef.h> for getting size_t defined.
+
+ * vasprintf.c: Don't use strtoul if !HAVE_STRTOUL.
+
+ * system.h: Include <stdlib.h> also if defined HAVE_STDLIB_H.
+ Make sure that qsort, free and strtoul are prototyped.
+
+Mon Jul 3 15:02:50 1995 Ulrich Drepper <drepper@myware>
+
+ * system.h: system.h (MAX): don't use GCC feature if !__STDC__.
+ Fix typo in EXIT_FAILURE defintion.
+
+ * xmalloc.c: Include prototype for calloc.c.
+
+ * Makefile.in (INCLUDES): even better path list.
+ (INCLUDES): remove unnecessary paths.
+ Correct path to original version.
+
+Sun Jul 2 02:01:43 1995 Ulrich Drepper <drepper@myware>
+
+ * First official release. This directory contains supplementary
+ code taken from GNU C Library and other package's lib/
+ directories.
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..3cab0b0
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,36 @@
+## Makefile for the support lib subdirectory of the GNU NLS Utilities
+## Copyright (C) 1995, 1996, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+## Process this file with automake to produce Makefile.in.
+
+AUTOMAKE_OPTIONS = 1.2 gnits
+
+noinst_LIBRARIES = libnlsut.a
+
+EXTRA_DIST = alloca.c error.c getline.c memset.c memmove.c \
+printf-prs.c stpcpy.c stpncpy.c strcasecmp.c strcspn.c strncasecmp.c \
+strstr.c strtol.c strtoul.c vasprintf.c
+
+libnlsut_a_SOURCES = basename.c fstrcmp.c getopt.c getopt1.c hash.c obstack.c \
+xgetcwd.c xmalloc.c xstrdup.c
+
+libnlsut_a_LIBADD = @ALLOCA@ @LIBOBJS@
+
+noinst_HEADERS = error.h fstrcmp.h getline.h getopt.h hash.h obstack.h \
+printf-parse.h printf.h system.h pathmax.h
+
+INCLUDES = -I../intl
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..49b8fe2
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,371 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+ACLOCAL_VERSION = @ACLOCAL_VERSION@
+AS = @AS@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+DATADIRNAME = @DATADIRNAME@
+DLLTOOL = @DLLTOOL@
+EMACS = @EMACS@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LIBOBJS = @LIBOBJS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+aclocaldir = @aclocaldir@
+l = @l@
+lispdir = @lispdir@
+
+AUTOMAKE_OPTIONS = 1.2 gnits
+
+noinst_LIBRARIES = libnlsut.a
+
+EXTRA_DIST = alloca.c error.c getline.c memset.c memmove.c printf-prs.c stpcpy.c stpncpy.c strcasecmp.c strcspn.c strncasecmp.c strstr.c strtol.c strtoul.c vasprintf.c
+
+
+libnlsut_a_SOURCES = basename.c fstrcmp.c getopt.c getopt1.c hash.c obstack.c xgetcwd.c xmalloc.c xstrdup.c
+
+
+libnlsut_a_LIBADD = @ALLOCA@ @LIBOBJS@
+
+noinst_HEADERS = error.h fstrcmp.h getline.h getopt.h hash.h obstack.h printf-parse.h printf.h system.h pathmax.h
+
+
+INCLUDES = -I../intl
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libnlsut_a_DEPENDENCIES = @ALLOCA@ @LIBOBJS@
+libnlsut_a_OBJECTS = basename.o fstrcmp.o getopt.o getopt1.o hash.o \
+obstack.o xgetcwd.o xmalloc.o xstrdup.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = ChangeLog Makefile.am Makefile.in alloca.c error.c \
+error.h getline.c memmove.c memset.c printf-prs.c stpcpy.c stpncpy.c \
+strcspn.c strncasecmp.c strstr.c strtoul.c vasprintf.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES = .deps/alloca.P .deps/basename.P .deps/error.P \
+.deps/fstrcmp.P .deps/getline.P .deps/getopt.P .deps/getopt1.P \
+.deps/hash.P .deps/memmove.P .deps/memset.P .deps/obstack.P \
+.deps/printf-prs.P .deps/stpcpy.P .deps/stpncpy.P .deps/strcspn.P \
+.deps/strncasecmp.P .deps/strstr.P .deps/strtoul.P .deps/vasprintf.P \
+.deps/xgetcwd.P .deps/xmalloc.P .deps/xstrdup.P
+SOURCES = $(libnlsut_a_SOURCES)
+OBJECTS = $(libnlsut_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnits lib/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libnlsut.a: $(libnlsut_a_OBJECTS) $(libnlsut_a_DEPENDENCIES)
+ -rm -f libnlsut.a
+ $(AR) cru libnlsut.a $(libnlsut_a_OBJECTS) $(libnlsut_a_LIBADD)
+ $(RANLIB) libnlsut.a
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnits lib/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLIBRARIES clean-compile clean-libtool clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/alloca.c b/lib/alloca.c
new file mode 100644
index 0000000..d2f7f0c
--- /dev/null
+++ b/lib/alloca.c
@@ -0,0 +1,513 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+/* Synched up with: FSF 19.30. */
+
+/* Authorsip:
+
+ FSF: A long time ago.
+ Very few changes for XEmacs.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* XEmacs: If compiling with GCC 2, this file is theoretically not needed.
+ However, alloca() is broken under GCC 2 on many machines: you
+ cannot put a call to alloca() as part of an argument to a function.
+ */
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+/* XEmacs sometimes uses the C alloca even when a builtin alloca is available,
+ because it's safer. */
+#if defined (EMACS_WANTS_C_ALLOCA) || (!defined (alloca) && (!defined (__GNUC__) || __GNUC__ < 2))
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#ifdef __STDC__ /* XEmacs change */
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+/* XEmacs: With ERROR_CHECK_MALLOC defined, there is no xfree -- it's
+ a macro that does some stuff to try and trap invalid frees,
+ and then calls xfree_1 to actually do the work. */
+
+#ifdef emacs
+# ifdef ERROR_CHECK_MALLOC
+void xfree_1 (pointer);
+# define xfree xfree_1
+# else
+void xfree (pointer);
+# endif
+#endif
+
+#ifndef WINDOWSNT
+#define NULL 0
+#endif
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+#ifndef WINDOWSNT
+extern pointer malloc ();
+#else
+extern void *malloc();
+#endif
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+#ifdef EMACS_WANTS_C_ALLOCA
+c_alloca (size)
+#else
+alloca (size)
+#endif
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ REGISTER char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ REGISTER header *hp; /* Traverses linked list. */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ REGISTER header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ REGISTER pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* complicated expression at top of file */
diff --git a/lib/basename.c b/lib/basename.c
new file mode 100644
index 0000000..52ecb51
--- /dev/null
+++ b/lib/basename.c
@@ -0,0 +1,41 @@
+/* Return the name-within-directory of a file name.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#ifndef _LIBC
+/* We cannot generally use the name `basename' since XPG defines an unusable
+ variant of the function but we cannot use it. */
+# define basename gnu_basename
+#endif
+
+
+char *
+basename (filename)
+ const char *filename;
+{
+ char *p = strrchr (filename, '/');
+ return p ? p + 1 : (char *) filename;
+}
diff --git a/lib/error.c b/lib/error.c
new file mode 100644
index 0000000..140fa77
--- /dev/null
+++ b/lib/error.c
@@ -0,0 +1,248 @@
+/* Error handler for noninteractive utilities
+ Copyright (C) 1990,91,92,93,94,95,96,97,98 Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
+# if __STDC__
+# include <stdarg.h>
+# define VA_START(args, lastarg) va_start(args, lastarg)
+# else
+# include <varargs.h>
+# define VA_START(args, lastarg) va_start(args)
+# endif
+#else
+# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#if STDC_HEADERS || _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+void exit ();
+#endif
+
+#include "error.h"
+
+#ifndef _
+# define _(String) String
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+void (*error_print_progname) (
+#if __STDC__ - 0
+ void
+#endif
+ );
+
+/* This variable is incremented each time `error' is called. */
+unsigned int error_message_count;
+
+#ifdef _LIBC
+/* In the GNU C library, there is a predefined variable for this. */
+
+# define program_name program_invocation_name
+# include <errno.h>
+
+/* In GNU libc we want do not want to use the common name `error' directly.
+ Instead make it a weak alias. */
+# define error __error
+# define error_at_line __error_at_line
+
+#else /* not _LIBC */
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+# ifdef HAVE_STRERROR_R
+# define __strerror_r strerror_r
+# else
+# if HAVE_STRERROR
+# ifndef strerror /* On some systems, strerror is a macro */
+char *strerror ();
+# endif
+# else
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return _(sys_errlist[errnum]);
+ return _("Unknown system error");
+}
+# define strerror private_strerror
+# endif /* HAVE_STRERROR */
+# endif /* HAVE_STRERROR_R */
+#endif /* not _LIBC */
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+
+void
+#if defined VA_START && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s: ", program_name);
+ }
+
+#ifdef VA_START
+ VA_START (args, message);
+# if HAVE_VPRINTF || _LIBC
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ ++error_message_count;
+ if (errnum)
+ {
+#if defined HAVE_STRERROR_R || defined _LIBC
+ char errbuf[1024];
+ fprintf (stderr, ": %s", __strerror_r (errnum, errbuf, sizeof errbuf));
+#else
+ fprintf (stderr, ": %s", strerror (errnum));
+#endif
+ }
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+int error_one_per_line;
+
+void
+#if defined VA_START && __STDC__
+error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message, ...)
+#else
+error_at_line (status, errnum, file_name, line_number, message, va_alist)
+ int status;
+ int errnum;
+ const char *file_name;
+ unsigned int line_number;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ if (error_one_per_line)
+ {
+ static const char *old_file_name;
+ static unsigned int old_line_number;
+
+ if (old_line_number == line_number &&
+ (file_name == old_file_name || !strcmp (old_file_name, file_name)))
+ /* Simply return and print nothing. */
+ return;
+
+ old_file_name = file_name;
+ old_line_number = line_number;
+ }
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s:", program_name);
+ }
+
+ if (file_name != NULL)
+ fprintf (stderr, "%s:%d: ", file_name, line_number);
+
+#ifdef VA_START
+ VA_START (args, message);
+# if HAVE_VPRINTF || _LIBC
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ ++error_message_count;
+ if (errnum)
+ {
+#if defined HAVE_STRERROR_R || defined _LIBC
+ char errbuf[1024];
+ fprintf (stderr, ": %s", __strerror_r (errnum, errbuf, sizeof errbuf));
+#else
+ fprintf (stderr, ": %s", strerror (errnum));
+#endif
+ }
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
+
+#ifdef _LIBC
+/* Make the weak alias. */
+# undef error
+# undef error_at_line
+weak_alias (__error, error)
+weak_alias (__error_at_line, error_at_line)
+#endif
diff --git a/lib/error.h b/lib/error.h
new file mode 100644
index 0000000..20f7582
--- /dev/null
+++ b/lib/error.h
@@ -0,0 +1,78 @@
+/* Declaration for error-reporting function
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifndef _ERROR_H
+#define _ERROR_H 1
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__STDC__) && __STDC__
+
+/* Print a message with `fprintf (stderr, FORMAT, ...)';
+ if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
+ If STATUS is nonzero, terminate the program with `exit (STATUS)'. */
+
+extern void error (int status, int errnum, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+extern void error_at_line (int status, int errnum, const char *fname,
+ unsigned int lineno, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+extern void (*error_print_progname) (void);
+
+#else
+void error ();
+void error_at_line ();
+extern void (*error_print_progname) ();
+#endif
+
+/* This variable is incremented each time `error' is called. */
+extern unsigned int error_message_count;
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+extern int error_one_per_line;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* error.h */
diff --git a/lib/fstrcmp.c b/lib/fstrcmp.c
new file mode 100644
index 0000000..b1f5971
--- /dev/null
+++ b/lib/fstrcmp.c
@@ -0,0 +1,636 @@
+/* Functions to make fuzzy comparisons between strings
+ Copyright (C) 1988, 1989, 1992, 1993, 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 of the License, 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.
+
+
+ Derived from GNU diff 2.7, analyze.c et al.
+
+ The basic algorithm is described in:
+ "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
+ Algorithmica Vol. 1 No. 2, 1986, pp. 251-266;
+ see especially section 4.2, which describes the variation used below.
+
+ The basic algorithm was independently discovered as described in:
+ "Algorithms for Approximate String Matching", E. Ukkonen,
+ Information and Control Vol. 64, 1985, pp. 100-118.
+
+ Modified to work on strings rather than files
+ by Peter Miller <pmiller@agso.gov.au>, October 1995 */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#else
+# define INT_MAX ((int)(~(unsigned)0 >> 1))
+#endif
+
+#include "system.h"
+#include "fstrcmp.h"
+
+
+/*
+ * Data on one input string being compared.
+ */
+struct string_data
+{
+ /* The string to be compared. */
+ const char *data;
+
+ /* The length of the string to be compared. */
+ int data_length;
+
+ /* The number of characters inserted or deleted. */
+ int edit_count;
+};
+
+static struct string_data string[2];
+
+
+#ifdef MINUS_H_FLAG
+
+/* This corresponds to the diff -H flag. With this heuristic, for
+ strings with a constant small density of changes, the algorithm is
+ linear in the strings size. This is unlikely in typical uses of
+ fstrcmp, and so is usually compiled out. Besides, there is no
+ interface to set it true. */
+static int heuristic;
+
+#endif
+
+
+/* Vector, indexed by diagonal, containing 1 + the X coordinate of the
+ point furthest along the given diagonal in the forward search of the
+ edit matrix. */
+static int *fdiag;
+
+/* Vector, indexed by diagonal, containing the X coordinate of the point
+ furthest along the given diagonal in the backward search of the edit
+ matrix. */
+static int *bdiag;
+
+/* Edit scripts longer than this are too expensive to compute. */
+static int too_expensive;
+
+/* Snakes bigger than this are considered `big'. */
+#define SNAKE_LIMIT 20
+
+struct partition
+{
+ /* Midpoints of this partition. */
+ int xmid, ymid;
+
+ /* Nonzero if low half will be analyzed minimally. */
+ int lo_minimal;
+
+ /* Likewise for high half. */
+ int hi_minimal;
+};
+
+
+/* NAME
+ diag - find diagonal path
+
+ SYNOPSIS
+ int diag(int xoff, int xlim, int yoff, int ylim, int minimal,
+ struct partition *part);
+
+ DESCRIPTION
+ Find the midpoint of the shortest edit script for a specified
+ portion of the two strings.
+
+ Scan from the beginnings of the strings, and simultaneously from
+ the ends, doing a breadth-first search through the space of
+ edit-sequence. When the two searches meet, we have found the
+ midpoint of the shortest edit sequence.
+
+ If MINIMAL is nonzero, find the minimal edit script regardless
+ of expense. Otherwise, if the search is too expensive, use
+ heuristics to stop the search and report a suboptimal answer.
+
+ RETURNS
+ Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal
+ number XMID - YMID equals the number of inserted characters
+ minus the number of deleted characters (counting only characters
+ before the midpoint). Return the approximate edit cost; this is
+ the total number of characters inserted or deleted (counting
+ only characters before the midpoint), unless a heuristic is used
+ to terminate the search prematurely.
+
+ Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script
+ for the left half of the partition is known; similarly for
+ PART->RIGHT_MINIMAL.
+
+ CAVEAT
+ This function assumes that the first characters of the specified
+ portions of the two strings do not match, and likewise that the
+ last characters do not match. The caller must trim matching
+ characters from the beginning and end of the portions it is
+ going to specify.
+
+ If we return the "wrong" partitions, the worst this can do is
+ cause suboptimal diff output. It cannot cause incorrect diff
+ output. */
+
+static int diag PARAMS ((int, int, int, int, int, struct partition *));
+
+static int
+diag (xoff, xlim, yoff, ylim, minimal, part)
+ int xoff;
+ int xlim;
+ int yoff;
+ int ylim;
+ int minimal;
+ struct partition *part;
+{
+ int *const fd = fdiag; /* Give the compiler a chance. */
+ int *const bd = bdiag; /* Additional help for the compiler. */
+ const char *const xv = string[0].data; /* Still more help for the compiler. */
+ const char *const yv = string[1].data; /* And more and more . . . */
+ const int dmin = xoff - ylim; /* Minimum valid diagonal. */
+ const int dmax = xlim - yoff; /* Maximum valid diagonal. */
+ const int fmid = xoff - yoff; /* Center diagonal of top-down search. */
+ const int bmid = xlim - ylim; /* Center diagonal of bottom-up search. */
+ int fmin = fmid;
+ int fmax = fmid; /* Limits of top-down search. */
+ int bmin = bmid;
+ int bmax = bmid; /* Limits of bottom-up search. */
+ int c; /* Cost. */
+ int odd = (fmid - bmid) & 1;
+
+ /*
+ * True if southeast corner is on an odd diagonal with respect
+ * to the northwest.
+ */
+ fd[fmid] = xoff;
+ bd[bmid] = xlim;
+ for (c = 1;; ++c)
+ {
+ int d; /* Active diagonal. */
+ int big_snake;
+
+ big_snake = 0;
+ /* Extend the top-down search by an edit step in each diagonal. */
+ if (fmin > dmin)
+ fd[--fmin - 1] = -1;
+ else
+ ++fmin;
+ if (fmax < dmax)
+ fd[++fmax + 1] = -1;
+ else
+ --fmax;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x;
+ int y;
+ int oldx;
+ int tlo;
+ int thi;
+
+ tlo = fd[d - 1],
+ thi = fd[d + 1];
+
+ if (tlo >= thi)
+ x = tlo + 1;
+ else
+ x = thi;
+ oldx = x;
+ y = x - d;
+ while (x < xlim && y < ylim && xv[x] == yv[y])
+ {
+ ++x;
+ ++y;
+ }
+ if (x - oldx > SNAKE_LIMIT)
+ big_snake = 1;
+ fd[d] = x;
+ if (odd && bmin <= d && d <= bmax && bd[d] <= x)
+ {
+ part->xmid = x;
+ part->ymid = y;
+ part->lo_minimal = part->hi_minimal = 1;
+ return 2 * c - 1;
+ }
+ }
+ /* Similarly extend the bottom-up search. */
+ if (bmin > dmin)
+ bd[--bmin - 1] = INT_MAX;
+ else
+ ++bmin;
+ if (bmax < dmax)
+ bd[++bmax + 1] = INT_MAX;
+ else
+ --bmax;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x;
+ int y;
+ int oldx;
+ int tlo;
+ int thi;
+
+ tlo = bd[d - 1],
+ thi = bd[d + 1];
+ if (tlo < thi)
+ x = tlo;
+ else
+ x = thi - 1;
+ oldx = x;
+ y = x - d;
+ while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
+ {
+ --x;
+ --y;
+ }
+ if (oldx - x > SNAKE_LIMIT)
+ big_snake = 1;
+ bd[d] = x;
+ if (!odd && fmin <= d && d <= fmax && x <= fd[d])
+ {
+ part->xmid = x;
+ part->ymid = y;
+ part->lo_minimal = part->hi_minimal = 1;
+ return 2 * c;
+ }
+ }
+
+ if (minimal)
+ continue;
+
+#ifdef MINUS_H_FLAG
+ /* Heuristic: check occasionally for a diagonal that has made lots
+ of progress compared with the edit distance. If we have any
+ such, find the one that has made the most progress and return
+ it as if it had succeeded.
+
+ With this heuristic, for strings with a constant small density
+ of changes, the algorithm is linear in the strings size. */
+ if (c > 200 && big_snake && heuristic)
+ {
+ int best;
+
+ best = 0;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int dd;
+ int x;
+ int y;
+ int v;
+
+ dd = d - fmid;
+ x = fd[d];
+ y = x - d;
+ v = (x - xoff) * 2 - dd;
+
+ if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+ {
+ if
+ (
+ v > best
+ &&
+ xoff + SNAKE_LIMIT <= x
+ &&
+ x < xlim
+ &&
+ yoff + SNAKE_LIMIT <= y
+ &&
+ y < ylim
+ )
+ {
+ /* We have a good enough best diagonal; now insist
+ that it end with a significant snake. */
+ int k;
+
+ for (k = 1; xv[x - k] == yv[y - k]; k++)
+ {
+ if (k == SNAKE_LIMIT)
+ {
+ best = v;
+ part->xmid = x;
+ part->ymid = y;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ part->lo_minimal = 1;
+ part->hi_minimal = 0;
+ return 2 * c - 1;
+ }
+ best = 0;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int dd;
+ int x;
+ int y;
+ int v;
+
+ dd = d - bmid;
+ x = bd[d];
+ y = x - d;
+ v = (xlim - x) * 2 + dd;
+
+ if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+ {
+ if (v > best && xoff < x && x <= xlim - SNAKE_LIMIT &&
+ yoff < y && y <= ylim - SNAKE_LIMIT)
+ {
+ /* We have a good enough best diagonal; now insist
+ that it end with a significant snake. */
+ int k;
+
+ for (k = 0; xv[x + k] == yv[y + k]; k++)
+ {
+ if (k == SNAKE_LIMIT - 1)
+ {
+ best = v;
+ part->xmid = x;
+ part->ymid = y;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ part->lo_minimal = 0;
+ part->hi_minimal = 1;
+ return 2 * c - 1;
+ }
+ }
+#endif /* MINUS_H_FLAG */
+
+ /* Heuristic: if we've gone well beyond the call of duty, give up
+ and report halfway between our best results so far. */
+ if (c >= too_expensive)
+ {
+ int fxybest;
+ int fxbest;
+ int bxybest;
+ int bxbest;
+
+ /* Pacify `gcc -Wall'. */
+ fxbest = 0;
+ bxbest = 0;
+
+ /* Find forward diagonal that maximizes X + Y. */
+ fxybest = -1;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x;
+ int y;
+
+ x = fd[d] < xlim ? fd[d] : xlim;
+ y = x - d;
+
+ if (ylim < y)
+ {
+ x = ylim + d;
+ y = ylim;
+ }
+ if (fxybest < x + y)
+ {
+ fxybest = x + y;
+ fxbest = x;
+ }
+ }
+ /* Find backward diagonal that minimizes X + Y. */
+ bxybest = INT_MAX;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x;
+ int y;
+
+ x = xoff > bd[d] ? xoff : bd[d];
+ y = x - d;
+
+ if (y < yoff)
+ {
+ x = yoff + d;
+ y = yoff;
+ }
+ if (x + y < bxybest)
+ {
+ bxybest = x + y;
+ bxbest = x;
+ }
+ }
+ /* Use the better of the two diagonals. */
+ if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff))
+ {
+ part->xmid = fxbest;
+ part->ymid = fxybest - fxbest;
+ part->lo_minimal = 1;
+ part->hi_minimal = 0;
+ }
+ else
+ {
+ part->xmid = bxbest;
+ part->ymid = bxybest - bxbest;
+ part->lo_minimal = 0;
+ part->hi_minimal = 1;
+ }
+ return 2 * c - 1;
+ }
+ }
+}
+
+
+/* NAME
+ compareseq - find edit sequence
+
+ SYNOPSIS
+ void compareseq(int xoff, int xlim, int yoff, int ylim, int minimal);
+
+ DESCRIPTION
+ Compare in detail contiguous subsequences of the two strings
+ which are known, as a whole, to match each other.
+
+ The subsequence of string 0 is [XOFF, XLIM) and likewise for
+ string 1.
+
+ Note that XLIM, YLIM are exclusive bounds. All character
+ numbers are origin-0.
+
+ If MINIMAL is nonzero, find a minimal difference no matter how
+ expensive it is. */
+
+static void compareseq PARAMS ((int, int, int, int, int));
+
+static void
+compareseq (xoff, xlim, yoff, ylim, minimal)
+ int xoff;
+ int xlim;
+ int yoff;
+ int ylim;
+ int minimal;
+{
+ const char *const xv = string[0].data; /* Help the compiler. */
+ const char *const yv = string[1].data;
+
+ /* Slide down the bottom initial diagonal. */
+ while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff])
+ {
+ ++xoff;
+ ++yoff;
+ }
+
+ /* Slide up the top initial diagonal. */
+ while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1])
+ {
+ --xlim;
+ --ylim;
+ }
+
+ /* Handle simple cases. */
+ if (xoff == xlim)
+ {
+ while (yoff < ylim)
+ {
+ ++string[1].edit_count;
+ ++yoff;
+ }
+ }
+ else if (yoff == ylim)
+ {
+ while (xoff < xlim)
+ {
+ ++string[0].edit_count;
+ ++xoff;
+ }
+ }
+ else
+ {
+ int c;
+ struct partition part;
+
+ /* Find a point of correspondence in the middle of the strings. */
+ c = diag (xoff, xlim, yoff, ylim, minimal, &part);
+ if (c == 1)
+ {
+#if 0
+ /* This should be impossible, because it implies that one of
+ the two subsequences is empty, and that case was handled
+ above without calling `diag'. Let's verify that this is
+ true. */
+ abort ();
+#else
+ /* The two subsequences differ by a single insert or delete;
+ record it and we are done. */
+ if (part.xmid - part.ymid < xoff - yoff)
+ ++string[1].edit_count;
+ else
+ ++string[0].edit_count;
+#endif
+ }
+ else
+ {
+ /* Use the partitions to split this problem into subproblems. */
+ compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal);
+ compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal);
+ }
+ }
+}
+
+
+/* NAME
+ fstrcmp - fuzzy string compare
+
+ SYNOPSIS
+ double fstrcmp(const char *, const char *);
+
+ DESCRIPTION
+ The fstrcmp function may be used to compare two string for
+ similarity. It is very useful in reducing "cascade" or
+ "secondary" errors in compilers or other situations where
+ symbol tables occur.
+
+ RETURNS
+ double; 0 if the strings are entirly dissimilar, 1 if the
+ strings are identical, and a number in between if they are
+ similar. */
+
+double
+fstrcmp (string1, string2)
+ const char *string1;
+ const char *string2;
+{
+ int i;
+
+ size_t fdiag_len;
+ static int *fdiag_buf;
+ static size_t fdiag_max;
+
+ /* set the info for each string. */
+ string[0].data = string1;
+ string[0].data_length = strlen (string1);
+ string[1].data = string2;
+ string[1].data_length = strlen (string2);
+
+ /* short-circuit obvious comparisons */
+ if (string[0].data_length == 0 && string[1].data_length == 0)
+ return 1.0;
+ if (string[0].data_length == 0 || string[1].data_length == 0)
+ return 0.0;
+
+ /* Set TOO_EXPENSIVE to be approximate square root of input size,
+ bounded below by 256. */
+ too_expensive = 1;
+ for (i = string[0].data_length + string[1].data_length; i != 0; i >>= 2)
+ too_expensive <<= 1;
+ if (too_expensive < 256)
+ too_expensive = 256;
+
+ /* Because fstrcmp is typically called multiple times, while scanning
+ symbol tables, etc, attempt to minimize the number of memory
+ allocations performed. Thus, we use a static buffer for the
+ diagonal vectors, and never free them. */
+ fdiag_len = string[0].data_length + string[1].data_length + 3;
+ if (fdiag_len > fdiag_max)
+ {
+ fdiag_max = fdiag_len;
+ fdiag_buf = xrealloc (fdiag_buf, fdiag_max * (2 * sizeof (int)));
+ }
+ fdiag = fdiag_buf + string[1].data_length + 1;
+ bdiag = fdiag + fdiag_len;
+
+ /* Now do the main comparison algorithm */
+ string[0].edit_count = 0;
+ string[1].edit_count = 0;
+ compareseq (0, string[0].data_length, 0, string[1].data_length, 0);
+
+ /* The result is
+ ((number of chars in common) / (average length of the strings)).
+ This is admittedly biased towards finding that the strings are
+ similar, however it does produce meaningful results. */
+ return ((double) (string[0].data_length + string[1].data_length -
+ string[1].edit_count - string[0].edit_count) / (string[0].data_length
+ + string[1].data_length));
+}
diff --git a/lib/fstrcmp.h b/lib/fstrcmp.h
new file mode 100644
index 0000000..0404717
--- /dev/null
+++ b/lib/fstrcmp.h
@@ -0,0 +1,25 @@
+/* GNU gettext - internationalization aids
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ This file was written by Peter Miller <pmiller@agso.gov.au>
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _FSTRCMP_H
+#define _FSTRCMP_H
+
+double fstrcmp PARAMS ((const char *__s1, const char *__s2));
+
+#endif
diff --git a/lib/getline.c b/lib/getline.c
new file mode 100644
index 0000000..ba05abb
--- /dev/null
+++ b/lib/getline.c
@@ -0,0 +1,155 @@
+/* getline.c -- Replacement for GNU C library function getline
+
+Copyright (C) 1993, 1996 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 of the
+License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* The `getdelim' function is only declared if the following symbol
+ is defined. */
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined __GNU_LIBRARY__ && HAVE_GETDELIM
+
+int
+getline (lineptr, n, stream)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+{
+ return getdelim (lineptr, n, '\n', stream);
+}
+
+
+#else /* ! have getdelim */
+
+# define NDEBUG
+# include <assert.h>
+
+# if STDC_HEADERS
+# include <stdlib.h>
+# else
+char *malloc (), *realloc ();
+# endif
+
+/* Always add at least this many bytes when extending the buffer. */
+# define MIN_CHUNK 64
+
+/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+ + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
+ malloc (or NULL), pointing to *N characters of space. It is realloc'd
+ as necessary. Return the number of characters read (not including the
+ null terminator), or -1 on error or EOF. */
+
+int
+getstr (lineptr, n, stream, terminator, offset)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+ char terminator;
+ size_t offset;
+{
+ int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ int ret;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+
+ if (!*lineptr)
+ {
+ *n = MIN_CHUNK;
+ *lineptr = malloc (*n);
+ if (!*lineptr)
+ return -1;
+ }
+
+ nchars_avail = *n - offset;
+ read_pos = *lineptr + offset;
+
+ for (;;)
+ {
+ register int c = getc (stream);
+
+ /* We always want at least one char left in the buffer, since we
+ always (unless we get an error while reading the first char)
+ NUL-terminate the line buffer. */
+
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ if (nchars_avail < 2)
+ {
+ if (*n > MIN_CHUNK)
+ *n *= 2;
+ else
+ *n += MIN_CHUNK;
+
+ nchars_avail = *n + *lineptr - read_pos;
+ *lineptr = realloc (*lineptr, *n);
+ if (!*lineptr)
+ return -1;
+ read_pos = *n - nchars_avail + *lineptr;
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ }
+
+ if (c == EOF || ferror (stream))
+ {
+ /* Return partial line, if any. */
+ if (read_pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *read_pos++ = c;
+ nchars_avail--;
+
+ if (c == terminator)
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of chars read. */
+ *read_pos = '\0';
+
+ ret = read_pos - (*lineptr + offset);
+ return ret;
+}
+
+int
+getline (lineptr, n, stream)
+ char **lineptr;
+ size_t *n;
+ FILE *stream;
+{
+ return getstr (lineptr, n, stream, '\n', 0);
+}
+
+int
+getdelim (lineptr, n, delimiter, stream)
+ char **lineptr;
+ size_t *n;
+ int delimiter;
+ FILE *stream;
+{
+ return getstr (lineptr, n, stream, delimiter, 0);
+}
+#endif
diff --git a/lib/getline.h b/lib/getline.h
new file mode 100644
index 0000000..cc6466d
--- /dev/null
+++ b/lib/getline.h
@@ -0,0 +1,36 @@
+/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef GETLINE_H_
+# define GETLINE_H_ 1
+
+# include <stdio.h>
+
+# ifndef PARAMS
+# if defined (__GNUC__) || __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+# endif
+
+int
+getline PARAMS ((char **_lineptr, size_t *_n, FILE *_stream));
+
+int
+getdelim PARAMS ((char **_lineptr, size_t *_n, int _delimiter, FILE *_stream));
+
+#endif /* not GETLINE_H_ */
diff --git a/lib/getopt.c b/lib/getopt.c
new file mode 100644
index 0000000..7da985f
--- /dev/null
+++ b/lib/getopt.c
@@ -0,0 +1,1052 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to drepper@gnu.org
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98
+ Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+# ifndef const
+# define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+# include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+# ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+# else
+# define _(msgid) (msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+# include <string.h>
+# define my_index strchr
+#else
+
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#ifdef _LIBC
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ nonoption_flags_max_len),
+ '\0', top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', nonoption_flags_max_len - len);
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ optarg = NULL;
+
+ if (optind == 0 || !__getopt_initialized)
+ {
+ if (optind == 0)
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+
+ nextchar += strlen (nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf (stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getopt.h b/lib/getopt.h
new file mode 100644
index 0000000..c4adc30
--- /dev/null
+++ b/lib/getopt.h
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* getopt.h */
diff --git a/lib/getopt1.c b/lib/getopt1.c
new file mode 100644
index 0000000..4ce1065
--- /dev/null
+++ b/lib/getopt1.c
@@ -0,0 +1,190 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+ Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644
index 0000000..dcf223c
--- /dev/null
+++ b/lib/hash.c
@@ -0,0 +1,385 @@
+/* hash - implement simple hashing table with string based keys.
+ Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if HAVE_OBSTACK
+# include <obstack.h>
+#else
+# include "obstack.h"
+#endif
+
+#if HAVE_VALUES_H
+# include <values.h>
+#endif
+
+#include "hash.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+#ifndef BITSPERBYTE
+# define BITSPERBYTE 8
+#endif
+
+#ifndef LONGBITS
+# define LONGBITS (sizeof (long) * BITSPERBYTE)
+#endif
+
+#ifndef bcopy
+# define bcopy(S, D, N) memcpy ((D), (S), (N))
+#endif
+
+void *xmalloc PARAMS ((size_t __n));
+
+typedef struct hash_entry
+{
+ unsigned long used;
+ const char *key;
+ void *data;
+ struct hash_entry *next;
+}
+hash_entry;
+
+/* Prototypes for local functions. */
+static void insert_entry_2 PARAMS ((hash_table *htab, const char *key,
+ unsigned long hval, size_t idx,
+ void *data));
+static size_t lookup PARAMS ((hash_table *htab, const char *key, size_t keylen,
+ unsigned long hval));
+static size_t lookup_2 PARAMS ((hash_table *htab, const char *key,
+ unsigned long hval));
+static unsigned long compute_hashval PARAMS ((const char *key, size_t keylen));
+static int is_prime PARAMS ((unsigned long candidate));
+
+
+int
+init_hash (htab, init_size)
+ hash_table *htab;
+ unsigned long init_size;
+{
+ /* We need the size to be a prime. */
+ init_size = next_prime (init_size);
+
+ /* Initialize the data structure. */
+ htab->size = init_size;
+ htab->filled = 0;
+ htab->first = NULL;
+ htab->table = (void *) xmalloc ((init_size + 1) * sizeof (hash_entry));
+ if (htab->table == NULL)
+ return -1;
+
+ memset (htab->table, '\0', (init_size + 1) * sizeof (hash_entry));
+ obstack_init (&htab->mem_pool);
+
+ return 0;
+}
+
+
+int
+delete_hash (htab)
+ hash_table *htab;
+{
+ free (htab->table);
+ obstack_free (&htab->mem_pool, NULL);
+ return 0;
+}
+
+
+int
+insert_entry (htab, key, keylen, data)
+ hash_table *htab;
+ const char *key;
+ size_t keylen;
+ void *data;
+{
+ unsigned long hval = compute_hashval (key, keylen);
+ hash_entry *table = (hash_entry *) htab->table;
+ size_t idx = lookup (htab, key, keylen, hval);
+
+ if (table[idx].used)
+ /* We don't want to overwrite the old value. */
+ return -1;
+ else
+ {
+ /* An empty bucket has been found. */
+ insert_entry_2 (htab, obstack_copy0 (&htab->mem_pool, key, keylen),
+ hval, idx, data);
+ return 0;
+ }
+}
+
+static void
+insert_entry_2 (htab, key, hval, idx, data)
+ hash_table *htab;
+ const char *key;
+ unsigned long hval;
+ size_t idx;
+ void *data;
+{
+ hash_entry *table = (hash_entry *) htab->table;
+
+ table[idx].used = hval;
+ table[idx].key = key;
+ table[idx].data = data;
+
+ /* List the new value in the list. */
+ if ((hash_entry *) htab->first == NULL)
+ {
+ table[idx].next = &table[idx];
+ *(hash_entry **) &htab->first = &table[idx];
+ }
+ else
+ {
+ table[idx].next = ((hash_entry *) htab->first)->next;
+ ((hash_entry *) htab->first)->next = &table[idx];
+ *(hash_entry **) &htab->first = &table[idx];
+ }
+
+ ++htab->filled;
+ if (100 * htab->filled > 90 * htab->size)
+ {
+ /* Table is filled more than 90%. Resize the table. */
+ unsigned long old_size = htab->size;
+
+ htab->size = next_prime (htab->size * 2);
+ htab->filled = 0;
+ htab->first = NULL;
+ htab->table = (void *) xmalloc ((1 + htab->size)
+ * sizeof (hash_entry));
+ memset (htab->table, '\0', (1 + htab->size) * sizeof (hash_entry));
+
+ for (idx = 1; idx <= old_size; ++idx)
+ if (table[idx].used)
+ insert_entry_2 (htab, table[idx].key, table[idx].used,
+ lookup_2 (htab, table[idx].key, table[idx].used),
+ table[idx].data);
+
+ free (table);
+ }
+}
+
+
+int
+find_entry (htab, key, keylen, result)
+ hash_table *htab;
+ const char *key;
+ size_t keylen;
+ void **result;
+{
+ hash_entry *table = (hash_entry *) htab->table;
+ size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
+
+ if (table[idx].used == 0)
+ return -1;
+
+ *result = table[idx].data;
+ return 0;
+}
+
+
+int
+iterate_table (htab, ptr, key, data)
+ hash_table *htab;
+ void **ptr;
+ const void **key;
+ void **data;
+{
+ if (*ptr == NULL)
+ {
+ if (htab->first == NULL)
+ return -1;
+ *ptr = (void *) ((hash_entry *) htab->first)->next;
+ }
+ else
+ {
+ if (*ptr == htab->first)
+ return -1;
+ *ptr = (void *) (((hash_entry *) *ptr)->next);
+ }
+
+ *key = ((hash_entry *) *ptr)->key;
+ *data = ((hash_entry *) *ptr)->data;
+ return 0;
+}
+
+
+static size_t
+lookup (htab, key, keylen, hval)
+ hash_table *htab;
+ const char *key;
+ size_t keylen;
+ unsigned long hval;
+{
+ unsigned long hash;
+ size_t idx;
+ hash_entry *table = (hash_entry *) htab->table;
+
+ /* First hash function: simply take the modul but prevent zero. */
+ hash = 1 + hval % htab->size;
+
+ idx = hash;
+
+ if (table[idx].used)
+ {
+ if (table[idx].used == hval && table[idx].key[keylen] == '\0'
+ && strncmp (key, table[idx].key, keylen) == 0)
+ return idx;
+
+ /* Second hash function as suggested in [Knuth]. */
+ hash = 1 + hval % (htab->size - 2);
+
+ do
+ {
+ if (idx <= hash)
+ idx = htab->size + idx - hash;
+ else
+ idx -= hash;
+
+ /* If entry is found use it. */
+ if (table[idx].used == hval && table[idx].key[keylen] == '\0'
+ && strncmp (key, table[idx].key, keylen) == 0)
+ return idx;
+ }
+ while (table[idx].used);
+ }
+ return idx;
+}
+
+
+/* References:
+ [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+ [Knuth] The Art of Computer Programming, part3 (6.4) */
+
+static size_t
+lookup_2 (htab, key, hval)
+ hash_table *htab;
+ const char *key;
+ unsigned long hval;
+{
+ unsigned long hash;
+ size_t idx;
+ hash_entry *table = (hash_entry *) htab->table;
+
+ /* First hash function: simply take the modul but prevent zero. */
+ hash = 1 + hval % htab->size;
+
+ idx = hash;
+
+ if (table[idx].used)
+ {
+ if (table[idx].used == hval && strcmp (key, table[idx].key) == 0)
+ return idx;
+
+ /* Second hash function as suggested in [Knuth]. */
+ hash = 1 + hval % (htab->size - 2);
+
+ do
+ {
+ if (idx <= hash)
+ idx = htab->size + idx - hash;
+ else
+ idx -= hash;
+
+ /* If entry is found use it. */
+ if (table[idx].used == hval && strcmp (key, table[idx].key) == 0)
+ return idx;
+ }
+ while (table[idx].used);
+ }
+ return idx;
+}
+
+
+static unsigned long
+compute_hashval (key, keylen)
+ const char *key;
+ size_t keylen;
+{
+ size_t cnt;
+ unsigned long hval, g;
+
+ /* Compute the hash value for the given string. The algorithm
+ is taken from [Aho,Sethi,Ullman]. */
+ cnt = 0;
+ hval = keylen;
+ while (cnt < keylen)
+ {
+ hval <<= 4;
+ hval += key[cnt++];
+ g = hval & ((unsigned long) 0xf << (LONGBITS - 4));
+ if (g != 0)
+ {
+ hval ^= g >> (LONGBITS - 8);
+ hval ^= g;
+ }
+ }
+ return hval != 0 ? hval : ~((unsigned long) 0);
+}
+
+
+unsigned long
+next_prime (seed)
+ unsigned long seed;
+{
+ /* Make it definitely odd. */
+ seed |= 1;
+
+ while (!is_prime (seed))
+ seed += 2;
+
+ return seed;
+}
+
+
+static int
+is_prime (candidate)
+ unsigned long candidate;
+{
+ /* No even number and none less than 10 will be passed here. */
+ unsigned long divn = 3;
+ unsigned long sq = divn * divn;
+
+ while (sq < candidate && candidate % divn != 0)
+ {
+ ++divn;
+ sq += 4 * divn;
+ ++divn;
+ }
+
+ return candidate % divn != 0;
+}
diff --git a/lib/hash.h b/lib/hash.h
new file mode 100644
index 0000000..238d6ca
--- /dev/null
+++ b/lib/hash.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 1995 Free Software Foundation, Inc.
+
+ 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., 59 Temple Place
+ - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _HASH_H
+# define _HASH_H
+
+# include <obstack.h>
+
+typedef struct hash_table
+{
+ unsigned long size;
+ unsigned long filled;
+ void *first;
+ void *table;
+ struct obstack mem_pool;
+}
+hash_table;
+
+# ifndef PARAMS
+# if defined (__GNUC__) || __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+int init_hash PARAMS ((hash_table *htab, unsigned long init_size));
+int delete_hash PARAMS ((hash_table *htab));
+int insert_entry PARAMS ((hash_table *htab, const char *key, size_t keylen,
+ void *data));
+int find_entry PARAMS ((hash_table *htab, const char *key, size_t keylen,
+ void **result));
+
+int iterate_table PARAMS ((hash_table *htab, void **ptr,
+ const void **key, void **data));
+
+unsigned long next_prime PARAMS ((unsigned long seed));
+
+#endif /* not _HASH_H */
diff --git a/lib/memmove.c b/lib/memmove.c
new file mode 100644
index 0000000..4115aa3
--- /dev/null
+++ b/lib/memmove.c
@@ -0,0 +1,108 @@
+/* Copy memory to memory until the specified number of bytes
+ has been copied. Overlap is handled correctly.
+ Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Torbjorn Granlund (tege@sics.se).
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <memcopy.h>
+#include <pagecopy.h>
+
+/* All this is so that bcopy.c can #include
+ this file after defining some things. */
+#ifndef a1
+#define a1 dest /* First arg is DEST. */
+#define a1const
+#define a2 src /* Second arg is SRC. */
+#define a2const const
+#undef memmove
+#endif
+#if !defined(RETURN) || !defined(rettype)
+#define RETURN(s) return (s) /* Return DEST. */
+#define rettype void *
+#endif
+
+
+rettype
+memmove (a1, a2, len)
+ a1const void *a1;
+ a2const void *a2;
+ size_t len;
+{
+ unsigned long int dstp = (long int) dest;
+ unsigned long int srcp = (long int) src;
+
+ /* This test makes the forward copying code be used whenever possible.
+ Reduces the working set. */
+ if (dstp - srcp >= len) /* *Unsigned* compare! */
+ {
+ /* Copy from the beginning to the end. */
+
+ /* If there not too few bytes to copy, use word copy. */
+ if (len >= OP_T_THRES)
+ {
+ /* Copy just a few bytes to make DSTP aligned. */
+ len -= (-dstp) % OPSIZ;
+ BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
+
+ /* Copy whole pages from SRCP to DSTP by virtual address
+ manipulation, as much as possible. */
+
+ PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
+
+ /* Copy from SRCP to DSTP taking advantage of the known
+ alignment of DSTP. Number of bytes remaining is put
+ in the third argument, i.e. in LEN. This number may
+ vary from machine to machine. */
+
+ WORD_COPY_FWD (dstp, srcp, len, len);
+
+ /* Fall out and copy the tail. */
+ }
+
+ /* There are just a few bytes to copy. Use byte memory operations. */
+ BYTE_COPY_FWD (dstp, srcp, len);
+ }
+ else
+ {
+ /* Copy from the end to the beginning. */
+ srcp += len;
+ dstp += len;
+
+ /* If there not too few bytes to copy, use word copy. */
+ if (len >= OP_T_THRES)
+ {
+ /* Copy just a few bytes to make DSTP aligned. */
+ len -= dstp % OPSIZ;
+ BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
+
+ /* Copy from SRCP to DSTP taking advantage of the known
+ alignment of DSTP. Number of bytes remaining is put
+ in the third argument, i.e. in LEN. This number may
+ vary from machine to machine. */
+
+ WORD_COPY_BWD (dstp, srcp, len, len);
+
+ /* Fall out and copy the tail. */
+ }
+
+ /* There are just a few bytes to copy. Use byte memory operations. */
+ BYTE_COPY_BWD (dstp, srcp, len);
+ }
+
+ RETURN (dest);
+}
diff --git a/lib/memset.c b/lib/memset.c
new file mode 100644
index 0000000..239dc21
--- /dev/null
+++ b/lib/memset.c
@@ -0,0 +1,90 @@
+/* Copyright (C) 1991, 1997 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <memcopy.h>
+
+#undef memset
+
+void *
+memset (dstpp, c, len)
+ void *dstpp;
+ int c;
+ size_t len;
+{
+ long int dstp = (long int) dstpp;
+
+ if (len >= 8)
+ {
+ size_t xlen;
+ op_t cccc;
+
+ cccc = (unsigned char) c;
+ cccc |= cccc << 8;
+ cccc |= cccc << 16;
+ if (OPSIZ > 4)
+ /* Do the shift in two steps to avoid warning if long has 32 bits. */
+ cccc |= (cccc << 16) << 16;
+
+ /* There are at least some bytes to set.
+ No need to test for LEN == 0 in this alignment loop. */
+ while (dstp % OPSIZ != 0)
+ {
+ ((byte *) dstp)[0] = c;
+ dstp += 1;
+ len -= 1;
+ }
+
+ /* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */
+ xlen = len / (OPSIZ * 8);
+ while (xlen > 0)
+ {
+ ((op_t *) dstp)[0] = cccc;
+ ((op_t *) dstp)[1] = cccc;
+ ((op_t *) dstp)[2] = cccc;
+ ((op_t *) dstp)[3] = cccc;
+ ((op_t *) dstp)[4] = cccc;
+ ((op_t *) dstp)[5] = cccc;
+ ((op_t *) dstp)[6] = cccc;
+ ((op_t *) dstp)[7] = cccc;
+ dstp += 8 * OPSIZ;
+ xlen -= 1;
+ }
+ len %= OPSIZ * 8;
+
+ /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */
+ xlen = len / OPSIZ;
+ while (xlen > 0)
+ {
+ ((op_t *) dstp)[0] = cccc;
+ dstp += OPSIZ;
+ xlen -= 1;
+ }
+ len %= OPSIZ;
+ }
+
+ /* Write the last few bytes. */
+ while (len > 0)
+ {
+ ((byte *) dstp)[0] = c;
+ dstp += 1;
+ len -= 1;
+ }
+
+ return dstpp;
+}
diff --git a/lib/obstack.c b/lib/obstack.c
new file mode 100644
index 0000000..e5b5d4f
--- /dev/null
+++ b/lib/obstack.c
@@ -0,0 +1,593 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+ Copyright (C) 1988,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "obstack.h"
+
+/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
+ incremented whenever callers compiled using an old obstack.h can no
+ longer properly call the functions in this obstack.c. */
+#define OBSTACK_INTERFACE_VERSION 1
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself, and the installed library
+ supports the same library interface we do. This code is part of the GNU
+ C Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object
+ files, it is simpler to just do this in the source for each such file. */
+
+#include <stdio.h> /* Random thing to get __GNU_LIBRARY__. */
+#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
+#include <gnu-versions.h>
+#if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+
+#ifndef ELIDE_CODE
+
+
+#if defined (__STDC__) && __STDC__
+#define POINTER void *
+#else
+#define POINTER char *
+#endif
+
+/* Determine default alignment. */
+struct fooalign {char x; double d;};
+#define DEFAULT_ALIGNMENT \
+ ((PTR_INT_TYPE) ((char *) &((struct fooalign *) 0)->d - (char *) 0))
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+ But in fact it might be less smart and round addresses to as much as
+ DEFAULT_ROUNDING. So we prepare for it to do that. */
+union fooround {long x; double d;};
+#define DEFAULT_ROUNDING (sizeof (union fooround))
+
+/* When we copy a long block of data, this is the unit to do it with.
+ On some machines, copying successive ints does not work;
+ in such a case, redefine COPYING_UNIT to `long' (if that works)
+ or `char' as a last resort. */
+#ifndef COPYING_UNIT
+#define COPYING_UNIT int
+#endif
+
+
+/* The functions allocating more room by calling `obstack_chunk_alloc'
+ jump to the handler pointed to by `obstack_alloc_failed_handler'.
+ This variable by default points to the internal function
+ `print_and_abort'. */
+#if defined (__STDC__) && __STDC__
+static void print_and_abort (void);
+void (*obstack_alloc_failed_handler) (void) = print_and_abort;
+#else
+static void print_and_abort ();
+void (*obstack_alloc_failed_handler) () = print_and_abort;
+#endif
+
+/* Exit value used when `print_and_abort' is used. */
+#if defined __GNU_LIBRARY__ || defined HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+int obstack_exit_failure = EXIT_FAILURE;
+
+/* The non-GNU-C macros copy the obstack into this global variable
+ to avoid multiple evaluation. */
+
+struct obstack *_obstack;
+
+/* Define a macro that either calls functions with the traditional malloc/free
+ calling interface, or calls functions with the mmalloc/mfree interface
+ (that adds an extra first argument), based on the state of use_extra_arg.
+ For free, do not use ?:, since some compilers, like the MIPS compilers,
+ do not allow (expr) ? void : void. */
+
+#if defined (__STDC__) && __STDC__
+#define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size)))
+
+#define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \
+ } while (0)
+#else
+#define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(struct _obstack_chunk *(*) ()) (h)->chunkfun) ((size)))
+
+#define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(void (*) ()) (h)->freefun) ((old_chunk)); \
+ } while (0)
+#endif
+
+
+/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
+ Objects start on multiples of ALIGNMENT (0 means use default).
+ CHUNKFUN is the function to use to allocate chunks,
+ and FREEFUN the function to free them.
+
+ Return nonzero if successful, zero if out of memory.
+ To recover from an out of memory error,
+ free up some memory, then call this again. */
+
+int
+_obstack_begin (h, size, alignment, chunkfun, freefun)
+ struct obstack *h;
+ int size;
+ int alignment;
+#if defined (__STDC__) && __STDC__
+ POINTER (*chunkfun) (long);
+ void (*freefun) (void *);
+#else
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+#endif
+{
+ register struct _obstack_chunk *chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = (int) DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+#if defined (__STDC__) && __STDC__
+ h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun;
+ h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+#else
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+#endif
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->use_extra_arg = 0;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ if (!chunk)
+ (*obstack_alloc_failed_handler) ();
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+ h->alloc_failed = 0;
+ return 1;
+}
+
+int
+_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
+ struct obstack *h;
+ int size;
+ int alignment;
+#if defined (__STDC__) && __STDC__
+ POINTER (*chunkfun) (POINTER, long);
+ void (*freefun) (POINTER, POINTER);
+#else
+ POINTER (*chunkfun) ();
+ void (*freefun) ();
+#endif
+ POINTER arg;
+{
+ register struct _obstack_chunk *chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = (int) DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+#if defined(__STDC__) && __STDC__
+ h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+ h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+#else
+ h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
+ h->freefun = freefun;
+#endif
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->extra_arg = arg;
+ h->use_extra_arg = 1;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ if (!chunk)
+ (*obstack_alloc_failed_handler) ();
+ h->next_free = h->object_base = chunk->contents;
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+ h->alloc_failed = 0;
+ return 1;
+}
+
+/* Allocate a new current chunk for the obstack *H
+ on the assumption that LENGTH bytes need to be added
+ to the current object, or a new object of length LENGTH allocated.
+ Copies any partial object from the end of the old chunk
+ to the beginning of the new one. */
+
+void
+_obstack_newchunk (h, length)
+ struct obstack *h;
+ int length;
+{
+ register struct _obstack_chunk *old_chunk = h->chunk;
+ register struct _obstack_chunk *new_chunk;
+ register long new_size;
+ register long obj_size = h->next_free - h->object_base;
+ register long i;
+ long already;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) + (obj_size >> 3) + 100;
+ if (new_size < h->chunk_size)
+ new_size = h->chunk_size;
+
+ /* Allocate and initialize the new chunk. */
+ new_chunk = CALL_CHUNKFUN (h, new_size);
+ if (!new_chunk)
+ (*obstack_alloc_failed_handler) ();
+ h->chunk = new_chunk;
+ new_chunk->prev = old_chunk;
+ new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+ /* Move the existing object to the new chunk.
+ Word at a time is fast and is safe if the object
+ is sufficiently aligned. */
+ if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+ {
+ for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)new_chunk->contents)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+ /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+ but that can cross a page boundary on a machine
+ which does not do strict alignment for COPYING_UNITS. */
+ already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+ }
+ else
+ already = 0;
+ /* Copy remaining bytes one by one. */
+ for (i = already; i < obj_size; i++)
+ new_chunk->contents[i] = h->object_base[i];
+
+ /* If the object just copied was the only data in OLD_CHUNK,
+ free that chunk and remove it from the chain.
+ But not if that chunk might contain an empty object. */
+ if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
+ {
+ new_chunk->prev = old_chunk->prev;
+ CALL_FREEFUN (h, old_chunk);
+ }
+
+ h->object_base = new_chunk->contents;
+ h->next_free = h->object_base + obj_size;
+ /* The new chunk certainly contains no empty object yet. */
+ h->maybe_empty_object = 0;
+}
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+ This is here for debugging.
+ If you use it in a program, you are probably losing. */
+
+#if defined (__STDC__) && __STDC__
+/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
+ obstack.h because it is just for debugging. */
+int _obstack_allocated_p (struct obstack *h, POINTER obj);
+#endif
+
+int
+_obstack_allocated_p (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+ lp = (h)->chunk;
+ /* We use >= rather than > since the object cannot be exactly at
+ the beginning of the chunk but might be an empty object exactly
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
+ {
+ plp = lp->prev;
+ lp = plp;
+ }
+ return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+ more recently than OBJ. If OBJ is zero, free everything in H. */
+
+#undef obstack_free
+
+/* This function has two names with identical definitions.
+ This is the first one, called from non-ANSI code. */
+
+void
+_obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *) (obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+/* This function is used from ANSI code. */
+
+void
+obstack_free (h, obj)
+ struct obstack *h;
+ POINTER obj;
+{
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *) (obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+int
+_obstack_memory_used (h)
+ struct obstack *h;
+{
+ register struct _obstack_chunk* lp;
+ register int nbytes = 0;
+
+ for (lp = h->chunk; lp != 0; lp = lp->prev)
+ {
+ nbytes += lp->limit - (char *) lp;
+ }
+ return nbytes;
+}
+
+/* Define the error handler. */
+#ifndef _
+# ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# ifndef _
+# define _(Str) gettext (Str)
+# endif
+# else
+# define _(Str) (Str)
+# endif
+#endif
+
+static void
+print_and_abort ()
+{
+ fputs (_("memory exhausted\n"), stderr);
+ exit (obstack_exit_failure);
+}
+
+#if 0
+/* These are now turned off because the applications do not use it
+ and it uses bcopy via obstack_grow, which causes trouble on sysV. */
+
+/* Now define the functional versions of the obstack macros.
+ Define them to simply use the corresponding macros to do the job. */
+
+#if defined (__STDC__) && __STDC__
+/* These function definitions do not work with non-ANSI preprocessors;
+ they won't pass through the macro names in parentheses. */
+
+/* The function names appear in parentheses in order to prevent
+ the macro-definitions of the names from being expanded there. */
+
+POINTER (obstack_base) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_base (obstack);
+}
+
+POINTER (obstack_next_free) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_next_free (obstack);
+}
+
+int (obstack_object_size) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_object_size (obstack);
+}
+
+int (obstack_room) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_room (obstack);
+}
+
+int (obstack_make_room) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_make_room (obstack, length);
+}
+
+void (obstack_grow) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow (obstack, pointer, length);
+}
+
+void (obstack_grow0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ obstack_grow0 (obstack, pointer, length);
+}
+
+void (obstack_1grow) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow (obstack, character);
+}
+
+void (obstack_blank) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank (obstack, length);
+}
+
+void (obstack_1grow_fast) (obstack, character)
+ struct obstack *obstack;
+ int character;
+{
+ obstack_1grow_fast (obstack, character);
+}
+
+void (obstack_blank_fast) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ obstack_blank_fast (obstack, length);
+}
+
+POINTER (obstack_finish) (obstack)
+ struct obstack *obstack;
+{
+ return obstack_finish (obstack);
+}
+
+POINTER (obstack_alloc) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_alloc (obstack, length);
+}
+
+POINTER (obstack_copy) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy (obstack, pointer, length);
+}
+
+POINTER (obstack_copy0) (obstack, pointer, length)
+ struct obstack *obstack;
+ POINTER pointer;
+ int length;
+{
+ return obstack_copy0 (obstack, pointer, length);
+}
+
+#endif /* __STDC__ */
+
+#endif /* 0 */
+
+#endif /* !ELIDE_CODE */
diff --git a/lib/obstack.h b/lib/obstack.h
new file mode 100644
index 0000000..144998c
--- /dev/null
+++ b/lib/obstack.h
@@ -0,0 +1,593 @@
+/* obstack.h - object stack macros
+ Copyright (C) 1988,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects. Each object starts life
+small, and may grow to maturity. (Consider building a word syllable
+by syllable.) An object can move while it is growing. Once it has
+been "finished" it never changes address again. So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'. On occasion, they free chunks,
+by calling `obstack_chunk_free'. You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables. Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols. At the time you are reading a symbol you don't know
+how long it is. One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer. This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently. Use one obstack for all symbol
+names. As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it. Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses. When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk. When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies. No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk. We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object. This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+ We allocate large chunks.
+ We carve out one object at a time from the current chunk.
+ Once carved, an object never moves.
+ We are free to append data of any size to the currently
+ growing object.
+ Exactly one object is growing in an obstack at any one time.
+ You can run one obstack per control block.
+ You may have as many control blocks as you dare.
+ Because of the way we do it, you can `unwind' an obstack
+ back to a previous state. (You may remove objects much
+ as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once. */
+
+#ifndef _OBSTACK_H
+#define _OBSTACK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We use subtraction of (char *) 0 instead of casting to int
+ because on word-addressable machines a simple cast to int
+ may ignore the byte-within-word field of the pointer. */
+
+#ifndef __PTR_TO_INT
+# define __PTR_TO_INT(P) ((P) - (char *) 0)
+#endif
+
+#ifndef __INT_TO_PTR
+# define __INT_TO_PTR(P) ((P) + (char *) 0)
+#endif
+
+/* We need the type of the resulting object. If __PTRDIFF_TYPE__ is
+ defined, as with GNU C, use that; that way we don't pollute the
+ namespace with <stddef.h>'s symbols. Otherwise, if <stddef.h> is
+ available, include it and use ptrdiff_t. In traditional C, long is
+ the best that we can do. */
+
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# ifdef HAVE_STDDEF_H
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+# else
+# define PTR_INT_TYPE long
+# endif
+#endif
+
+#if defined _LIBC || defined HAVE_STRING_H
+# include <string.h>
+# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N))
+#else
+# ifdef memcpy
+# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N))
+# else
+# define _obstack_memcpy(To, From, N) bcopy ((From), (To), (N))
+# endif
+#endif
+
+struct _obstack_chunk /* Lives at front of each chunk. */
+{
+ char *limit; /* 1 past end of this chunk */
+ struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+ char contents[4]; /* objects begin here */
+};
+
+struct obstack /* control current object in current chunk */
+{
+ long chunk_size; /* preferred size to allocate chunks in */
+ struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
+ char *object_base; /* address of object we are building */
+ char *next_free; /* where to add next char to current object */
+ char *chunk_limit; /* address of char after current chunk */
+ PTR_INT_TYPE temp; /* Temporary for some macros. */
+ int alignment_mask; /* Mask of alignment for each object. */
+#if defined __STDC__ && __STDC__
+ /* These prototypes vary based on `use_extra_arg', and we use
+ casts to the prototypeless function type in all assignments,
+ but having prototypes here quiets -Wstrict-prototypes. */
+ struct _obstack_chunk *(*chunkfun) (void *, long);
+ void (*freefun) (void *, struct _obstack_chunk *);
+ void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#else
+ struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
+ void (*freefun) (); /* User's function to free a chunk. */
+ char *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#endif
+ unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
+ unsigned maybe_empty_object:1;/* There is a possibility that the current
+ chunk contains a zero-length object. This
+ prevents freeing the chunk if we allocate
+ a bigger chunk to replace it. */
+ unsigned alloc_failed:1; /* No longer used, as we now call the failed
+ handler on error, but retained for binary
+ compatibility. */
+};
+
+/* Declare the external functions we use; they are in obstack.c. */
+
+#if defined __STDC__ && __STDC__
+extern void _obstack_newchunk (struct obstack *, int);
+extern void _obstack_free (struct obstack *, void *);
+extern int _obstack_begin (struct obstack *, int, int,
+ void *(*) (long), void (*) (void *));
+extern int _obstack_begin_1 (struct obstack *, int, int,
+ void *(*) (void *, long),
+ void (*) (void *, void *), void *);
+extern int _obstack_memory_used (struct obstack *);
+#else
+extern void _obstack_newchunk ();
+extern void _obstack_free ();
+extern int _obstack_begin ();
+extern int _obstack_begin_1 ();
+extern int _obstack_memory_used ();
+#endif
+
+#if defined __STDC__ && __STDC__
+
+/* Do the function-declarations after the structs
+ but before defining the macros. */
+
+void obstack_init (struct obstack *obstack);
+
+void * obstack_alloc (struct obstack *obstack, int size);
+
+void * obstack_copy (struct obstack *obstack, void *address, int size);
+void * obstack_copy0 (struct obstack *obstack, void *address, int size);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+void obstack_blank (struct obstack *obstack, int size);
+
+void obstack_grow (struct obstack *obstack, void *data, int size);
+void obstack_grow0 (struct obstack *obstack, void *data, int size);
+
+void obstack_1grow (struct obstack *obstack, int data_char);
+void obstack_ptr_grow (struct obstack *obstack, void *data);
+void obstack_int_grow (struct obstack *obstack, int data);
+
+void * obstack_finish (struct obstack *obstack);
+
+int obstack_object_size (struct obstack *obstack);
+
+int obstack_room (struct obstack *obstack);
+void obstack_make_room (struct obstack *obstack, int size);
+void obstack_1grow_fast (struct obstack *obstack, int data_char);
+void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
+void obstack_int_grow_fast (struct obstack *obstack, int data);
+void obstack_blank_fast (struct obstack *obstack, int size);
+
+void * obstack_base (struct obstack *obstack);
+void * obstack_next_free (struct obstack *obstack);
+int obstack_alignment_mask (struct obstack *obstack);
+int obstack_chunk_size (struct obstack *obstack);
+int obstack_memory_used (struct obstack *obstack);
+
+#endif /* __STDC__ */
+
+/* Non-ANSI C cannot really support alternative functions for these macros,
+ so we do not declare them. */
+
+/* Error handler called when `obstack_chunk_alloc' failed to allocate
+ more memory. This can be set to a user defined function. The
+ default action is to print a message and abort. */
+#if defined __STDC__ && __STDC__
+extern void (*obstack_alloc_failed_handler) (void);
+#else
+extern void (*obstack_alloc_failed_handler) ();
+#endif
+
+/* Exit value used when `print_and_abort' is used. */
+extern int obstack_exit_failure;
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+ Note that this might not be the final address of the object
+ because a new chunk might be needed to hold the final size. */
+
+#define obstack_base(h) ((h)->object_base)
+
+/* Size for allocating ordinary chunks. */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk. */
+
+#define obstack_next_free(h) ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object. */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+/* To prevent prototype warnings provide complete argument list in
+ standard C version. */
+#if defined __STDC__ && __STDC__
+
+# define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) (long)) (chunkfun), (void (*) (void *)) (freefun))
+
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) (void *, long)) (chunkfun), \
+ (void (*) (void *, void *)) (freefun), (arg))
+
+# define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+
+# define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+
+#else
+
+# define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+# define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
+
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun))
+
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg))
+
+# define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun))
+
+# define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)()) (newfreefun))
+
+#endif
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#define obstack_memory_used(h) _obstack_memory_used (h)
+
+#if defined __GNUC__ && defined __STDC__ && __STDC__
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+ does not implement __extension__. But that compiler doesn't define
+ __GNUC_MINOR__. */
+# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+# define __extension__
+# endif
+
+/* For GNU C, if not -traditional,
+ we can define these macros to compute all args only once
+ without using a global variable.
+ Also, we can avoid using the `temp' slot, to make faster code. */
+
+# define obstack_object_size(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->next_free - __o->object_base); })
+
+# define obstack_room(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (unsigned) (__o->chunk_limit - __o->next_free); })
+
+# define obstack_make_room(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ (void) 0; })
+
+# define obstack_empty_p(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); })
+
+# define obstack_grow(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->next_free + __len > __o->chunk_limit) \
+ _obstack_newchunk (__o, __len); \
+ _obstack_memcpy (__o->next_free, (char *) (where), __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+# define obstack_grow0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->next_free + __len + 1 > __o->chunk_limit) \
+ _obstack_newchunk (__o, __len + 1); \
+ _obstack_memcpy (__o->next_free, (char *) (where), __len); \
+ __o->next_free += __len; \
+ *(__o->next_free)++ = 0; \
+ (void) 0; })
+
+# define obstack_1grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + 1 > __o->chunk_limit) \
+ _obstack_newchunk (__o, 1); \
+ *(__o->next_free)++ = (datum); \
+ (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers or ints,
+ and that the data added so far to the current object
+ shares that much alignment. */
+
+# define obstack_ptr_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (void *)); \
+ *((void **)__o->next_free)++ = ((void *)datum); \
+ (void) 0; })
+
+# define obstack_int_grow(OBSTACK,datum) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ if (__o->next_free + sizeof (int) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (int)); \
+ *((int *)__o->next_free)++ = ((int)datum); \
+ (void) 0; })
+
+# define obstack_ptr_grow_fast(h,aptr) (*((void **) (h)->next_free)++ = (void *)aptr)
+# define obstack_int_grow_fast(h,aint) (*((int *) (h)->next_free)++ = (int) aint)
+
+# define obstack_blank(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ __o->next_free += __len; \
+ (void) 0; })
+
+# define obstack_alloc(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_blank (__h, (length)); \
+ obstack_finish (__h); })
+
+# define obstack_copy(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+# define obstack_copy0(OBSTACK,where,length) \
+__extension__ \
+({ struct obstack *__h = (OBSTACK); \
+ obstack_grow0 (__h, (where), (length)); \
+ obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+ when obstack_blank is called. */
+# define obstack_finish(OBSTACK) \
+__extension__ \
+({ struct obstack *__o1 = (OBSTACK); \
+ void *value; \
+ value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ if (__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ __o1->next_free = __o1->chunk_limit; \
+ __o1->object_base = __o1->next_free; \
+ value; })
+
+# define obstack_free(OBSTACK, OBJ) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ void *__obj = (OBJ); \
+ if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \
+ __o->next_free = __o->object_base = __obj; \
+ else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+# define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+# define obstack_room(h) \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+# define obstack_empty_p(h) \
+ ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0)
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+ so that we can avoid having void expressions
+ in the arms of the conditional expression.
+ Casting the third operand to void was tried before,
+ but some compilers won't accept it. */
+
+# define obstack_make_room(h,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0))
+
+# define obstack_grow(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ _obstack_memcpy ((h)->next_free, (char *) (where), (h)->temp), \
+ (h)->next_free += (h)->temp)
+
+# define obstack_grow0(h,where,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
+ _obstack_memcpy ((h)->next_free, (char *) (where), (h)->temp), \
+ (h)->next_free += (h)->temp, \
+ *((h)->next_free)++ = 0)
+
+# define obstack_1grow(h,datum) \
+( (((h)->next_free + 1 > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), 1), 0) : 0), \
+ (*((h)->next_free)++ = (datum)))
+
+# define obstack_ptr_grow(h,datum) \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
+ (*((char **) (((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *) datum)))
+
+# define obstack_int_grow(h,datum) \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
+ (*((int *) (((h)->next_free+=sizeof(int))-sizeof(int))) = ((int) datum)))
+
+# define obstack_ptr_grow_fast(h,aptr) (*((char **) (h)->next_free)++ = (char *) aptr)
+# define obstack_int_grow_fast(h,aint) (*((int *) (h)->next_free)++ = (int) aint)
+
+# define obstack_blank(h,length) \
+( (h)->temp = (length), \
+ (((h)->chunk_limit - (h)->next_free < (h)->temp) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
+ ((h)->next_free += (h)->temp))
+
+# define obstack_alloc(h,length) \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+# define obstack_copy(h,where,length) \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_copy0(h,where,length) \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_finish(h) \
+( ((h)->next_free == (h)->object_base \
+ ? (((h)->maybe_empty_object = 1), 0) \
+ : 0), \
+ (h)->temp = __PTR_TO_INT ((h)->object_base), \
+ (h)->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
+ & ~ ((h)->alignment_mask)), \
+ (((h)->next_free - (char *) (h)->chunk \
+ > (h)->chunk_limit - (char *) (h)->chunk) \
+ ? ((h)->next_free = (h)->chunk_limit) : 0), \
+ (h)->object_base = (h)->next_free, \
+ __INT_TO_PTR ((h)->temp))
+
+# if defined __STDC__ && __STDC__
+# define obstack_free(h,obj) \
+( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
+# else
+# define obstack_free(h,obj) \
+( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \
+ (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
+ ? (int) ((h)->next_free = (h)->object_base \
+ = (h)->temp + (char *) (h)->chunk) \
+ : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
+# endif
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#ifdef __cplusplus
+} /* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/lib/pathmax.h b/lib/pathmax.h
new file mode 100644
index 0000000..74f5792
--- /dev/null
+++ b/lib/pathmax.h
@@ -0,0 +1,53 @@
+/* Define PATH_MAX somehow. Requires sys/types.h.
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _PATHMAX_H
+#define _PATHMAX_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+ PATH_MAX but might cause redefinition warnings when sys/param.h is
+ later included (as on MORE/BSD 4.3). */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+#include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been. */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+#include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#endif /* _PATHMAX_H */
diff --git a/lib/po-mode.el b/lib/po-mode.el
new file mode 100644
index 0000000..69643cd
--- /dev/null
+++ b/lib/po-mode.el
@@ -0,0 +1,2599 @@
+;;; po-mode.el -- for helping GNU gettext lovers to edit PO files.
+;;; Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+;;; François Pinard <pinard@iro.umontreal.ca>, 1995.
+;;; Helped by Greg McGary <gkm@magilla.cichlid.com>.
+
+;; This file is part of GNU gettext.
+
+;; GNU gettext 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.
+
+;; GNU gettext 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; This package provides the tools meant to help editing PO files,
+;;; as documented in the GNU gettext user's manual. See this manual
+;;; for user documentation, which is not repeated here.
+
+;;; To install, merely put this file somewhere GNU Emacs will find it,
+;;; then add the following lines to your .emacs file:
+;;;
+;;; (autoload 'po-mode "po-mode")
+;;; (setq auto-mode-alist (cons '("\\.po[tx]?\\'\\|\\.po\\." . po-mode)
+;;; auto-mode-alist))
+;;;
+;;; To automatically use proper fonts under Emacs 20, also add:
+;;;
+;;; (autoload 'po-find-file-coding-system "po-mode")
+;;; (modify-coding-system-alist 'file "\\.po[tx]?\\'\\|\\.po\\."
+;;; 'po-find-file-coding-system)
+;;;
+;;; You may also adjust some variables, below, by defining them in your
+;;; `.emacs' file, either directly or through command `M-x customize'.
+
+;;; Emacs portability matters.
+
+;;; Most portability matters are addressed in this page. All other cases
+;;; involve one of `eval-and-compile' or `fboundp', just search for these.
+
+;; Identify which Emacs variety is being used.
+(eval-and-compile
+ (cond ((string-match "Lucid\\|XEmacs" emacs-version)
+ (setq po-EMACS20 nil po-XEMACS t))
+ ((and (string-lessp "19" emacs-version) (featurep 'faces))
+ (setq po-EMACS20 t po-XEMACS nil))
+ (t (setq po-EMACS20 nil po-XEMACS nil))))
+
+;; Experiment with Emacs LISP message internationalisation.
+(eval-and-compile
+ (or (fboundp 'set-translation-domain)
+ (defsubst set-translation-domain (string) nil))
+ (or (fboundp 'translate-string)
+ (defsubst translate-string (string) string)))
+(defsubst _ (string) (translate-string string))
+(defsubst N_ (string) string)
+
+;; Handle missing `customs' package.
+(eval-and-compile
+ (condition-case ()
+ (require 'custom)
+ (error nil))
+ (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
+ nil
+ (defmacro defgroup (&rest args)
+ nil)
+ (defmacro defcustom (var value doc &rest args)
+ (` (defvar (, var) (, value) (, doc))))))
+
+;; Protect string comparisons from text properties.
+(eval-and-compile
+ (fset 'po-buffer-substring
+ (symbol-function (if (fboundp 'buffer-substring-no-properties)
+ 'buffer-substring-no-properties
+ 'buffer-substring))))
+
+;; Handle missing `with-temp-buffer' function.
+(eval-and-compile
+ (if nil ; FIXME: just testing... (fboundp 'with-temp-buffer)
+
+ (fset 'po-with-temp-buffer (symbol-function 'with-temp-buffer))
+
+ (defmacro po-with-temp-buffer (&rest forms)
+ "Create a temporary buffer, and evaluate FORMS there like `progn'."
+ (let ((curr-buffer (make-symbol "curr-buffer"))
+ (temp-buffer (make-symbol "temp-buffer")))
+ `(let ((,curr-buffer (current-buffer))
+ (,temp-buffer (get-buffer-create
+ (generate-new-buffer-name " *po-temp*"))))
+ (unwind-protect
+ (progn
+ (set-buffer ,temp-buffer)
+ ,@forms)
+ (set-buffer ,curr-buffer)
+ (and (buffer-name ,temp-buffer)
+ (kill-buffer ,temp-buffer))))))))
+
+;; Handle missing `kill-new' function.
+(eval-and-compile
+ (if (fboundp 'kill-new)
+
+ (fset 'po-kill-new (symbol-function 'kill-new))
+
+ (defun po-kill-new (string)
+ "Push STRING onto the kill ring, for Emacs 18 where kill-new is missing."
+ (po-with-temp-buffer
+ (insert string)
+ (kill-region (point-min) (point-max))))))
+
+;; Handle missing `read-event' function.
+(eval-and-compile
+ (fset 'po-read-event
+ (cond ((fboundp 'read-event)
+ ;; GNU Emacs.
+ 'read-event)
+ ((fboundp 'next-command-event)
+ ;; XEmacs.
+ 'next-command-event)
+ (t
+ ;; Older Emacses.
+ 'read-char))))
+
+;; Handle missing `force-mode-line-update' function.
+(eval-and-compile
+ (if (fboundp 'force-mode-line-update)
+
+ (fset 'po-force-mode-line-update
+ (symbol-function 'force-mode-line-update))
+
+ (defun po-force-mode-line-update ()
+ "Force the mode-line of the current buffer to be redisplayed."
+ (set-buffer-modified-p (buffer-modified-p)))))
+
+;; Handle portable highlighting. Code has been adapted (OK... stolen! :-)
+;; from `ispell.el'.
+(eval-and-compile
+ (cond
+ (po-EMACS20
+
+ (defun po-create-overlay ()
+ "Create and return a deleted overlay structure.
+The variable `po-highlight-face' selects the face to use for highlighting."
+ (let ((overlay (make-overlay (point) (point))))
+ (overlay-put overlay 'face po-highlight-face)
+ ;; The fun thing is that a deleted overlay retains its face, and is
+ ;; movable.
+ (delete-overlay overlay)
+ overlay))
+
+ (defun po-highlight (overlay start end &optional buffer)
+ "Use OVERLAY to highlight the string from START to END.
+If limits are not relative to the current buffer, use optional BUFFER."
+ (move-overlay overlay start end (or buffer (current-buffer))))
+
+ (defun po-rehighlight (overlay)
+ "Ensure OVERLAY is highlighted."
+ ;; There is nothing to do, as GNU Emacs allows multiple highlights.
+ nil)
+
+ (defun po-dehighlight (overlay)
+ "Display normally the last string which OVERLAY highlighted.
+The current buffer should be in PO mode, when this function is called."
+ (delete-overlay overlay)))
+
+ (po-XEMACS
+
+ (defun po-create-overlay (overlay)
+ "Create and return a deleted overlay structure."
+ (cons (make-marker) (make-marker)))
+
+ (defun po-highlight (overlay start end &optional buffer)
+ "Use OVERLAY to highlight the string from START to END.
+If limits are not relative to the current buffer, use optional BUFFER."
+ (if buffer
+ (save-excursion
+ (set-buffer buffer)
+ (isearch-highlight start end))
+ (isearch-highlight start end))
+ (set-marker (car overlay) start (or buffer (current-buffer)))
+ (set-marker (cdr overlay) end (or buffer (current-buffer))))
+
+ (defun po-rehighlight (overlay)
+ "Ensure OVERLAY is highlighted."
+ (let ((buffer (marker-buffer (car overlay)))
+ (start (marker-position (car overlay)))
+ (end (marker-position (cdr overlay))))
+ (and buffer
+ (name-buffer buffer)
+ (po-highlight overlay start end buffer))))
+
+ (defun po-dehighlight (overlay)
+ "Display normally the last string which OVERLAY highlighted."
+ (isearch-dehighlight t)
+ (setcar overlay (make-marker))
+ (setcdr overlay (make-marker))))
+
+ (t
+
+ (defun po-create-overlay ()
+ "Create and return a deleted overlay structure."
+ (cons (make-marker) (make-marker)))
+
+ (defun po-highlight (overlay start end &optional buffer)
+ "Use OVERLAY to highlight the string from START to END.
+If limits are not relative to the current buffer, use optional BUFFER.
+No doubt that highlighting, when Emacs does not allow it, is a kludge."
+ (save-excursion
+ (and buffer (set-buffer buffer))
+ (let ((modified (buffer-modified-p))
+ (buffer-read-only nil)
+ (inhibit-quit t)
+ (buffer-undo-list t)
+ (text (buffer-substring start end)))
+ (goto-char start)
+ (delete-region start end)
+ (insert-char ? (- end start))
+ (sit-for 0)
+ (setq inverse-video (not inverse-video))
+ (delete-region start end)
+ (insert text)
+ (sit-for 0)
+ (setq inverse-video (not inverse-video))
+ (set-buffer-modified-p modified)))
+ (set-marker (car overlay) start (or buffer (current-buffer)))
+ (set-marker (cdr overlay) end (or buffer (current-buffer))))
+
+ (defun po-rehighlight (overlay)
+ "Ensure OVERLAY is highlighted."
+ (let ((buffer (marker-buffer (car overlay)))
+ (start (marker-position (car overlay)))
+ (end (marker-position (cdr overlay))))
+ (and buffer
+ (name-buffer buffer)
+ (po-highlight overlay start end buffer))))
+
+ (defun po-dehighlight (overlay)
+ "Display normally the last string which OVERLAY highlighted."
+ (let ((buffer (marker-buffer (car overlay)))
+ (start (marker-position (car overlay)))
+ (end (marker-position (cdr overlay))))
+ (if buffer
+ (save-excursion
+ (set-buffer buffer)
+ (let ((modified (buffer-modified-p))
+ (buffer-read-only nil)
+ (inhibit-quit t)
+ (buffer-undo-list t))
+ (let ((text (buffer-substring start end)))
+ (goto-char start)
+ (delete-region start end)
+ (insert-char ? (- end start))
+ (sit-for 0)
+ (delete-region start end)
+ (insert text)
+ (sit-for 0)
+ (set-buffer-modified-p modified)))))
+ (setcar overlay (make-marker))
+ (setcdr overlay (make-marker))))
+
+ )))
+
+;;; Customisation.
+
+(defgroup po nil
+ "Major mode for editing PO files"
+ :group 'i18n)
+
+(defcustom po-auto-edit-with-msgid nil
+ "*Automatically use msgid when editing untranslated entries."
+ :type 'boolean
+ :group 'po)
+
+(defcustom po-auto-fuzzy-on-edit nil
+ "*Automatically mark entries fuzzy when being edited."
+ :type 'boolean
+ :group 'po)
+
+(defcustom po-auto-select-on-unfuzzy nil
+ "*Automatically select some new entry while making an entry not fuzzy."
+ :type 'boolean
+ :group 'po)
+
+(defcustom po-auto-replace-revision-date 'ask
+ "*Automatically revise date in headers. Value is nil, t, or ask."
+ :type '(choice (const nil)
+ (const t)
+ (const ask))
+ :group 'po)
+
+(defcustom po-default-file-header "\
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid \"\"
+msgstr \"\"
+\"Project-Id-Version: PACKAGE VERSION\\n\"
+\"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\\n\"
+\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"
+\"Language-Team: LANGUAGE <LL@li.org>\\n\"
+\"MIME-Version: 1.0\\n\"
+\"Content-Type: text/plain; charset=CHARSET\\n\"
+\"Content-Transfer-Encoding: ENCODING\\n\"
+"
+ "*Default PO file header."
+ :type 'string
+ :group 'po)
+
+(defcustom po-highlighting (or po-EMACS20 po-XEMACS)
+ "*Highlight text whenever appropriate, when non-nil. However, on older
+Emacses, a yet unexplained highlighting bug causes files to get mangled."
+ :type 'boolean
+ :group 'po)
+
+(defcustom po-highlight-face 'highlight
+ "*The face used for PO mode highlighting. For Emacses with overlays.
+Possible values are `highlight', `modeline', `secondary-selection',
+`region', and `underline'.
+This variable can be set by the user to whatever face they desire.
+It's most convenient if the cursor color and highlight color are
+slightly different."
+ :type 'face
+ :group 'po)
+
+(defcustom po-gzip-uuencode-command "gzip -9 | uuencode -m"
+ "*The filter to use for preparing a mail invoice of the PO file.
+Normally \"gzip -9 | uuencode -m\", remove the -9 for lesser compression,
+or remove the -m if you are not using the GNU version of `uuencode'."
+ :type 'string
+ :group 'po)
+
+;;; The following block of declarations has the main purpose of avoiding
+;;; byte compiler warnings. It also introduces some documentation for
+;;; each of these variables, all meant to be local to PO mode buffers.
+
+;; Flag telling that MODE-LINE-STRING should be displayed. See `Window'
+;; page below. Exceptionally, this variable is local to *all* buffers.
+
+(defvar po-mode-flag)
+
+;; PO buffers are kept read-only to prevent random modifications. READ-ONLY
+;; holds the value of the read-only flag before PO mode was entered.
+
+(defvar po-read-only)
+
+;; The current entry extends from START-OF-ENTRY to END-OF-ENTRY, it
+;; includes preceding whitespace and excludes following whitespace. The
+;; start of keyword lines are START-OF-MSGID and START-OF-MSGSTR.
+;; ENTRY-TYPE classifies the entry.
+
+(defvar po-start-of-entry)
+(defvar po-start-of-msgid)
+(defvar po-start-of-msgstr)
+(defvar po-end-of-entry)
+(defvar po-entry-type)
+
+;; A few counters are usefully shown in the Emacs mode line.
+
+(defvar po-translated-counter)
+(defvar po-fuzzy-counter)
+(defvar po-untranslated-counter)
+(defvar po-obsolete-counter)
+(defvar po-mode-line-string)
+
+;; PO mode keeps track of fields being edited, for one given field should
+;; have one editing buffer at most, and for exiting a PO buffer properly
+;; should offer to close all pending edits. Variable EDITED-FIELDS holds an
+;; an list of "slots" of the form: (ENTRY-MARKER EDIT-BUFFER OVERLAY-INFO).
+;; To allow simultaneous edition of the comment and the msgstr of an entry,
+;; ENTRY-MARKER points to the msgid line if a comment is being edited, or to
+;; the msgstr line if the msgstr is being edited. EDIT-BUFFER is the
+;; temporary Emacs buffer used to edit the string. OVERLAY-INFO, when not
+;; nil, holds an overlay (or if overlays are not supported, a cons of two
+;; markers) for this msgid string which became highlighted for the edit.
+
+(defvar po-edited-fields)
+
+;; We maintain a set of movable pointers for returning to entries.
+
+(defvar po-marker-stack)
+
+;; SEARCH path contains a list of directories where files may be found,
+;; in a format suitable for read completion. Each directory includes
+;; its trailing slash. PO mode starts with "./" and "../".
+
+(defvar po-search-path)
+
+;; The following variables are meaningful only when REFERENCE-CHECK
+;; is identical to START-OF-ENTRY, else they should be recomputed.
+;; REFERENCE-ALIST contains all known references for the current
+;; entry, each list element is (PROMPT FILE LINE), where PROMPT may
+;; be used for completing read, FILE is a string and LINE is a number.
+;; REFERENCE-CURSOR is a cycling cursor into REFERENCE-ALIST.
+
+(defvar po-reference-alist)
+(defvar po-reference-cursor)
+(defvar po-reference-check)
+
+;; The following variables are for marking translatable strings in program
+;; sources. KEYWORDS is the list of keywords for marking translatable
+;; strings, kept in a format suitable for reading with completion.
+;; NEXT-FILE-LIST is the list of source files to visit, gotten from the tags
+;; table. STRING-START is the position for the beginning of the last found
+;; string, or nil if the string is invalidated. STRING-END is the position
+;; for the end of the string and indicates where the search should be
+;; resumed, or nil for the beginning of the current file. MARKING-OVERLAY,
+;; if not `nil', holds the overlay which highlight the last found string;
+;; for older Emacses, it holds the cons of two markers around the
+;; highlighted region.
+
+(defvar po-keywords)
+(defvar po-next-file-list)
+(defvar po-string-start)
+(defvar po-string-end)
+(defvar po-marking-overlay)
+
+;;; PO mode variables and constants (usually not to customize).
+
+;; The textdomain should really be "gettext", only trying it for now.
+;; All this requires more thinking, we cannot just do this like that.
+(set-translation-domain "po-mode")
+
+(defun po-mode-version ()
+ "Show Emacs PO mode version."
+ (interactive)
+ (message (_"Emacs PO mode, version %s") (substring "$Revision: 1.1 $" 11 -2)))
+
+(defconst po-help-display-string
+ (_"\
+PO Mode Summary Next Previous Miscellaneous
+*: Later, /: Docum n p Any type . Redisplay
+ /t /M-t Translated /v Version info
+Moving around f M-f Fuzzy ?, h This help
+< First if any o M-o Obsolete = Current index
+> Last if any u M-u Untranslated O Other window
+/SPC Auto select V Validate
+ Msgstr Comments M Mail officially
+Modifying entries RET # Call editor U Undo
+TAB Remove fuzzy mark k K Kill to E Edit out full
+/DEL Fuzzy or fade out w W Copy to Q Forceful quit
+LFD Init with msgid y Y Yank from q Confirm and quit
+
+gettext Keyword Marking Position Stack
+, Find next string Compendiums m Mark and push current
+M-, Mark translatable *c To compendium r Pop and return
+M-. Change mark, mark *M-C Select, save x Exchange current/top
+
+Program Sources Auxiliary Files Lexicography
+s Cycle reference a Cycle file *l Lookup translation
+M-s Select reference M-a Select file *M-l Add/edit translation
+S Consider path A Consider PO file *L Consider lexicon
+M-S Ignore path M-A Ignore PO file *M-L Ignore lexicon
+")
+ "Help page for PO mode.")
+
+(defconst po-mode-menu-layout
+ '("PO"
+ ("Moving around"
+ ["Auto select" po-auto-select-entry t]
+ "---"
+ "Forward"
+ ["Any next" po-next-entry t]
+ ["Next translated" po-next-translated-entry t]
+ ["Next fuzzy" po-next-fuzzy-entry t]
+ ["Next obsolete" po-next-obsolete-entry t]
+ ["Next untranslated" po-next-untranslated-entry t]
+ ["Last file entry" po-last-entry t]
+ "---"
+ "Backward"
+ ["Any previous" po-previous-entry t]
+ ["Previous translated" po-previous-translated-entry t]
+ ["Previous fuzzy" po-previous-fuzzy-entry t]
+ ["Previous obsolete" po-previous-obsolete-entry t]
+ ["Previous untranslated" po-previous-untranslated-entry t]
+ ["First file entry" po-first-entry t]
+ "---"
+ "Position stack"
+ ["Mark and push current" po-push-location t]
+ ["Pop and return" po-pop-location t]
+ ["Exchange current/top" po-exchange-location t]
+ "---"
+ ["Redisplay" po-current-entry t]
+ ["Current index" po-statistics t])
+ ("Modifying entries"
+ ["Undo" po-undo t]
+ "---"
+ "Msgstr"
+ ["Edit msgstr" po-edit-msgstr t]
+ ["Kill msgstr" po-kill-msgstr t]
+ ["Save msgstr" po-kill-ring-save-msgstr t]
+ ["Yank msgstr" po-yank-msgstr t]
+ "---"
+ "Comments"
+ ["Edit comment" po-edit-comment t]
+ ["Kill comment" po-kill-comment t]
+ ["Save comment" po-kill-ring-save-comment t]
+ ["Yank comment" po-yank-comment t]
+ "---"
+ ["Remove fuzzy mark" po-unfuzzy t]
+ ["Fuzzy or fade out" po-fade-out-entry t]
+ ["Init with msgid" po-msgid-to-msgstr t])
+ ("Other files"
+ ["Other window" po-other-window t]
+ "---"
+ "Program sources"
+ ["Cycle reference" po-cycle-source-reference t]
+ ["Select reference" po-select-source-reference t]
+ ["Consider path" po-consider-source-path t]
+ ["Ignore path" po-ignore-source-path t]
+ "---"
+ "Compendiums"
+ ["To compendium" po-save-entry nil]
+ ["Select, save" po-select-and-save-entry nil]
+ "---"
+ "Auxiliary files"
+ ["Cycle file" po-cycle-auxiliary nil]
+ ["Select file" po-select-auxiliary nil]
+ ["Consider file" po-consider-as-auxiliary nil]
+ ["Ignore file" po-ignore-as-auxiliary nil]
+ "---"
+ "Lexicography"
+ ["Lookup translation" po-lookup-lexicons nil]
+ ["Add/edit translation" po-edit-lexicon-entry nil]
+ ["Consider lexicon" po-consider-lexicon-file nil]
+ ["Ignore lexicon" po-ignore-lexicon-file nil])
+ "---"
+ "Source marking"
+ ["Find first string" (po-tags-search '(nil)) t]
+ ["Prefer keyword" (po-select-mark-and-mark '(nil)) t]
+ ["Find next string" po-tags-search t]
+ ["Mark preferred" po-mark-translatable t]
+ ["Mark with keyword" po-select-mark-and-mark t]
+ "---"
+ ["Version info" po-mode-version t]
+ ["Help page" po-help t]
+ ["Validate" po-validate t]
+ ["Mail officially" po-send-mail t]
+ ["Edit out full" po-edit-out-full t]
+ "---"
+ ["Forceful quit" po-quit t]
+ ["Soft quit" po-confirm-and-quit t])
+ "Menu layout for PO mode.")
+
+(defconst po-subedit-message
+ (_"Type `C-c C-c' once done, or `C-c C-k' to abort edit")
+ "Message to post in the minibuffer when an edit buffer is displayed.")
+
+(defconst po-content-type-charset-alist
+ '((euc . japanese-iso-8bit))
+ "How to convert Content-Type into a Mule coding system.")
+
+(defvar po-auxiliary-list nil
+ "List of auxiliary PO files, in completing read format.")
+
+(defvar po-auxiliary-cursor nil
+ "Cursor into the `po-auxiliary-list'.")
+
+(defvar po-translation-project-address
+ "translation@iro.umontreal.ca"
+ "Electronic mail address of the Translation Project.")
+
+(defvar po-compose-mail-function
+ (let ((functions '(compose-mail-other-window
+ message-mail-other-window
+ compose-mail
+ message-mail))
+ result)
+ (while (and (not result) functions)
+ (if (fboundp (car functions))
+ (setq result (car functions))
+ (setq functions (cdr functions))))
+ (cond (result)
+ ((fboundp 'mail-other-window)
+ (function (lambda (to subject)
+ (mail-other-window nil to subject))))
+ ((fboundp 'mail)
+ (function (lambda (to subject)
+ (mail nil to subject))))
+ (t (function (lambda (to subject)
+ (error (_"I do not know how to mail to `%s'") to))))))
+ "Function to start composing an electronic message.")
+
+(defvar po-any-msgid-regexp
+ "^\\(#~?[ \t]*\\)?msgid.*\n\\(\\(#~?[ \t]*\\)?\".*\n\\)*"
+ "Regexp matching a whole msgid field, whether obsolete or not.")
+
+(defvar po-any-msgstr-regexp
+ "^\\(#~?[ \t]*\\)?msgstr.*\n\\(\\(#~?[ \t]*\\)?\".*\n\\)*"
+ "Regexp matching a whole msgstr field, whether obsolete or not.")
+
+(defvar po-msgfmt-program "msgfmt"
+ "Path to msgfmt program from GNU gettext package.")
+
+;; Font lock based highlighting code.
+(defconst po-font-lock-keywords
+ '(
+ ("^\\(msgid \\|msgstr \\)?\"\\|\"$" . font-lock-keyword-face)
+ ("\\\\.\\|%[-.0-9ul]*[a-zA-Z]" . font-lock-variable-name-face)
+ ("^# .*\\|^#[:,]?" . font-lock-comment-face)
+ ("^#:\\(.*\\)" 1 font-lock-reference-face)
+ ;; The following line does not work, and I wonder why.
+ ;;("^#,\\(.*\\)" 1 font-function-name-reference-face)
+ )
+ "Additional expressions to highlight in PO mode.")
+
+;; Old activator for `font lock'. Is it still useful? I don't think so.
+;;
+;;(if (boundp 'font-lock-keywords)
+;; (put 'po-mode 'font-lock-keywords 'po-font-lock-keywords))
+
+;; `hilit19' based highlighting code has been disabled, as most probably
+;; nobody really needs it (it also generates ugly byte-compiler warnings).
+;;
+;;(if (fboundp 'hilit-set-mode-patterns)
+;; (hilit-set-mode-patterns 'po-mode
+;; '(("^# .*\\|^#$" nil comment)
+;; ("^#[.,:].*" nil include)
+;; ("^\\(msgid\\|msgstr\\) *\"" nil keyword)
+;; ("^\"\\|\"$" nil keyword))))
+
+;;; Mode activation.
+
+(eval-and-compile
+ (if po-EMACS20
+
+ (defun po-find-file-coding-system (arg-list)
+ "Return a Mule (DECODING . ENCODING) pair, according to PO file charset.
+Called through file-coding-system-alist, before the file is visited for real."
+ (and (eq (car arg-list) 'insert-file-contents)
+ (with-temp-buffer
+ (let ((coding-system-for-read 'no-conversion))
+ ;; Is 4096 enough? FIXME: See archives to decide! Some
+ ;; translators insert looong comments for the header entry.
+ (insert-file-contents (nth 1 arg-list) nil 0 4096)
+ (if (re-search-forward
+ "^\"Content-Type: text/plain;[ \t]*charset=\\([^\\]+\\)"
+ nil t)
+ (let* ((charset (intern (downcase (buffer-substring
+ (match-beginning 1)
+ (match-end 1)))))
+ (slot (assq charset
+ po-content-type-charset-alist)))
+ (list (cond (slot (cdr slot))
+ ((memq charset (coding-system-list)) charset)
+ (t 'no-conversion))))
+ '(no-conversion))))))
+
+ ))
+
+(defvar po-mode-map nil
+ "Keymap for PO mode.")
+(if po-mode-map
+ ()
+ ;; The following line because (make-sparse-keymap) does not work on Demacs.
+ (setq po-mode-map (make-keymap))
+ (suppress-keymap po-mode-map)
+ (define-key po-mode-map "\C-i" 'po-unfuzzy)
+ (define-key po-mode-map "\C-j" 'po-msgid-to-msgstr)
+ (define-key po-mode-map "\C-m" 'po-edit-msgstr)
+ (define-key po-mode-map " " 'po-auto-select-entry)
+ (define-key po-mode-map "?" 'po-help)
+ (define-key po-mode-map "#" 'po-edit-comment)
+ (define-key po-mode-map "," 'po-tags-search)
+ (define-key po-mode-map "." 'po-current-entry)
+ (define-key po-mode-map "<" 'po-first-entry)
+ (define-key po-mode-map "=" 'po-statistics)
+ (define-key po-mode-map ">" 'po-last-entry)
+ (define-key po-mode-map "a" 'po-cycle-auxiliary)
+;;;; (define-key po-mode-map "c" 'po-save-entry)
+ (define-key po-mode-map "f" 'po-next-fuzzy-entry)
+ (define-key po-mode-map "h" 'po-help)
+ (define-key po-mode-map "k" 'po-kill-msgstr)
+;;;; (define-key po-mode-map "l" 'po-lookup-lexicons)
+ (define-key po-mode-map "m" 'po-push-location)
+ (define-key po-mode-map "n" 'po-next-entry)
+ (define-key po-mode-map "o" 'po-next-obsolete-entry)
+ (define-key po-mode-map "p" 'po-previous-entry)
+ (define-key po-mode-map "q" 'po-confirm-and-quit)
+ (define-key po-mode-map "r" 'po-pop-location)
+ (define-key po-mode-map "s" 'po-cycle-source-reference)
+ (define-key po-mode-map "t" 'po-next-translated-entry)
+ (define-key po-mode-map "u" 'po-next-untranslated-entry)
+ (define-key po-mode-map "v" 'po-mode-version)
+ (define-key po-mode-map "w" 'po-kill-ring-save-msgstr)
+ (define-key po-mode-map "x" 'po-exchange-location)
+ (define-key po-mode-map "y" 'po-yank-msgstr)
+ (define-key po-mode-map "A" 'po-consider-as-auxiliary)
+ (define-key po-mode-map "E" 'po-edit-out-full)
+ (define-key po-mode-map "K" 'po-kill-comment)
+;;;; (define-key po-mode-map "L" 'po-consider-lexicon-file)
+ (define-key po-mode-map "M" 'po-send-mail)
+ (define-key po-mode-map "O" 'po-other-window)
+ (define-key po-mode-map "Q" 'po-quit)
+ (define-key po-mode-map "S" 'po-consider-source-path)
+ (define-key po-mode-map "U" 'po-undo)
+ (define-key po-mode-map "V" 'po-validate)
+ (define-key po-mode-map "W" 'po-kill-ring-save-comment)
+ (define-key po-mode-map "Y" 'po-yank-comment)
+ (define-key po-mode-map "\177" 'po-fade-out-entry)
+ (define-key po-mode-map "\M-," 'po-mark-translatable)
+ (define-key po-mode-map "\M-." 'po-select-mark-and-mark)
+ (define-key po-mode-map "\M-a" 'po-select-auxiliary)
+;;;; (define-key po-mode-map "\M-c" 'po-select-and-save-entry)
+ (define-key po-mode-map "\M-f" 'po-previous-fuzzy-entry)
+;;;; (define-key po-mode-map "\M-l" 'po-edit-lexicon-entry)
+ (define-key po-mode-map "\M-o" 'po-previous-obsolete-entry)
+ (define-key po-mode-map "\M-t" 'po-previous-translated-entry)
+ (define-key po-mode-map "\M-u" 'po-previous-untranslated-entry)
+ (define-key po-mode-map "\M-s" 'po-select-source-reference)
+ (define-key po-mode-map "\M-A" 'po-ignore-as-auxiliary)
+;;;; (define-key po-mode-map "\M-L" 'po-ignore-lexicon-file)
+ (define-key po-mode-map "\M-S" 'po-ignore-source-path)
+ )
+
+(defun po-mode ()
+ "Major mode for translators when they edit PO files.
+Special commands:\\{po-mode-map}
+Turning on PO mode calls the value of the variable `po-mode-hook',
+if that value is non-nil. Behaviour may be adjusted through some variables,
+all reachable through `M-x customize', in group `Emacs.Editing.I18n.Po'."
+
+ (interactive)
+ (kill-all-local-variables)
+ (setq major-mode 'po-mode
+ mode-name "PO")
+ (use-local-map po-mode-map)
+ (if (fboundp 'easy-menu-define)
+ (easy-menu-define po-mode-menu po-mode-map "" po-mode-menu-layout))
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(po-font-lock-keywords t))
+
+ (make-local-variable 'po-read-only)
+ (setq po-read-only buffer-read-only
+ buffer-read-only t)
+
+ (make-local-variable 'po-start-of-entry)
+ (make-local-variable 'po-start-of-msgid)
+ (make-local-variable 'po-start-of-msgstr)
+ (make-local-variable 'po-end-of-entry)
+ (make-local-variable 'po-entry-type)
+
+ (make-local-variable 'po-translated-counter)
+ (make-local-variable 'po-fuzzy-counter)
+ (make-local-variable 'po-untranslated-counter)
+ (make-local-variable 'po-obsolete-counter)
+ (make-local-variable 'po-mode-line-string)
+
+ (setq po-mode-flag t)
+
+ (po-check-file-header)
+ (po-compute-counters nil)
+
+ (make-local-variable 'po-edited-fields)
+ (setq po-edited-fields nil)
+
+ (make-local-variable 'po-marker-stack)
+ (setq po-marker-stack nil)
+
+ (make-local-variable 'po-search-path)
+ (setq po-search-path '(("./") ("../")))
+
+ (make-local-variable 'po-reference-alist)
+ (make-local-variable 'po-reference-cursor)
+ (make-local-variable 'po-reference-check)
+ (setq po-reference-alist nil
+ po-reference-cursor nil
+ po-reference-check 0)
+
+ (make-local-variable 'po-keywords)
+ (make-local-variable 'po-next-file-list)
+ (make-local-variable 'po-string-start)
+ (make-local-variable 'po-string-end)
+ (make-local-variable 'po-marking-overlay)
+ (setq po-keywords '(("gettext") ("gettext_noop") ("_") ("N_"))
+ po-next-file-list nil
+ po-string-start nil
+ po-string-end nil
+ po-marking-overlay (po-create-overlay))
+
+ (message (_"You may type `h' or `?' for a short PO mode reminder."))
+ (run-hooks 'po-mode-hook))
+
+;;; Window management.
+
+(make-variable-buffer-local 'po-mode-flag)
+
+(defvar po-mode-line-entry '(po-mode-flag (" " po-mode-line-string))
+ "Mode line format entry displaying MODE-LINE-STRING.")
+
+;; Insert MODE-LINE-ENTRY in mode line, but on first load only.
+(or (member po-mode-line-entry mode-line-format)
+ (let ((entry (member 'global-mode-string mode-line-format)))
+ (setcdr entry (cons po-mode-line-entry (cdr entry)))))
+
+(defun po-update-mode-line-string ()
+ "Compute a new statistics string to display in mode line."
+ (setq po-mode-line-string
+ (concat (format "%dt" po-translated-counter)
+ (if (> po-fuzzy-counter 0)
+ (format "+%df" po-fuzzy-counter))
+ (if (> po-untranslated-counter 0)
+ (format "+%du" po-untranslated-counter))
+ (if (> po-obsolete-counter 0)
+ (format "+%do" po-obsolete-counter))))
+ (po-force-mode-line-update))
+
+(defun po-type-counter ()
+ "Return the symbol name of the counter appropriate for the current entry."
+ (cond ((eq po-entry-type 'obsolete) 'po-obsolete-counter)
+ ((eq po-entry-type 'fuzzy) 'po-fuzzy-counter)
+ ((eq po-entry-type 'translated) 'po-translated-counter)
+ ((eq po-entry-type 'untranslated) 'po-untranslated-counter)
+ (t (error (_"Unknown entry type")))))
+
+(defun po-decrease-type-counter ()
+ "Decrease the counter corresponding to the nature of the current entry."
+ (let ((counter (po-type-counter)))
+ (set counter (1- (eval counter)))))
+
+(defun po-increase-type-counter ()
+ "Increase the counter corresponding to the nature of the current entry.
+Then, update the mode line counters."
+ (let ((counter (po-type-counter)))
+ (set counter (1+ (eval counter))))
+ (po-update-mode-line-string))
+
+;; Avoid byte compiler warnings.
+(defvar po-fuzzy-regexp)
+(defvar po-untranslated-regexp)
+
+(defun po-compute-counters (flag)
+ "Prepare counters for mode line display. If FLAG, also echo entry position."
+ (and flag (po-find-span-of-entry))
+ (setq po-translated-counter 0
+ po-fuzzy-counter 0
+ po-untranslated-counter 0
+ po-obsolete-counter 0)
+ (let ((position 0) (total 0) here)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward po-any-msgstr-regexp nil t)
+ (and (= (% total 20) 0)
+ (if flag
+ (message (_"Position %d/%d") position total)
+ (message (_"Position %d") total)))
+ (setq here (point))
+ (goto-char (match-beginning 0))
+ (setq total (1+ total))
+ (and flag (eq (point) po-start-of-msgstr) (setq position total))
+ (cond ((eq (following-char) ?#)
+ (setq po-obsolete-counter (1+ po-obsolete-counter)))
+ ((looking-at po-untranslated-regexp)
+ (setq po-untranslated-counter (1+ po-untranslated-counter)))
+ (t (setq po-translated-counter (1+ po-translated-counter))))
+ (goto-char here))
+
+ ;; Make another pass just for the fuzzy entries, kind of kludgey.
+ ;; FIXME: Counts will be wrong if untranslated entries are fuzzy, yet
+ ;; this should not normally happen.
+ (goto-char (point-min))
+ (while (re-search-forward po-fuzzy-regexp nil t)
+ (setq po-fuzzy-counter (1+ po-fuzzy-counter)))
+ (setq po-translated-counter (- po-translated-counter po-fuzzy-counter)))
+
+ ;; Push the results out.
+ (if flag
+ (message (_"\
+Position %d/%d; %d translated, %d fuzzy, %d untranslated, %d obsolete")
+ position total po-translated-counter po-fuzzy-counter
+ po-untranslated-counter po-obsolete-counter)
+ (message "")))
+ (po-update-mode-line-string))
+
+(defun po-redisplay ()
+ "Redisplay the current entry."
+ ;; FIXME: Should try to fit the whole entry on the window. If this is not
+ ;; possible, should try to fit the comment and the msgid. Otherwise,
+ ;; should try to fit the msgid. Else, the first line of the msgid should
+ ;; be at the top of the window.
+ (goto-char po-start-of-msgid))
+
+(defun po-other-window ()
+ "Get the cursor into another window, out of PO mode."
+ (interactive)
+ (if (one-window-p t)
+ (progn
+ (split-window)
+ (switch-to-buffer (other-buffer)))
+ (other-window 1)))
+
+;;; Processing the PO file header entry.
+
+(defun po-check-file-header ()
+ "Create a missing PO mode file header, or replace an oldish one."
+ (save-excursion
+ (let ((buffer-read-only po-read-only)
+ insert-flag end-of-header)
+ (goto-char (point-min))
+ (if (re-search-forward po-any-msgstr-regexp nil t)
+ (progn
+
+ ;; There is at least one entry.
+ (goto-char (match-beginning 0))
+ (previous-line 1)
+ (setq end-of-header (match-end 0))
+ (if (looking-at "msgid \"\"\n")
+
+ ;; There is indeed a PO file header.
+ (if (re-search-forward "\n\"PO-Revision-Date: "
+ end-of-header t)
+ nil
+
+ ;; This is an oldish header. Replace it all.
+ (goto-char end-of-header)
+ (while (> (point) (point-min))
+ (previous-line 1)
+ (insert "#~ ")
+ (beginning-of-line))
+ (beginning-of-line)
+ (setq insert-flag t))
+
+ ;; The first entry is not a PO file header, insert one.
+ (setq insert-flag t)))
+
+ ;; Not a single entry found.
+ (setq insert-flag t))
+
+ (goto-char (point-min))
+ (and insert-flag (insert po-default-file-header "\n")))))
+
+(defun po-replace-revision-date ()
+ "Replace the revision date by current time in the PO file header."
+ (if (fboundp 'format-time-string)
+ (if (or (eq po-auto-replace-revision-date t)
+ (and (eq po-auto-replace-revision-date 'ask)
+ (y-or-n-p (_"May I set PO-Revision-Date? "))))
+ (save-excursion
+ (goto-char (point-min))
+ (if (re-search-forward "^\"PO-Revision-Date:.*" nil t)
+ (let* ((buffer-read-only po-read-only)
+ (time (current-time))
+ (seconds (or (car (current-time-zone time)) 0))
+ (minutes (/ (abs seconds) 60))
+ (zone (format "%c%02d:%02d"
+ (if (< seconds 0) ?- ?+)
+ (/ minutes 60)
+ (% minutes 60))))
+ (replace-match
+ (concat "\"PO-Revision-Date: "
+ (format-time-string "%Y-%m-%d %H:%M" time)
+ zone "\\n\"")
+ t t))))
+ (message ""))
+ (message (_"PO-Revision-Date should be adjusted..."))))
+
+;;; Handling span of entry, entry type and entry attributes.
+
+(defun po-find-span-of-entry ()
+ "Find the extent of the PO file entry where the cursor is. Set variables
+PO-START-OF-ENTRY, PO-START-OF-MSGID, PO-START-OF-MSGSTR, PO-END-OF-ENTRY
+and PO-ENTRY-TYPE to meaningful values. Decreasing priority of type
+interpretation is: obsolete, fuzzy, untranslated or translated."
+ (let ((here (point)))
+ (if (re-search-backward po-any-msgstr-regexp nil t)
+ (progn
+
+ ;; After a backward match, (match-end 0) will not extend
+ ;; beyond point, in case point was *inside* the regexp. We
+ ;; need a dependable (match-end 0), so we redo the match in
+ ;; the forward direction.
+ (re-search-forward po-any-msgstr-regexp)
+ (if (<= (match-end 0) here)
+ (progn
+
+ ;; We most probably found the msgstr of the previous
+ ;; entry. The current entry then starts just after
+ ;; its end, save this information just in case.
+ (setq po-start-of-entry (match-end 0))
+
+ ;; However, it is also possible that we are located in
+ ;; the crumb after the last entry in the file. If
+ ;; yes, we know the middle and end of last PO entry.
+ (setq po-start-of-msgstr (match-beginning 0)
+ po-end-of-entry (match-end 0))
+
+ (if (re-search-forward po-any-msgstr-regexp nil t)
+ (progn
+
+ ;; We definitely were not in the crumb.
+ (setq po-start-of-msgstr (match-beginning 0)
+ po-end-of-entry (match-end 0)))
+
+ ;; We were in the crumb. The start of the last PO
+ ;; file entry is the end of the previous msgstr if
+ ;; any, or else, the beginning of the file.
+ (goto-char po-start-of-msgstr)
+ (setq po-start-of-entry
+ (if (re-search-backward po-any-msgstr-regexp nil t)
+ (match-end 0)
+ (point-min)))))
+
+ ;; The cursor was inside msgstr of the current entry.
+ (setq po-start-of-msgstr (match-beginning 0)
+ po-end-of-entry (match-end 0))
+ ;; The start of this entry is the end of the previous
+ ;; msgstr if any, or else, the beginning of the file.
+ (goto-char po-start-of-msgstr)
+ (setq po-start-of-entry
+ (if (re-search-backward po-any-msgstr-regexp nil t)
+ (match-end 0)
+ (point-min)))))
+
+ ;; The cursor was before msgstr in the first entry in the file.
+ (setq po-start-of-entry (point-min))
+ (goto-char po-start-of-entry)
+ ;; There is at least the PO file header, so this should match.
+ (re-search-forward po-any-msgstr-regexp)
+ (setq po-start-of-msgstr (match-beginning 0)
+ po-end-of-entry (match-end 0)))
+
+ ;; Find start of msgid.
+ (goto-char po-start-of-entry)
+ (re-search-forward po-any-msgid-regexp)
+ (setq po-start-of-msgid (match-beginning 0))
+
+ ;; Classify the entry.
+ (setq po-entry-type
+ (if (eq (following-char) ?#)
+ 'obsolete
+ (goto-char po-start-of-entry)
+ (if (re-search-forward po-fuzzy-regexp po-start-of-msgid t)
+ 'fuzzy
+ (goto-char po-start-of-msgstr)
+ (if (looking-at po-untranslated-regexp)
+ 'untranslated
+ 'translated))))
+
+ ;; Put the cursor back where it was.
+ (goto-char here)))
+
+(defun po-add-attribute (name)
+ "Add attribute NAME to the current entry, unless it is already there."
+ (save-excursion
+ (let ((buffer-read-only po-read-only))
+ (goto-char po-start-of-entry)
+ (if (re-search-forward "\n#[,!] .*" po-start-of-msgid t)
+ (save-restriction
+ (narrow-to-region (match-beginning 0) (match-end 0))
+ (goto-char (point-min))
+ (if (re-search-forward (concat "\\b" name "\\b") nil t)
+ nil
+ (goto-char (point-max))
+ (insert ", " name)))
+ (skip-chars-forward "\n")
+ (while (eq (following-char) ?#)
+ (next-line 1))
+ (insert "#, " name "\n")))))
+
+(defun po-delete-attribute (name)
+ "Delete attribute NAME from the current entry, if any."
+ (save-excursion
+ (let ((buffer-read-only po-read-only))
+ (goto-char po-start-of-entry)
+ (if (re-search-forward "\n#[,!] .*" po-start-of-msgid t)
+ (save-restriction
+ (narrow-to-region (match-beginning 0) (match-end 0))
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "\\(\n#[,!] " name "$\\|, " name "$\\| " name ",\\)")
+ nil t)
+ (replace-match "" t t)))))))
+
+;;; Entry positionning.
+
+(defun po-say-location-depth ()
+ "Tell how many entries in the entry location stack."
+ (let ((depth (length po-marker-stack)))
+ (cond ((= depth 0) (message (_"Empty location stack")))
+ ((= depth 1) (message (_"One entry in location stack")))
+ (t (message (_"%d entries in location stack") depth)))))
+
+(defun po-push-location ()
+ "Stack the location of the current entry, for later return."
+ (interactive)
+ (po-find-span-of-entry)
+ (save-excursion
+ (goto-char po-start-of-msgid)
+ (setq po-marker-stack (cons (point-marker) po-marker-stack)))
+ (po-say-location-depth))
+
+(defun po-pop-location ()
+ "Unstack a saved location, and return to the corresponding entry."
+ (interactive)
+ (if po-marker-stack
+ (progn
+ (goto-char (car po-marker-stack))
+ (setq po-marker-stack (cdr po-marker-stack))
+ (po-current-entry)
+ (po-say-location-depth))
+ (error (_"The entry location stack is empty"))))
+
+(defun po-exchange-location ()
+ "Exchange the location of the current entry with the top of stack."
+ (interactive)
+ (if po-marker-stack
+ (progn
+ (po-find-span-of-entry)
+ (goto-char po-start-of-msgid)
+ (let ((location (point-marker)))
+ (goto-char (car po-marker-stack))
+ (setq po-marker-stack (cons location (cdr po-marker-stack))))
+ (po-current-entry)
+ (po-say-location-depth))
+ (error (_"The entry location stack is empty"))))
+
+(defun po-current-entry ()
+ "Display the current entry."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-redisplay))
+
+(defun po-first-entry-with-regexp (regexp)
+ "Display the first entry in the file which msgstr matches REGEXP."
+ (let ((here (point)))
+ (goto-char (point-min))
+ (if (re-search-forward regexp nil t)
+ (progn
+ (goto-char (match-beginning 0))
+ (po-current-entry))
+ (goto-char here)
+ (error (_"There is no such entry")))))
+
+(defun po-last-entry-with-regexp (regexp)
+ "Display the last entry in the file which msgstr matches REGEXP."
+ (let ((here (point)))
+ (goto-char (point-max))
+ (if (re-search-backward regexp nil t)
+ (po-current-entry)
+ (goto-char here)
+ (error (_"There is no such entry")))))
+
+(defun po-next-entry-with-regexp (regexp wrap)
+ "Display the entry following the current entry which msgstr matches REGEXP.
+If WRAP is not nil, the search may wrap around the buffer."
+ (po-find-span-of-entry)
+ (let ((here (point)))
+ (goto-char po-end-of-entry)
+ (if (re-search-forward regexp nil t)
+ (progn
+ (goto-char (match-beginning 0))
+ (po-current-entry))
+ (if (and wrap
+ (progn
+ (goto-char (point-min))
+ (re-search-forward regexp po-start-of-entry t)))
+ (progn
+ (goto-char (match-beginning 0))
+ (po-current-entry)
+ (message (_"Wrapping around the buffer")))
+ (goto-char here)
+ (error (_"There is no such entry"))))))
+
+(defun po-previous-entry-with-regexp (regexp wrap)
+ "Redisplay the entry preceding the current entry which msgstr matches REGEXP.
+If WRAP is not nil, the search may wrap around the buffer."
+ (po-find-span-of-entry)
+ (let ((here (point)))
+ (goto-char po-start-of-entry)
+ (if (re-search-backward regexp nil t)
+ (po-current-entry)
+ (if (and wrap
+ (progn
+ (goto-char (point-max))
+ (re-search-backward regexp po-end-of-entry t)))
+ (progn
+ (po-current-entry)
+ (message (_"Wrapping around the buffer")))
+ (goto-char here)
+ (error (_"There is no such entry"))))))
+
+;; Any entries.
+
+(defun po-first-entry ()
+ "Display the first entry."
+ (interactive)
+ (po-first-entry-with-regexp po-any-msgstr-regexp))
+
+(defun po-last-entry ()
+ "Display the last entry."
+ (interactive)
+ (po-last-entry-with-regexp po-any-msgstr-regexp))
+
+(defun po-next-entry ()
+ "Display the entry following the current entry."
+ (interactive)
+ (po-next-entry-with-regexp po-any-msgstr-regexp nil))
+
+(defun po-previous-entry ()
+ "Display the entry preceding the current entry."
+ (interactive)
+ (po-previous-entry-with-regexp po-any-msgstr-regexp nil))
+
+;; Untranslated entries.
+
+(defvar po-after-entry-regexp
+ "\\(\\'\\|\\(#[ \t]*\\)?[^\"]\\)"
+ "Regexp which should be true after a full msgstr string matched.")
+
+(defvar po-untranslated-regexp
+ (concat "^msgstr[ \t]*\"\"\n" po-after-entry-regexp)
+ "Regexp matching a whole msgstr field, but only if active and empty.")
+
+(defun po-next-untranslated-entry ()
+ "Find the next untranslated entry, wrapping around if necessary."
+ (interactive)
+ (po-next-entry-with-regexp po-untranslated-regexp t))
+
+(defun po-previous-untranslated-entry ()
+ "Find the previous untranslated entry, wrapping around if necessary."
+ (interactive)
+ (po-previous-entry-with-regexp po-untranslated-regexp t))
+
+(defun po-msgid-to-msgstr ()
+ "Use another window to edit msgstr reinitialized with msgid."
+ (interactive)
+ (po-find-span-of-entry)
+ (if (or (eq po-entry-type 'untranslated)
+ (eq po-entry-type 'obsolete)
+ (y-or-n-p (_"Really loose previous translation? ")))
+ (po-set-msgstr (po-get-msgid nil)))
+ (message ""))
+
+;; Obsolete entries.
+
+(defvar po-obsolete-msgstr-regexp
+ "^#~?[ \t]*msgstr.*\n\\(#~?[ \t]*\".*\n\\)*"
+ "Regexp matching a whole msgstr field of an obsolete entry.")
+
+(defun po-next-obsolete-entry ()
+ "Find the next obsolete entry, wrapping around if necessary."
+ (interactive)
+ (po-next-entry-with-regexp po-obsolete-msgstr-regexp t))
+
+(defun po-previous-obsolete-entry ()
+ "Find the previous obsolete entry, wrapping around if necessary."
+ (interactive)
+ (po-previous-entry-with-regexp po-obsolete-msgstr-regexp t))
+
+;; Fuzzy entries.
+
+(defvar po-fuzzy-regexp "^#[,!] .*fuzzy"
+ "Regexp matching the string inserted by msgmerge for translations
+which does not match exactly.")
+
+(defun po-next-fuzzy-entry ()
+ "Find the next fuzzy entry, wrapping around if necessary."
+ (interactive)
+ (po-next-entry-with-regexp po-fuzzy-regexp t))
+
+(defun po-previous-fuzzy-entry ()
+ "Find the next fuzzy entry, wrapping around if necessary."
+ (interactive)
+ (po-previous-entry-with-regexp po-fuzzy-regexp t))
+
+(defun po-unfuzzy ()
+ "Remove the fuzzy attribute for the current entry."
+ (interactive)
+ (po-find-span-of-entry)
+ (cond ((eq po-entry-type 'fuzzy)
+ (po-decrease-type-counter)
+ (po-delete-attribute "fuzzy")
+ (po-current-entry)
+ (po-increase-type-counter)))
+ (if po-auto-select-on-unfuzzy
+ (po-auto-select-entry))
+ (po-update-mode-line-string))
+
+;; Translated entries.
+
+(defun po-next-translated-entry ()
+ "Find the next untranslated entry, wrapping around if necessary."
+ (interactive)
+ (if (= po-translated-counter 0)
+ (error (_"There is no such entry"))
+ (po-next-entry-with-regexp po-untranslated-regexp t)
+ (po-find-span-of-entry)
+ (while (not (eq po-entry-type 'translated))
+ (po-next-entry-with-regexp po-any-msgstr-regexp t)
+ (po-find-span-of-entry))))
+
+(defun po-previous-translated-entry ()
+ "Find the previous untranslated entry, wrapping around if necessary."
+ (interactive)
+ (if (= po-translated-counter 0)
+ (error (_"There is no such entry"))
+ (po-previous-entry-with-regexp po-any-msgstr-regexp t)
+ (po-find-span-of-entry)
+ (while (not (eq po-entry-type 'translated))
+ (po-previous-entry-with-regexp po-untranslated-regexp t)
+ (po-find-span-of-entry))))
+
+;; Auto-selection feature.
+
+(defun po-auto-select-entry ()
+ "Select the next entry having the same type as the current one.
+If none, wrap from the beginning of the buffer with another type,
+going from untranslated to fuzzy, and from fuzzy to obsolete.
+Plain translated entries are always disregarded unless there are
+no entries of the other types."
+ (interactive)
+ (po-find-span-of-entry)
+ (goto-char po-end-of-entry)
+ (if (and (= po-untranslated-counter 0)
+ (= po-fuzzy-counter 0)
+ (= po-obsolete-counter 0))
+
+ ;; All entries are plain translated. Next entry will do, or
+ ;; wrap around if there is none.
+ (if (re-search-forward po-any-msgstr-regexp nil t)
+ (goto-char (match-beginning 0))
+ (goto-char (point-min)))
+
+ ;; If over a translated entry, look for an untranslated one first.
+ ;; Else, look for an entry of the same type first.
+ (let ((goal (if (eq po-entry-type 'translated)
+ 'untranslated
+ po-entry-type)))
+ (while goal
+
+ ;; Find an untranslated entry, or wrap up for a fuzzy entry.
+ (if (eq goal 'untranslated)
+ (if (and (> po-untranslated-counter 0)
+ (re-search-forward po-untranslated-regexp nil t))
+ (progn
+ (goto-char (match-beginning 0))
+ (setq goal nil))
+ (goto-char (point-min))
+ (setq goal 'fuzzy)))
+
+ ;; Find a fuzzy entry, or wrap up for an obsolete entry.
+ (if (eq goal 'fuzzy)
+ (if (and (> po-fuzzy-counter 0)
+ (re-search-forward po-fuzzy-regexp nil t))
+ (progn
+ (goto-char (match-beginning 0))
+ (setq goal nil))
+ (goto-char (point-min))
+ (setq goal 'obsolete)))
+
+ ;; Find an obsolete entry, or wrap up for an untranslated entry.
+ (if (eq goal 'obsolete)
+ (if (and (> po-obsolete-counter 0)
+ (re-search-forward po-obsolete-msgstr-regexp nil t))
+ (progn
+ (goto-char (match-beginning 0))
+ (setq goal nil))
+ (goto-char (point-min))
+ (setq goal 'untranslated))))))
+
+ ;; Display this entry nicely.
+ (po-current-entry))
+
+;;; Killing and yanking fields.
+
+(defun po-extract-unquoted (buffer start end)
+ "Extract and return the unquoted string in BUFFER going from START to END.
+Crumb preceding or following the quoted string is ignored."
+ (po-with-temp-buffer
+ (insert-buffer-substring buffer start end)
+ ;; Remove preceding crumb.
+ (goto-char (point-min))
+ (search-forward "\"")
+ (delete-region (point-min) (point))
+ ;; Remove following crumb.
+ (goto-char (point-max))
+ (search-backward "\"")
+ (delete-region (point) (point-max))
+ ;; Glue concatenated strings.
+ (goto-char (point-min))
+ (while (re-search-forward "\"[ \t]*\\\\?\n\\(#~?\\)?[ \t]*\"" nil t)
+ (replace-match "" t t))
+ ;; Remove escaped newlines.
+ (goto-char (point-min))
+ (while (re-search-forward "\\\\[ \t]*\n" nil t)
+ (replace-match "" t t))
+ ;; Unquote individual characters.
+ (goto-char (point-min))
+ (while (re-search-forward "\\\\[\"abfnt\\0-7]" nil t)
+ (cond ((eq (preceding-char) ?\") (replace-match "\"" t t))
+ ((eq (preceding-char) ?a) (replace-match "\a" t t))
+ ((eq (preceding-char) ?b) (replace-match "\b" t t))
+ ((eq (preceding-char) ?f) (replace-match "\f" t t))
+ ((eq (preceding-char) ?n) (replace-match "\n" t t))
+ ((eq (preceding-char) ?t) (replace-match "\t" t t))
+ ((eq (preceding-char) ?\\) (replace-match "\\" t t))
+ (t (let ((value (- (preceding-char) ?0)))
+ (replace-match "" t t)
+ (while (looking-at "[0-7]")
+ (setq value (+ (* 8 value) (- (following-char) ?0)))
+ (replace-match "" t t))
+ (insert value)))))
+ (buffer-string)))
+
+(defun po-eval-requoted (form prefix obsolete)
+ "Eval FORM, which inserts a string, and return the string fully requoted.
+If PREFIX, precede the result with its contents. If OBSOLETE, comment all
+generated lines in the returned string. Evaluating FORM should insert the
+wanted string in the buffer which is current at the time of evaluation.
+If FORM is itself a string, then this string is used for insertion."
+ (po-with-temp-buffer
+ (if (stringp form)
+ (insert form)
+ (push-mark)
+ (eval form))
+ (goto-char (point-min))
+ (let ((multi-line (re-search-forward "[^\n]\n+[^\n]" nil t)))
+ (goto-char (point-min))
+ (while (re-search-forward "[\"\a\b\f\n\t\\]" nil t)
+ (cond ((eq (preceding-char) ?\") (replace-match "\\\"" t t))
+ ((eq (preceding-char) ?\a) (replace-match "\\a" t t))
+ ((eq (preceding-char) ?\b) (replace-match "\\b" t t))
+ ((eq (preceding-char) ?\f) (replace-match "\\f" t t))
+ ((eq (preceding-char) ?\n)
+ (replace-match (if (or (not multi-line) (eobp))
+ "\\n"
+ "\\n\"\n\"")
+ t t))
+ ((eq (preceding-char) ?\t) (replace-match "\\t" t t))
+ ((eq (preceding-char) ?\\) (replace-match "\\\\" t t))))
+ (goto-char (point-min))
+ (if prefix (insert prefix " "))
+ (insert (if multi-line "\"\"\n\"" "\""))
+ (goto-char (point-max))
+ (insert "\"")
+ (if prefix (insert "\n"))
+ (if obsolete
+ (progn
+ (goto-char (point-min))
+ (while (not (eobp))
+ (or (eq (following-char) ?\n) (insert "#~ "))
+ (search-forward "\n"))))
+ (buffer-string))))
+
+(defun po-get-msgid (kill)
+ "Extract and return the unquoted msgid string.
+If KILL, then add the unquoted string to the kill ring."
+ (let ((string (po-extract-unquoted (current-buffer)
+ po-start-of-msgid po-start-of-msgstr)))
+ (if kill (po-kill-new string))
+ string))
+
+(defun po-get-msgstr (kill)
+ "Extract and return the unquoted msgstr string.
+If KILL, then add the unquoted string to the kill ring."
+ (let ((string (po-extract-unquoted (current-buffer)
+ po-start-of-msgstr po-end-of-entry)))
+ (if kill (po-kill-new string))
+ string))
+
+(defun po-set-msgid (form)
+ "Replace the current msgid, using FORM to get a string.
+Evaluating FORM should insert the wanted string in the current buffer. If
+FORM is itself a string, then this string is used for insertion. The string
+is properly requoted before the replacement occurs.
+
+Returns `nil' if the buffer has not been modified, for if the new msgid
+described by FORM is merely identical to the msgid already in place."
+ (let ((string (po-eval-requoted form "msgid" (eq po-entry-type 'obsolete))))
+ (save-excursion
+ (goto-char po-start-of-entry)
+ (re-search-forward po-any-msgid-regexp po-start-of-msgstr)
+ (and (not (string-equal (po-buffer-substring (match-beginning 0)
+ (match-end 0))
+ string))
+ (let ((buffer-read-only po-read-only))
+ (replace-match string t t)
+ (goto-char po-start-of-msgid)
+ (po-find-span-of-entry)
+ t)))))
+
+(defun po-set-msgstr (form)
+ "Replace the current msgstr, using FORM to get a string.
+Evaluating FORM should insert the wanted string in the current buffer. If
+FORM is itself a string, then this string is used for insertion. The string
+is properly requoted before the replacement occurs.
+
+Returns `nil' if the buffer has not been modified, for if the new msgstr
+described by FORM is merely identical to the msgstr already in place."
+ (let ((string (po-eval-requoted form "msgstr" (eq po-entry-type 'obsolete))))
+ (save-excursion
+ (goto-char po-start-of-entry)
+ (re-search-forward po-any-msgstr-regexp po-end-of-entry)
+ (and (not (string-equal (po-buffer-substring (match-beginning 0)
+ (match-end 0))
+ string))
+ (let ((buffer-read-only po-read-only))
+ (po-decrease-type-counter)
+ (replace-match string t t)
+ (goto-char po-start-of-msgid)
+ (po-find-span-of-entry)
+ (po-increase-type-counter)
+ t)))))
+
+(defun po-kill-ring-save-msgstr ()
+ "Push the msgstr string from current entry on the kill ring."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-get-msgstr t))
+
+(defun po-kill-msgstr ()
+ "Empty the msgstr string from current entry, pushing it on the kill ring."
+ (interactive)
+ (po-kill-ring-save-msgstr)
+ (po-set-msgstr ""))
+
+(defun po-yank-msgstr ()
+ "Replace the current msgstr string by the top of the kill ring."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-set-msgstr (if (eq last-command 'yank) '(yank-pop 1) '(yank)))
+ (setq this-command 'yank))
+
+(defun po-fade-out-entry ()
+ "Mark an active entry as fuzzy; obsolete a fuzzy or untranslated entry;
+or completely delete an obsolete entry, saving its msgstr on the kill ring."
+ (interactive)
+ (po-find-span-of-entry)
+
+ (cond ((eq po-entry-type 'translated)
+ (po-decrease-type-counter)
+ (po-add-attribute "fuzzy")
+ (po-current-entry)
+ (po-increase-type-counter))
+
+ ((or (eq po-entry-type 'fuzzy)
+ (eq po-entry-type 'untranslated))
+ (if (yes-or-no-p (_"Should I really obsolete this entry? "))
+ (progn
+ (po-decrease-type-counter)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region po-start-of-entry po-end-of-entry)
+ (let ((buffer-read-only po-read-only))
+ (goto-char (point-min))
+ (skip-chars-forward "\n")
+ (while (not (eobp))
+ (insert "#~ ")
+ (search-forward "\n")))))
+ (po-current-entry)
+ (po-increase-type-counter)))
+ (message ""))
+
+ ((and (eq po-entry-type 'obsolete)
+ (po-check-for-pending-edit po-start-of-msgid)
+ (po-check-for-pending-edit po-start-of-msgstr))
+ (po-decrease-type-counter)
+ (po-update-mode-line-string)
+ (po-get-msgstr t)
+ (let ((buffer-read-only po-read-only))
+ (delete-region po-start-of-entry po-end-of-entry))
+ (goto-char po-start-of-entry)
+ (if (re-search-forward po-any-msgstr-regexp nil t)
+ (goto-char (match-beginning 0))
+ (re-search-backward po-any-msgstr-regexp nil t))
+ (po-current-entry)
+ (message ""))))
+
+;;; Killing and yanking comments.
+
+(defvar po-active-comment-regexp
+ "^\\(#\n\\|# .*\n\\)+"
+ "Regexp matching the whole editable comment part of an active entry.")
+
+(defvar po-obsolete-comment-regexp
+ "^\\(#~? #\n\\|#~? # .*\n\\)+"
+ "Regexp matching the whole editable comment part of an obsolete entry.")
+
+(defun po-get-comment (kill-flag)
+ "Extract and return the editable comment string, uncommented.
+If KILL-FLAG, then add the unquoted comment to the kill ring."
+ (let ((buffer (current-buffer))
+ (obsolete (eq po-entry-type 'obsolete)))
+ (save-excursion
+ (goto-char po-start-of-entry)
+ (if (re-search-forward (if obsolete po-obsolete-comment-regexp
+ po-active-comment-regexp)
+ po-end-of-entry t)
+ (po-with-temp-buffer
+ (insert-buffer-substring buffer (match-beginning 0) (match-end 0))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if (looking-at (if obsolete "#~? # ?" "#~? ?"))
+ (replace-match "" t t))
+ (forward-line 1))
+ (and kill-flag (copy-region-as-kill (point-min) (point-max)))
+ (buffer-string))
+ ""))))
+
+(defun po-set-comment (form)
+ "Using FORM to get a string, replace the current editable comment.
+Evaluating FORM should insert the wanted string in the current buffer.
+If FORM is itself a string, then this string is used for insertion.
+The string is properly recommented before the replacement occurs."
+ (let ((obsolete (eq po-entry-type 'obsolete))
+ string)
+ (po-with-temp-buffer
+ (if (stringp form)
+ (insert form)
+ (push-mark)
+ (eval form))
+ (if (not (or (bobp) (= (preceding-char) ?\n)))
+ (insert "\n"))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (insert (if (= (following-char) ?\n)
+ (if obsolete "#~ #" "#")
+ (if obsolete "#~ # " "# ")))
+ (search-forward "\n"))
+ (setq string (buffer-string)))
+ (goto-char po-start-of-entry)
+ (if (re-search-forward
+ (if obsolete po-obsolete-comment-regexp po-active-comment-regexp)
+ po-end-of-entry t)
+ (if (not (string-equal (po-buffer-substring (match-beginning 0)
+ (match-end 0))
+ string))
+ (let ((buffer-read-only po-read-only))
+ (replace-match string t t)))
+ (skip-chars-forward " \t\n")
+ (let ((buffer-read-only po-read-only))
+ (insert string))))
+ (po-current-entry))
+
+(defun po-kill-ring-save-comment ()
+ "Push the msgstr string from current entry on the kill ring."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-get-comment t))
+
+(defun po-kill-comment ()
+ "Empty the msgstr string from current entry, pushing it on the kill ring."
+ (interactive)
+ (po-kill-ring-save-comment)
+ (po-set-comment "")
+ (po-redisplay))
+
+(defun po-yank-comment ()
+ "Replace the current comment string by the top of the kill ring."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-set-comment (if (eq last-command 'yank) '(yank-pop 1) '(yank)))
+ (setq this-command 'yank)
+ (po-redisplay))
+
+;;; Editing management and submode.
+
+;; In a string edit buffer, BACK-POINTER points to one of the slots of the
+;; list EDITED-FIELDS kept in the PO buffer. See its description elsewhere.
+;; Reminder: slots have the form (ENTRY-MARKER EDIT-BUFFER OVERLAY-INFO).
+
+(defvar po-subedit-back-pointer)
+
+(defun po-clean-out-killed-edits ()
+ "From EDITED-FIELDS, clean out any edit having a killed edit buffer."
+ (while (and po-edited-fields
+ (null (buffer-name (nth 1 (car po-edited-fields)))))
+ (let ((overlay (nth 2 (car po-edited-fields))))
+ (and overlay (po-dehighlight overlay)))
+ (setq po-edited-fields (cdr po-edited-fields)))
+ (let ((cursor po-edited-fields))
+ (while cursor
+ (let ((slot (car cursor)))
+ (setq cursor (cdr cursor))
+ (if (buffer-name (nth 1 slot))
+ nil
+ (let ((overlay (nth 2 slot)))
+ (and overlay (po-dehighlight overlay)))
+ (setq po-edited-fields (delete slot po-edited-fields)))))))
+
+(defun po-check-all-pending-edits ()
+ "Resume any pending edit. Return nil if some remains."
+ (po-clean-out-killed-edits)
+ (or (null po-edited-fields)
+ (let ((slot (car po-edited-fields)))
+ (goto-char (nth 0 slot))
+ (pop-to-buffer (nth 1 slot))
+ (let ((overlay (nth 2 slot)))
+ (and overlay (po-rehighlight overlay)))
+ (message po-subedit-message)
+ nil)))
+
+(defun po-check-for-pending-edit (position)
+ "Resume any pending edit at POSITION. Return nil if such edit exists."
+ (po-clean-out-killed-edits)
+ (let ((marker (make-marker)))
+ (set-marker marker position)
+ (let ((slot (assoc marker po-edited-fields)))
+ (if slot
+ (progn
+ (goto-char marker)
+ (pop-to-buffer (nth 1 slot))
+ (let ((overlay (nth 2 slot)))
+ (and overlay (po-rehighlight overlay)))
+ (message po-subedit-message)))
+ (not slot))))
+
+(defun po-edit-out-full ()
+ "Get out of PO mode, leaving PO file buffer in fundamental mode."
+ (interactive)
+ (if (and (po-check-all-pending-edits)
+ (yes-or-no-p (_"Should I let you edit the whole PO file? ")))
+ (progn
+ (setq buffer-read-only po-read-only)
+ (fundamental-mode)
+ (message (_"Type `M-x po-mode RET' once done")))))
+
+(defvar po-subedit-mode-map nil
+ "Keymap while editing a PO mode entry (or the full PO file).")
+(if po-subedit-mode-map
+ ()
+ (setq po-subedit-mode-map (make-sparse-keymap))
+ (define-key po-subedit-mode-map "\C-c\C-a" 'po-subedit-cycle-auxiliary)
+ (define-key po-subedit-mode-map "\C-c\C-c" 'po-subedit-exit)
+ (define-key po-subedit-mode-map "\C-c\C-k" 'po-subedit-abort))
+
+(defun po-subedit-abort ()
+ "Exit the subedit buffer, merely discarding its contents."
+ (interactive)
+ (let* ((edit-buffer (current-buffer))
+ (back-pointer po-subedit-back-pointer)
+ (marker (nth 0 back-pointer))
+ (overlay (nth 2 back-pointer))
+ (buffer (marker-buffer marker)))
+ (if (null buffer)
+ (error (_"Corresponding PO buffer does not exist anymore"))
+ (or (one-window-p) (delete-window))
+ (switch-to-buffer buffer)
+ (goto-char marker)
+ (and overlay (po-dehighlight overlay))
+ (kill-buffer edit-buffer)
+ (setq po-edited-fields (delete back-pointer po-edited-fields)))))
+
+(defun po-subedit-exit ()
+ "Exit the subedit buffer, replacing the string in the PO buffer."
+ (interactive)
+ (goto-char (point-max))
+ (skip-chars-backward " \t\n")
+ (if (eq (preceding-char) ?<)
+ (delete-region (1- (point)) (point-max)))
+ (let ((string (buffer-string)))
+ (po-subedit-abort)
+ (po-find-span-of-entry)
+ (cond ((= (point) po-start-of-msgid)
+ (po-set-comment string)
+ (po-redisplay))
+ ((= (point) po-start-of-msgstr)
+ (let ((replaced (po-set-msgstr string)))
+ (if (and replaced
+ po-auto-fuzzy-on-edit
+ (eq po-entry-type 'translated))
+ (progn
+ (po-decrease-type-counter)
+ (po-add-attribute "fuzzy")
+ (po-current-entry)
+ (po-increase-type-counter)))))
+ (t (debug)))))
+
+(defun po-edit-string (string type expand-tabs)
+ "Prepare a pop up buffer for editing STRING, which is of a given TYPE.
+TYPE may be 'comment or 'msgstr. If EXPAND-TABS, expand tabs to spaces.
+Run functions on po-subedit-mode-hook."
+ (let ((marker (make-marker)))
+ (set-marker marker (cond ((eq type 'comment) po-start-of-msgid)
+ ((eq type 'msgstr) po-start-of-msgstr)))
+ (if (po-check-for-pending-edit marker)
+ (let ((edit-buffer (generate-new-buffer
+ (concat "*" (buffer-name) "*")))
+ (buffer (current-buffer))
+ overlay slot)
+ (if (and (eq type 'msgstr) po-highlighting)
+ ;; ;; Try showing all of msgid in the upper window while editing.
+ ;; (goto-char (1- po-start-of-msgstr))
+ ;; (recenter -1)
+ (save-excursion
+ (goto-char po-start-of-entry)
+ (re-search-forward po-any-msgid-regexp nil t)
+ (let ((end (1- (match-end 0))))
+ (goto-char (match-beginning 0))
+ (re-search-forward "msgid +" nil t)
+ (setq overlay (po-create-overlay))
+ (po-highlight overlay (point) end buffer))))
+ (setq slot (list marker edit-buffer overlay)
+ po-edited-fields (cons slot po-edited-fields))
+ (pop-to-buffer edit-buffer)
+ (make-local-variable 'po-subedit-back-pointer)
+ (setq po-subedit-back-pointer slot)
+ (erase-buffer)
+ (insert string "<")
+ (goto-char (point-min))
+ (and expand-tabs (setq indent-tabs-mode nil))
+ (use-local-map po-subedit-mode-map)
+ (run-hooks 'po-subedit-mode-hook)
+ (message po-subedit-message)))))
+
+(defun po-edit-comment ()
+ "Use another window to edit the current translator comment."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-edit-string (po-get-comment nil) 'comment nil))
+
+(defun po-edit-msgstr ()
+ "Use another window to edit the current msgstr."
+ (interactive)
+ (po-find-span-of-entry)
+ (po-edit-string (if (and po-auto-edit-with-msgid
+ (eq po-entry-type 'untranslated))
+ (po-get-msgid nil)
+ (po-get-msgstr nil))
+ 'msgstr
+ t))
+
+;;; String normalization and searching.
+
+(defun po-normalize-old-style (explain)
+ "Normalize old gettext style fields using K&R C multiline string syntax.
+To minibuffer messages sent while normalizing, add the EXPLAIN string."
+ (let ((here (point-marker))
+ (counter 0)
+ (buffer-read-only po-read-only))
+ (goto-char (point-min))
+ (message (_"Normalizing %d, %s") counter explain)
+ (while (re-search-forward
+ "\\(^#?[ \t]*msg\\(id\\|str\\)[ \t]*\"\\|[^\" \t][ \t]*\\)\\\\\n"
+ nil t)
+ (if (= (% counter 10) 0)
+ (message (_"Normalizing %d, %s") counter explain))
+ (replace-match "\\1\"\n\"" t nil)
+ (setq counter (1+ counter)))
+ (goto-char here)
+ (message (_"Normalizing %d...done") counter)))
+
+(defun po-normalize-field (field explain)
+ "Normalize FIELD of all entries. FIELD is either the symbol msgid or msgstr.
+To minibuffer messages sent while normalizing, add the EXPLAIN string."
+ (let ((here (point-marker))
+ (counter 0))
+ (goto-char (point-min))
+ (while (re-search-forward po-any-msgstr-regexp nil t)
+ (if (= (% counter 10) 0)
+ (message (_"Normalizing %d, %s") counter explain))
+ (goto-char (match-beginning 0))
+ (po-find-span-of-entry)
+ (cond ((eq field 'msgid) (po-set-msgid (po-get-msgid nil)))
+ ((eq field 'msgstr) (po-set-msgstr (po-get-msgstr nil))))
+ (goto-char po-end-of-entry)
+ (setq counter (1+ counter)))
+ (goto-char here)
+ (message (_"Normalizing %d...done") counter)))
+
+;; Normalize, but the British way! :-)
+(defsubst po-normalise () (po-normalize))
+
+(defun po-normalize ()
+ "Normalize all entries in the PO file."
+ (interactive)
+ (po-normalize-old-style (_"pass 1/3"))
+ (po-normalize-field t (_"pass 2/3"))
+ (po-normalize-field nil (_"pass 3/3"))
+ ;; The last PO file entry has just been processed.
+ (if (not (= po-end-of-entry (point-max)))
+ (let ((buffer-read-only po-read-only))
+ (kill-region po-end-of-entry (point-max))))
+ ;; A bizarre format might have fooled the counters, so recompute
+ ;; them to make sure their value is dependable.
+ (po-compute-counters nil))
+
+;;; Multiple PO files.
+
+(defun po-show-auxiliary-list ()
+ "Echo the current auxiliary list in the message area."
+ (if po-auxiliary-list
+ (let ((cursor po-auxiliary-cursor)
+ string)
+ (while cursor
+ (setq string (concat string (if string " ") (car (car cursor)))
+ cursor (cdr cursor)))
+ (setq cursor po-auxiliary-list)
+ (while (not (eq cursor po-auxiliary-cursor))
+ (setq string (concat string (if string " ") (car (car cursor)))
+ cursor (cdr cursor)))
+ (message string))
+ (message (_"No auxiliary files."))))
+
+(defun po-consider-as-auxiliary ()
+ "Add the current PO file to the list of auxiliary files."
+ (interactive)
+ (if (member (list buffer-file-name) po-auxiliary-list)
+ nil
+ (setq po-auxiliary-list
+ (nconc po-auxiliary-list (list (list buffer-file-name))))
+ (or po-auxiliary-cursor
+ (setq po-auxiliary-cursor po-auxiliary-list)))
+ (po-show-auxiliary-list))
+
+(defun po-ignore-as-auxiliary ()
+ "Delete the current PO file from the list of auxiliary files."
+ (interactive)
+ (setq po-auxiliary-list (delete (list buffer-file-name) po-auxiliary-list)
+ po-auxiliary-cursor po-auxiliary-list)
+ (po-show-auxiliary-list))
+
+(defun po-seek-equivalent-translation (name string)
+ "Search a PO file NAME for a `msgid' STRING having a non-empty `msgstr'.
+STRING is the full quoted msgid field, including the `msgid' keyword. When
+found, display the file over the current window, with the `msgstr' field
+possibly highlighted, the cursor at start of msgid, then return `t'.
+Otherwise, move nothing, and just return `nil'."
+ (let ((current (current-buffer))
+ (buffer (find-file-noselect name)))
+ (set-buffer buffer)
+ (let ((start (point))
+ found)
+ (goto-char (point-min))
+ (while (and (not found) (search-forward string nil t))
+ ;; Screen out longer `msgid's.
+ (if (looking-at "^msgstr ")
+ (progn
+ (po-find-span-of-entry)
+ ;; Ignore an untranslated entry.
+ (or (string-equal
+ (buffer-substring po-start-of-msgstr po-end-of-entry)
+ "msgstr \"\"\n")
+ (setq found t)))))
+ (if found
+ (progn
+ (switch-to-buffer buffer)
+ (po-find-span-of-entry)
+ (if po-highlighting
+ (progn
+ (goto-char po-start-of-entry)
+ (re-search-forward po-any-msgstr-regexp nil t)
+ (let ((end (1- (match-end 0))))
+ (goto-char (match-beginning 0))
+ (re-search-forward "msgstr +" nil t)
+ ;; FIXME:
+ (po-highlight (point) end))))
+ (goto-char po-start-of-msgid))
+ (goto-char start)
+ (po-find-span-of-entry)
+ (select-buffer current))
+ found)))
+
+(defun po-cycle-auxiliary ()
+ "Select the next auxiliary file having an entry with same `msgid'."
+ (interactive)
+ (po-find-span-of-entry)
+ (if po-auxiliary-list
+ (let ((string (buffer-substring po-start-of-msgid po-start-of-msgstr))
+ (cursor po-auxiliary-cursor)
+ found name)
+ (while (and (not found) cursor)
+ (setq name (car (car cursor)))
+ (if (and (not (string-equal buffer-file-name name))
+ (po-seek-equivalent-translation name string))
+ (setq found t
+ po-auxiliary-cursor cursor))
+ (setq cursor (cdr cursor)))
+ (setq cursor po-auxiliary-list)
+ (while (and (not found) cursor)
+ (setq name (car (car cursor)))
+ (if (and (not (string-equal buffer-file-name name))
+ (po-seek-equivalent-translation name string))
+ (setq found t
+ po-auxiliary-cursor cursor))
+ (setq cursor (cdr cursor)))
+ (or found (message (_"No other translation found")))
+ found)))
+
+(defun po-subedit-cycle-auxiliary ()
+ "Cycle auxiliary file, but from the translation edit buffer."
+ (interactive)
+ (if po-buffer-of-edited-entry
+ (let ((buffer (current-buffer)))
+ (pop-to-buffer po-buffer-of-edited-entry)
+ (po-cycle-auxiliary)
+ (pop-to-buffer buffer))
+ (error (_"Not editing a PO file entry"))))
+
+(defun po-select-auxiliary ()
+ "Select one of the available auxiliary files and locate an equivalent
+entry. If an entry having the same `msgid' cannot be found, merely select
+the file without moving its cursor."
+ (interactive)
+ (po-find-span-of-entry)
+ (if po-auxiliary-list
+ (let ((string (buffer-substring po-start-of-msgid po-start-of-msgstr))
+ (name (car (assoc (completing-read (_"Which auxiliary file? ")
+ po-auxiliary-list nil t)
+ po-auxiliary-list))))
+ (po-consider-as-auxiliary)
+ (or (po-seek-equivalent-translation name string)
+ (find-file name)))))
+
+;;; Original program sources as context.
+
+(defun po-show-source-path ()
+ "Echo the current source search path in the message area."
+ (if po-search-path
+ (let ((cursor po-search-path)
+ string)
+ (while cursor
+ (setq string (concat string (if string " ") (car (car cursor)))
+ cursor (cdr cursor)))
+ (message string))
+ (message (_"Empty source path."))))
+
+(defun po-consider-source-path (directory)
+ "Add a given DIRECTORY, requested interactively, to the source search path."
+ (interactive "DDirectory for search path: ")
+ (setq po-search-path (cons (list (if (string-match "/$" directory)
+ directory
+ (concat directory "/")))
+ po-search-path))
+ (setq po-reference-check 0)
+ (po-show-source-path))
+
+(defun po-ignore-source-path ()
+ "Delete a directory, selected with completion, from the source search path."
+ (interactive)
+ (setq po-search-path
+ (delete (list (completing-read (_"Directory to remove? ")
+ po-search-path nil t))
+ po-search-path))
+ (setq po-reference-check 0)
+ (po-show-source-path))
+
+(defun po-ensure-source-references ()
+ "Extract all references into a list, with paths resolved, if necessary."
+ (po-find-span-of-entry)
+ (if (= po-start-of-entry po-reference-check)
+ ()
+ (setq po-reference-alist nil)
+ (save-excursion
+ (goto-char po-start-of-entry)
+ (if (re-search-forward "^#:" po-start-of-msgid t)
+ (while (looking-at "\\(\n#:\\)? *\\([^: ]+\\):\\([0-9]+\\)")
+ (goto-char (match-end 0))
+ (let* ((name (po-buffer-substring (match-beginning 2)
+ (match-end 2)))
+ (line (po-buffer-substring (match-beginning 3)
+ (match-end 3)))
+ (path po-search-path)
+ file)
+ (while (and (progn (setq file (concat (car (car path)) name))
+ (not (file-exists-p file)))
+ path)
+ (setq path (cdr path)))
+ (if path
+ (setq po-reference-alist
+ (cons (list (concat file ":" line)
+ file
+ (string-to-int line))
+ po-reference-alist)))))))
+ (setq po-reference-alist (nreverse po-reference-alist)
+ po-reference-cursor po-reference-alist
+ po-reference-check po-start-of-entry)))
+
+(defun po-show-source-context (triplet)
+ "Show the source context given a TRIPLET which is (PROMPT FILE LINE)."
+ (find-file-other-window (car (cdr triplet)))
+ (goto-line (car (cdr (cdr triplet))))
+ (other-window 1)
+ (let ((maximum 0)
+ position
+ (cursor po-reference-alist))
+ (while (not (eq triplet (car cursor)))
+ (setq maximum (1+ maximum)
+ cursor (cdr cursor)))
+ (setq position (1+ maximum)
+ po-reference-cursor cursor)
+ (while cursor
+ (setq maximum (1+ maximum)
+ cursor (cdr cursor)))
+ (message (_"Displaying %d/%d: \"%s\"") position maximum (car triplet))))
+
+(defun po-cycle-source-reference ()
+ "Display some source context for the current entry.
+If the command is repeated many times in a row, cycle through contexts."
+ (interactive)
+ (po-ensure-source-references)
+ (if po-reference-cursor
+ (po-show-source-context
+ (car (if (eq last-command 'po-cycle-source-reference)
+ (or (cdr po-reference-cursor) po-reference-alist)
+ po-reference-cursor)))
+ (error (_"No resolved source references"))))
+
+(defun po-select-source-reference ()
+ "Select one of the available source contexts for the current entry."
+ (interactive)
+ (po-ensure-source-references)
+ (if po-reference-alist
+ (po-show-source-context
+ (assoc
+ (completing-read (_"Which source context? ") po-reference-alist nil t)
+ po-reference-alist))
+ (error (_"No resolved source references"))))
+
+;;; Program sources strings though tags table.
+
+;;; C mode.
+
+;;; A few long string cases (submitted by Ben Pfaff).
+
+;; #define string "This is a long string " \
+;; "that is continued across several lines " \
+;; "in a macro in order to test \\ quoting\\" \
+;; "\\ with goofy strings.\\"
+
+;; char *x = "This is just an ordinary string "
+;; "continued across several lines without needing "
+;; "to use \\ characters at end-of-line.";
+
+;; char *y = "Here is a string continued across \
+;; several lines in the manner that was sanctioned \
+;; in K&R C compilers and still works today, \
+;; even though the method used above is more esthetic.";
+
+;;; End of long string cases.
+
+(defun po-find-c-string (keywords)
+ "Find the next C string, excluding those marked by any of KEYWORDS.
+Returns (START . END) for the found string, or (nil . nil) if none found."
+ (let (start end)
+ (while (and (not start)
+ (re-search-forward "\\([\"']\\|/\\*\\)" nil t))
+ (cond ((= (preceding-char) ?*)
+ ;; Disregard comments.
+ (search-forward "*/"))
+
+ ((= (preceding-char) ?\')
+ ;; Disregard character constants.
+ (forward-char (if (= (following-char) ?\\) 3 2)))
+
+ ((save-excursion
+ (beginning-of-line)
+ (looking-at "^# *\\(include\\|line\\)"))
+ ;; Disregard lines being #include or #line directives.
+ (end-of-line))
+
+ ;; Else, find the end of the (possibly concatenated) string.
+ (t (setq start (1- (point))
+ end nil)
+ (while (not end)
+ (cond ((= (following-char) ?\")
+ (if (looking-at "\"[ \t\n\\\\]*\"")
+ (goto-char (match-end 0))
+ (forward-char 1)
+ (setq end (point))))
+ ((= (following-char) ?\\) (forward-char 2))
+ (t (skip-chars-forward "^\"\\\\"))))
+
+ ;; Check before string for keyword and opening parenthesis.
+ (goto-char start)
+ (skip-chars-backward " \n\t")
+ (if (= (preceding-char) ?\()
+ (progn
+ (backward-char 1)
+ (skip-chars-backward " \n\t")
+ (let ((end-keyword (point)))
+ (skip-chars-backward "_A-Za-z0-9")
+ (if (member (list (po-buffer-substring (point)
+ end-keyword))
+ keywords)
+
+ ;; Disregard already marked strings.
+ (progn
+ (goto-char end)
+ (setq start nil
+ end nil)))))))))
+
+ ;; Return the found string, if any.
+ (cons start end)))
+
+(defun po-mark-c-string (start end keyword)
+ "Mark the C string, from START to END, with KEYWORD.
+Return the adjusted value for END."
+ (goto-char end)
+ (insert ")")
+ (goto-char start)
+ (insert keyword)
+ (if (not (string-equal keyword "_"))
+ (progn (insert " ") (setq end (1+ end))))
+ (insert "(")
+ (+ end 2 (length keyword)))
+
+;;; Emacs LISP mode.
+
+(defun po-find-emacs-lisp-string (keywords)
+ "Find the next Emacs LISP string, excluding those marked by any of KEYWORDS.
+Returns (START . END) for the found string, or (nil . nil) if none found."
+ (let (start end)
+ (while (and (not start)
+ (re-search-forward "[;\"?]" nil t))
+
+ (cond ((= (preceding-char) ?\;)
+ ;; Disregard comments.
+ (search-forward "\n"))
+
+ ((= (preceding-char) ?\?)
+ ;; Disregard character constants.
+ (forward-char (if (= (following-char) ?\\) 2 1)))
+
+ ;; Else, find the end of the string.
+ (t (setq start (1- (point)))
+ (while (not (= (following-char) ?\"))
+ (skip-chars-forward "^\"\\\\")
+ (if (= (following-char) ?\\) (forward-char 2)))
+ (forward-char 1)
+ (setq end (point))
+
+ ;; Check before string for keyword and opening parenthesis.
+ (goto-char start)
+ (skip-chars-backward " \n\t")
+ (let ((end-keyword (point)))
+ (skip-chars-backward "-_A-Za-z0-9")
+ (if (and (= (preceding-char) ?\()
+ (member (list (po-buffer-substring (point)
+ end-keyword))
+ keywords))
+
+ ;; Disregard already marked strings.
+ (progn
+ (goto-char end)
+ (setq start nil
+ end nil)))))))
+
+ ;; Return the found string, if any.
+ (cons start end)))
+
+(defun po-mark-emacs-lisp-string (start end keyword)
+ "Mark the Emacs LISP string, from START to END, with KEYWORD.
+Return the adjusted value for END."
+ (goto-char end)
+ (insert ")")
+ (goto-char start)
+ (insert "(" keyword)
+ (if (not (string-equal keyword "_"))
+ (progn (insert " ") (setq end (1+ end))))
+ (+ end 2 (length keyword)))
+
+;;; Processing generic to all programming modes.
+
+(eval-and-compile
+ (autoload 'visit-tags-table-buffer "etags"))
+
+(defun po-tags-search (restart)
+ (interactive "P")
+ "Find an unmarked translatable string through all files in tags table.
+Disregard some simple strings which are most probably non-translatable.
+With prefix argument, restart search at first file."
+
+ ;; Take care of restarting the search if necessary.
+ (if restart (setq po-next-file-list nil))
+
+ ;; Loop doing things until an interesting string is found.
+ (let ((keywords po-keywords)
+ found buffer start
+ (end po-string-end))
+ (while (not found)
+
+ ;; Reinitialize the source file list if necessary.
+ (if (not po-next-file-list)
+ (progn
+ (setq po-next-file-list
+ (save-excursion
+ (visit-tags-table-buffer)
+ (copy-sequence (tags-table-files))))
+ (or po-next-file-list (error (_"No files to process")))
+ (setq end nil)))
+
+ ;; Try finding a string after resuming the search position.
+ (message (_"Scanning %s...") (car po-next-file-list))
+ (save-excursion
+ (setq buffer (find-file-noselect (car po-next-file-list)))
+ (set-buffer buffer)
+ (goto-char (or end (point-min)))
+
+ (cond ((string-equal mode-name "C")
+ (let ((pair (po-find-c-string keywords)))
+ (setq start (car pair)
+ end (cdr pair))))
+ ((string-equal mode-name "Emacs-Lisp")
+ (let ((pair (po-find-emacs-lisp-string keywords)))
+ (setq start (car pair)
+ end (cdr pair))))
+ (t (message (_"Unknown source mode for PO mode, skipping..."))
+ (setq start nil
+ end nil))))
+
+ ;; Advance to next file if no string was found.
+ (if (not start)
+ (progn
+ (setq po-next-file-list (cdr po-next-file-list))
+ (if po-next-file-list
+ (setq end nil)
+ (setq po-string-end nil)
+ (and po-highlighting (po-dehighlight po-marking-overlay))
+ (error (_"All files processed"))))
+
+ ;; Push the string just found string into a work buffer for study.
+ (po-with-temp-buffer
+ (insert (po-extract-unquoted buffer start end))
+ (goto-char (point-min))
+
+ ;; Do not disregard if at least three letters in a row.
+ (if (re-search-forward "[A-Za-z][A-Za-z][A-Za-z]" nil t)
+ (setq found t)
+
+ ;; Disregard if two letters, and more punctuations than letters.
+ (if (re-search-forward "[A-Za-z][A-Za-z]" nil t)
+ (let ((total (buffer-size)))
+ (goto-char (point-min))
+ (while (re-search-forward "[A-Za-z]+" nil t)
+ (replace-match "" t t))
+ (if (< (* 2 (buffer-size)) total)
+ (setq found t))))
+
+ ;; Disregard if single letters or no letters at all.
+ ))))
+
+ ;; Ensure the string is being displayed.
+
+ (if (one-window-p t) (split-window) (other-window 1))
+ (switch-to-buffer buffer)
+ (goto-char start)
+ (or (pos-visible-in-window-p start) (recenter '(nil)))
+ (if (pos-visible-in-window-p end)
+ (goto-char end)
+ (goto-char end)
+ (recenter -1))
+ (other-window 1)
+ (and po-highlighting (po-highlight po-marking-overlay start end buffer))
+
+ ;; Save the string for later commands.
+ (message (_"Scanning %s...done") (car po-next-file-list))
+ (setq po-string-start start
+ po-string-end end)))
+
+(defun po-mark-found-string (keyword)
+ "Mark last found string in program sources as translatable, using KEYWORD."
+ (and po-highlighting (po-dehighlight po-marking-overlay))
+ (let ((buffer (find-file-noselect (car po-next-file-list)))
+ (start po-string-start)
+ (end po-string-end)
+ line string)
+
+ ;; Mark string in program sources.
+ (setq string (po-extract-unquoted buffer start end))
+ (save-excursion
+ (set-buffer buffer)
+ (setq line (count-lines (point-min) start)
+ end (cond ((string-equal mode-name "C")
+ (po-mark-c-string start end keyword))
+ ((string-equal mode-name "Emacs-Lisp")
+ (po-mark-emacs-lisp-string start end keyword))
+ (t (error (_"Cannot mark in unknown source mode"))))))
+ (setq po-string-end end)
+
+ ;; Add PO file entry.
+ (let ((buffer-read-only po-read-only))
+ (goto-char (point-max))
+ (insert "\n" (format "#: %s:%d\n" (car po-next-file-list) line))
+ (save-excursion
+ (insert (po-eval-requoted string "msgid" nil) "msgstr \"\"\n"))
+ (setq po-untranslated-counter (1+ po-untranslated-counter))
+ (po-update-mode-line-string))))
+
+(defun po-mark-translatable ()
+ (interactive)
+ "Mark last found string in program sources as translatable, using `_'."
+ (if (and po-string-start po-string-end)
+ (progn
+ (po-mark-found-string "_")
+ (setq po-string-start nil))
+ (error (_"No such string"))))
+
+(defun po-select-mark-and-mark (arg)
+ (interactive "P")
+ "Mark last found string in program sources as translatable, ask for keywoard,
+using completion. With prefix argument, just ask the name of a preferred
+keyword for subsequent commands, also added to possible completions."
+ (if arg
+ (let ((keyword (list (read-from-minibuffer (_"Keyword: ")))))
+ (setq po-keywords (cons keyword (delete keyword po-keywords))))
+ (if (and po-string-start po-string-end)
+ (let* ((default (car (car po-keywords)))
+ (keyword (completing-read (format (_"Mark with keywoard? [%s] ")
+ default)
+ po-keywords nil t )))
+ (if (string-equal keyword "") (setq keyword default))
+ (po-mark-found-string keyword)
+ (setq po-string-start nil))
+ (error (_"No such string")))))
+
+;;; Miscellaneous features.
+
+(defun po-help ()
+ "Provide an help window for PO mode."
+ (interactive)
+ (po-with-temp-buffer
+ (insert po-help-display-string)
+ (goto-char (point-min))
+ (save-window-excursion
+ (switch-to-buffer (current-buffer))
+ (delete-other-windows)
+ (message (_"Type any character to continue"))
+ (po-read-event))))
+
+(defun po-undo ()
+ "Undo the last change to the PO file."
+ (interactive)
+ (let ((buffer-read-only po-read-only))
+ (undo))
+ (po-compute-counters nil))
+
+(defun po-statistics ()
+ "Say how many entries in each category, and the current position."
+ (interactive)
+ (po-compute-counters t))
+
+(defun po-validate ()
+ "Use `msgfmt' for validating the current PO file contents."
+ (interactive)
+
+ ;; If modifications were done already, change the last revision date.
+ (if (buffer-modified-p)
+ (po-replace-revision-date))
+
+ ;; This `let' is for protecting the previous value of compile-command.
+ (let ((compile-command (concat po-msgfmt-program
+ " --statistics -c -v -o /dev/null "
+ buffer-file-name)))
+ (compile compile-command)))
+
+(defun po-guess-archive-name ()
+ "Return the ideal file name for this PO file in the central archives."
+ (let (start-of-header end-of-header package version team)
+ (save-excursion
+ ;; Find the PO file header entry.
+ (goto-char (point-min))
+ (re-search-forward po-any-msgstr-regexp)
+ (setq start-of-header (match-beginning 0)
+ end-of-header (match-end 0))
+ ;; Get the package and version.
+ (goto-char start-of-header)
+ (if (re-search-forward
+ "\n\"Project-Id-Version:\\( GNU\\)? \\([^\n ]+\\) \\([^\n ]+\\)\\\\n\"$"
+ end-of-header t)
+ (setq package (buffer-substring (match-beginning 2) (match-end 2))
+ version (buffer-substring (match-beginning 3) (match-end 3))))
+ (if (or (not package) (string-equal package "PACKAGE")
+ (not version) (string-equal version "VERSION"))
+ (error (_"Project-Id-Version field does not have a proper value")))
+ ;; Get the team.
+ (goto-char start-of-header)
+ (if (re-search-forward "\n\"Language-Team:.*<\\(.*\\)@li.org>\\\\n\"$"
+ end-of-header t)
+ (setq team (buffer-substring (match-beginning 1) (match-end 1))))
+ (if (or (not team) (string-equal team "LL"))
+ (error (_"Language-Team field does not have a proper value")))
+ ;; Compose the name.
+ (concat package "-" version "." team ".po"))))
+
+(defun po-guess-team-address ()
+ "Return the team address related to this PO file."
+ (let (team)
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward po-any-msgstr-regexp)
+ (goto-char (match-beginning 0))
+ (if (re-search-forward
+ "\n\"Language-Team: +\\(.*<\\(.*\\)@li.org>\\)\\\\n\"$"
+ (match-end 0) t)
+ (setq team (buffer-substring (match-beginning 2) (match-end 2))))
+ (if (or (not team) (string-equal team "LL"))
+ (error (_"Language-Team field does not have a proper value")))
+ (buffer-substring (match-beginning 1) (match-end 1)))))
+
+(defun po-send-mail ()
+ "Start composing a letter, possibly including the current PO file."
+ (interactive)
+ (let* ((team-flag (y-or-n-p
+ (_"\
+Write to your team? (`n' means writing to translation project) ")))
+ (address (if team-flag
+ (po-guess-team-address)
+ po-translation-project-address)))
+ (if (not (y-or-n-p (_"Include current PO file? ")))
+ (apply po-compose-mail-function address
+ (read-string (_"Subject? ")) nil)
+ (if (buffer-modified-p)
+ (error (_"The file is not even saved, you did not validate it.")))
+ (if (and (y-or-n-p (_"You validated (`V') this file, didn't you? "))
+ (or (zerop po-untranslated-counter)
+ (y-or-n-p
+ (format (_"%d entries are untranslated, include anyway? ")
+ po-untranslated-counter)))
+ (or (zerop po-fuzzy-counter)
+ (y-or-n-p
+ (format (_"%d entries are still fuzzy, include anyway? ")
+ po-fuzzy-counter)))
+ (or (zerop po-obsolete-counter)
+ (y-or-n-p
+ (format (_"%d entries are obsolete, include anyway? ")
+ po-obsolete-counter))))
+ (let ((buffer (current-buffer))
+ (name (po-guess-archive-name))
+ (transient-mark-mode nil))
+ (apply po-compose-mail-function address
+ (if team-flag
+ (read-string (_"Subject? "))
+ (format "TP-Robot %s" name))
+ nil)
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "\n"))
+ (save-excursion
+ (insert-buffer buffer)
+ (shell-command-on-region
+ (region-beginning) (region-end)
+ (concat po-gzip-uuencode-command " " name ".gz") t))))))
+ (message ""))
+
+(defun po-confirm-and-quit ()
+ "Confirm if quit should be attempted and then, do it.
+This is a failsafe. Confirmation is asked if only the real quit would not."
+ (interactive)
+ (if (po-check-all-pending-edits)
+ (progn
+ (if (or (buffer-modified-p)
+ (> po-untranslated-counter 0)
+ (> po-fuzzy-counter 0)
+ (> po-obsolete-counter 0)
+ (y-or-n-p (_"Really quit editing this PO file? ")))
+ (po-quit))
+ (message ""))))
+
+(defun po-quit ()
+ "Save the PO file and kill buffer. However, offer validation if
+appropriate and ask confirmation if untranslated strings remain."
+ (interactive)
+ (if (po-check-all-pending-edits)
+ (let ((quit t))
+
+ ;; Offer validation of newly modified entries.
+ (if (and (buffer-modified-p)
+ (not (y-or-n-p
+ (_"File was modified; skip validation step? "))))
+ (progn
+ (message "")
+ (po-validate)
+ ;; If we knew that the validation was all successful, we should
+ ;; just quit. But since we do not know yet, as the validation
+ ;; might be asynchronous with PO mode commands, the safest is to
+ ;; stay within PO mode, even if this implies that another
+ ;; `po-quit' command will be later required to exit for true.
+ (setq quit nil)))
+
+ ;; Offer to work on untranslated entries.
+ (if (and quit
+ (or (> po-untranslated-counter 0)
+ (> po-fuzzy-counter 0)
+ (> po-obsolete-counter 0))
+ (not (y-or-n-p
+ (_"Unprocessed entries remain; quit anyway? "))))
+ (progn
+ (setq quit nil)
+ (po-auto-select-entry)))
+
+ ;; Clear message area.
+ (message "")
+
+ ;; Or else, kill buffers and quit for true.
+ (if quit
+ (progn
+ (and (buffer-modified-p) (po-replace-revision-date))
+ (save-buffer)
+ (kill-buffer (current-buffer)))))))
+
+;;; po-mode.el ends here
diff --git a/lib/printf-parse.h b/lib/printf-parse.h
new file mode 100644
index 0000000..d8ab2b7
--- /dev/null
+++ b/lib/printf-parse.h
@@ -0,0 +1,421 @@
+/* Internal header for parsing printf format strings.
+ Copyright (C) 1995, 1996, 1998 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* We use some extension so define this here. */
+#define _GNU_SOURCE 1
+
+#include <ctype.h>
+#include <printf.h>
+#if STDC_HEADERS
+# include <stddef.h>
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if __GNUC__ >= 2
+# define long_long_int long long int
+# define long_double long double
+#else
+# define long_long_int long
+# define long_double double
+#endif
+
+#ifndef MB_CUR_MAX
+# define MB_CUR_MAX (sizeof (long))
+#endif
+
+#define NDEBUG 1
+#include <assert.h>
+
+#ifndef MAX
+# if defined __GNU__ && __GNUC__ >= 2
+# define MAX(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); \
+ _a > _b ? _a : _b; })
+# else
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+# endif
+#endif
+#ifndef MIN
+# if defined __GNU__ && __GNUC__ >= 2
+# define MIN(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); \
+ _a < _b ? _a : _b; })
+# else
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+# endif
+#endif
+
+struct printf_spec
+ {
+ /* Information parsed from the format spec. */
+ struct printf_info info;
+
+ /* Pointers into the format string for the end of this format
+ spec and the next (or to the end of the string if no more). */
+ const char *end_of_fmt, *next_fmt;
+
+ /* Position of arguments for precision and width, or -1 if `info' has
+ the constant value. */
+ int prec_arg, width_arg;
+
+ int data_arg; /* Position of data argument. */
+ int data_arg_type; /* Type of first argument. */
+ /* Number of arguments consumed by this format specifier. */
+ size_t ndata_args;
+ };
+
+
+/* The various kinds off arguments that can be passed to printf. */
+union printf_arg
+ {
+ unsigned char pa_char;
+ short int pa_short_int;
+ int pa_int;
+ long int pa_long_int;
+ long_long_int pa_long_long_int;
+ unsigned short int pa_u_short_int;
+ unsigned int pa_u_int;
+ unsigned long int pa_u_long_int;
+ unsigned long_long_int pa_u_long_long_int;
+ float pa_float;
+ double pa_double;
+ long_double pa_long_double;
+ const char *pa_string;
+ void *pa_pointer;
+ };
+
+
+/* Prototype for local function. */
+static unsigned int read_int PARAMS ((const char **pstr));
+static const char *find_spec PARAMS ((const char *format));
+static inline size_t parse_one_spec PARAMS ((const char *format,
+ size_t posn,
+ struct printf_spec *spec,
+ size_t *max_ref_arg));
+
+
+/* Read a simple integer from a string and update the string pointer.
+ It is assumed that the first character is a digit. */
+static inline unsigned int
+read_int (pstr)
+ const char **pstr;
+{
+ unsigned int retval = **pstr - '0';
+
+ while (isdigit (*++(*pstr)))
+ {
+ retval *= 10;
+ retval += **pstr - '0';
+ }
+
+ return retval;
+}
+
+
+
+/* Find the next spec in FORMAT, or the end of the string. Returns
+ a pointer into FORMAT, to a '%' or a '\0'. */
+static inline const char *
+find_spec (format)
+ const char *format;
+{
+ while (*format != '\0' && *format != '%')
+ {
+ int len;
+
+#ifdef HAVE_MBLEN
+ if (isascii (*format) || (len = mblen (format, MB_CUR_MAX)) <= 0)
+ ++format;
+ else
+ format += len;
+#else
+ ++format;
+#endif
+ }
+ return format;
+}
+
+
+/* FORMAT must point to a '%' at the beginning of a spec. Fills in *SPEC
+ with the parsed details. POSN is the number of arguments already
+ consumed. At most MAXTYPES - POSN types are filled in TYPES. Return
+ the number of args consumed by this spec; *MAX_REF_ARG is updated so it
+ remains the highest argument index used. */
+static inline size_t
+parse_one_spec (format, posn, spec, max_ref_arg)
+ const char *format;
+ size_t posn;
+ struct printf_spec *spec;
+ size_t *max_ref_arg;
+{
+ unsigned int n;
+ size_t nargs = 0;
+
+ /* Skip the '%'. */
+ ++format;
+
+ /* Clear information structure. */
+ spec->data_arg = -1;
+ spec->info.alt = 0;
+ spec->info.space = 0;
+ spec->info.left = 0;
+ spec->info.showsign = 0;
+ spec->info.group = 0;
+ spec->info.pad = ' ';
+
+ /* Test for positional argument. */
+ if (isdigit (*format))
+ {
+ const char *begin = format;
+
+ n = read_int (&format);
+
+ if (n > 0 && *format == '$')
+ /* Is positional parameter. */
+ {
+ ++format; /* Skip the '$'. */
+ spec->data_arg = n - 1;
+ *max_ref_arg = MAX (*max_ref_arg, n);
+ }
+ else
+ /* Oops; that was actually the width and/or 0 padding flag.
+ Step back and read it again. */
+ format = begin;
+ }
+
+ /* Check for spec modifiers. */
+ while (*format == ' ' || *format == '+' || *format == '-' ||
+ *format == '#' || *format == '0' || *format == '\'')
+ switch (*format++)
+ {
+ case ' ':
+ /* Output a space in place of a sign, when there is no sign. */
+ spec->info.space = 1;
+ break;
+ case '+':
+ /* Always output + or - for numbers. */
+ spec->info.showsign = 1;
+ break;
+ case '-':
+ /* Left-justify things. */
+ spec->info.left = 1;
+ break;
+ case '#':
+ /* Use the "alternate form":
+ Hex has 0x or 0X, FP always has a decimal point. */
+ spec->info.alt = 1;
+ break;
+ case '0':
+ /* Pad with 0s. */
+ spec->info.pad = '0';
+ break;
+ case '\'':
+ /* Show grouping in numbers if the locale information
+ indicates any. */
+ spec->info.group = 1;
+ break;
+ }
+ if (spec->info.left)
+ spec->info.pad = ' ';
+
+ /* Get the field width. */
+ spec->width_arg = -1;
+ spec->info.width = 0;
+ if (*format == '*')
+ {
+ /* The field width is given in an argument.
+ A negative field width indicates left justification. */
+ const char *begin = ++format;
+
+ if (isdigit (*format))
+ {
+ /* The width argument might be found in a positional parameter. */
+ n = read_int (&format);
+
+ if (n > 0 && *format == '$')
+ {
+ spec->width_arg = n - 1;
+ *max_ref_arg = MAX (*max_ref_arg, n);
+ ++format; /* Skip '$'. */
+ }
+ }
+
+ if (spec->width_arg < 0)
+ {
+ /* Not in a positional parameter. Consume one argument. */
+ spec->width_arg = posn++;
+ ++nargs;
+ format = begin; /* Step back and reread. */
+ }
+ }
+ else if (isdigit (*format))
+ /* Constant width specification. */
+ spec->info.width = read_int (&format);
+
+ /* Get the precision. */
+ spec->prec_arg = -1;
+ /* -1 means none given; 0 means explicit 0. */
+ spec->info.prec = -1;
+ if (*format == '.')
+ {
+ ++format;
+ if (*format == '*')
+ {
+ /* The precision is given in an argument. */
+ const char *begin = ++format;
+
+ if (isdigit (*format))
+ {
+ n = read_int (&format);
+
+ if (n > 0 && *format == '$')
+ {
+ spec->prec_arg = n - 1;
+ *max_ref_arg = MAX (*max_ref_arg, n);
+ ++format;
+ }
+ }
+
+ if (spec->prec_arg < 0)
+ {
+ /* Not in a positional parameter. */
+ spec->prec_arg = posn++;
+ ++nargs;
+ format = begin;
+ }
+ }
+ else if (isdigit (*format))
+ spec->info.prec = read_int (&format);
+ else
+ /* "%.?" is treated like "%.0?". */
+ spec->info.prec = 0;
+ }
+
+ /* Check for type modifiers. */
+#define is_longlong is_long_double
+ spec->info.is_long_double = 0;
+ spec->info.is_short = 0;
+ spec->info.is_long = 0;
+
+ while (*format == 'h' || *format == 'l' || *format == 'L' ||
+ *format == 'Z' || *format == 'q')
+ switch (*format++)
+ {
+ case 'h':
+ /* int's are short int's. */
+ spec->info.is_short = 1;
+ break;
+ case 'l':
+ if (spec->info.is_long)
+ /* A double `l' is equivalent to an `L'. */
+ spec->info.is_longlong = 1;
+ else
+ /* int's are long int's. */
+ spec->info.is_long = 1;
+ break;
+ case 'L':
+ /* double's are long double's, and int's are long long int's. */
+ spec->info.is_long_double = 1;
+ break;
+ case 'Z':
+ /* int's are size_t's. */
+ assert (sizeof(size_t) <= sizeof(unsigned long_long_int));
+ spec->info.is_longlong = sizeof(size_t) > sizeof(unsigned long int);
+ spec->info.is_long = sizeof(size_t) > sizeof(unsigned int);
+ break;
+ case 'q':
+ /* 4.4 uses this for long long. */
+ spec->info.is_longlong = 1;
+ break;
+ }
+
+ /* Get the format specification. */
+ spec->info.spec = *format++;
+ /* Find the data argument types of a built-in spec. */
+ spec->ndata_args = 1;
+
+ switch (spec->info.spec)
+ {
+ case 'i':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'X':
+ case 'x':
+ if (spec->info.is_longlong)
+ spec->data_arg_type = PA_INT|PA_FLAG_LONG_LONG;
+ else if (spec->info.is_long)
+ spec->data_arg_type = PA_INT|PA_FLAG_LONG;
+ else if (spec->info.is_short)
+ spec->data_arg_type = PA_INT|PA_FLAG_SHORT;
+ else
+ spec->data_arg_type = PA_INT;
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ if (spec->info.is_long_double)
+ spec->data_arg_type = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
+ else
+ spec->data_arg_type = PA_DOUBLE;
+ break;
+ case 'c':
+ spec->data_arg_type = PA_CHAR;
+ break;
+ case 's':
+ spec->data_arg_type = PA_STRING;
+ break;
+ case 'p':
+ spec->data_arg_type = PA_POINTER|PA_FLAG_PTR;
+ break;
+ case 'n':
+ spec->data_arg_type = PA_INT|PA_FLAG_PTR;
+ break;
+
+ case 'm':
+ default:
+ /* An unknown spec will consume no args. */
+ spec->ndata_args = 0;
+ break;
+ }
+
+ if (spec->data_arg == -1 && spec->ndata_args > 0)
+ {
+ /* There are args consumed, but no positional spec.
+ Use the next sequential arg position. */
+ spec->data_arg = posn;
+ posn += spec->ndata_args;
+ nargs += spec->ndata_args;
+ }
+
+ if (spec->info.spec == '\0')
+ /* Format ended before this spec was complete. */
+ spec->end_of_fmt = spec->next_fmt = format - 1;
+ else
+ {
+ /* Find the next format spec. */
+ spec->end_of_fmt = format;
+ spec->next_fmt = find_spec (format);
+ }
+
+ return nargs;
+}
diff --git a/lib/printf-prs.c b/lib/printf-prs.c
new file mode 100644
index 0000000..19869ca
--- /dev/null
+++ b/lib/printf-prs.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1999 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <printf.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <sys/param.h>
+
+#ifndef COMPILE_WPRINTF
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define INT_T int
+# define L_(Str) Str
+# define ISDIGIT(Ch) isdigit (Ch)
+# define ISASCII(Ch) isascii (Ch)
+# define MBRLEN(Cp, L, St) mbrlen (Cp, L, St)
+
+# ifdef USE_IN_LIBIO
+# define PUT(F, S, N) _IO_sputn (F, S, N)
+# define PAD(Padchar) \
+ if (width > 0) \
+ done += _IO_padn (s, Padchar, width)
+# else
+# define PUTC(C, F) putc (C, F)
+ssize_t __printf_pad __P ((FILE *, char pad, size_t n));
+# define PAD(Padchar) \
+ if (width > 0) \
+ { if (__printf_pad (s, Padchar, width) == -1) \
+ return -1; else done += width; }
+# endif
+#else
+# define vfprintf vfwprintf
+# define CHAR_T wchar_t
+# define UCHAR_T uwchar_t
+# define INT_T wint_t
+# define L_(Str) L##Str
+# define ISDIGIT(Ch) iswdigit (Ch)
+
+# ifdef USE_IN_LIBIO
+# define PUT(F, S, N) _IO_sputn (F, S, N)
+# define PAD(Padchar) \
+ if (width > 0) \
+ done += _IO_wpadn (s, Padchar, width)
+# else
+# define PUTC(C, F) wputc (C, F)
+ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n));
+# define PAD(Padchar) \
+ if (width > 0) \
+ { if (__wprintf_pad (s, Padchar, width) == -1) \
+ return -1; else done += width; }
+# endif
+#endif
+
+#include "printf-parse.h"
+
+
+size_t
+parse_printf_format (fmt, n, argtypes)
+ const char *fmt;
+ size_t n;
+ int *argtypes;
+{
+ size_t nargs; /* Number of arguments. */
+ size_t max_ref_arg; /* Highest index used in a positional arg. */
+ struct printf_spec spec;
+ mbstate_t mbstate;
+
+ nargs = 0;
+ max_ref_arg = 0;
+
+ /* Search for format specifications. */
+ for (fmt = find_spec (fmt, &mbstate); *fmt != '\0'; fmt = spec.next_fmt)
+ {
+ /* Parse this spec. */
+ nargs += parse_one_spec (fmt, nargs, &spec, &max_ref_arg, &mbstate);
+
+ /* If the width is determined by an argument this is an int. */
+ if (spec.width_arg != -1 && (size_t) spec.width_arg < n)
+ argtypes[spec.width_arg] = PA_INT;
+
+ /* If the precision is determined by an argument this is an int. */
+ if (spec.prec_arg != -1 && (size_t) spec.prec_arg < n)
+ argtypes[spec.prec_arg] = PA_INT;
+
+ if ((size_t) spec.data_arg < n)
+ switch (spec.ndata_args)
+ {
+ case 0: /* No arguments. */
+ break;
+ case 1: /* One argument; we already have the type. */
+ argtypes[spec.data_arg] = spec.data_arg_type;
+ break;
+ default:
+ /* We have more than one argument for this format spec. We must
+ call the arginfo function again to determine all the types. */
+ (void) (*__printf_arginfo_table[spec.info.spec])
+ (&spec.info, n - spec.data_arg, &argtypes[spec.data_arg]);
+ break;
+ }
+ }
+
+ return MAX (nargs, max_ref_arg);
+}
diff --git a/lib/printf.h b/lib/printf.h
new file mode 100644
index 0000000..03b0035
--- /dev/null
+++ b/lib/printf.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 1991, 1992, 1993, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _PRINTF_H
+
+#define _PRINTF_H 1
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef STDC_HEADERS
+# include <stddef.h>
+#endif
+
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+struct printf_info
+{
+ int prec; /* Precision. */
+ int width; /* Width. */
+ char spec; /* Format letter. */
+ unsigned is_long_double:1; /* L flag. */
+ unsigned is_short:1; /* h flag. */
+ unsigned is_long:1; /* l flag. */
+ unsigned alt:1; /* # flag. */
+ unsigned space:1; /* Space flag. */
+ unsigned left:1; /* - flag. */
+ unsigned showsign:1; /* + flag. */
+ unsigned group:1; /* ' flag. */
+ char pad; /* Padding character. */
+};
+
+
+/* Type of a printf specifier-handler function.
+ STREAM is the FILE on which to write output.
+ INFO gives information about the format specification.
+ Arguments can be read from ARGS.
+ The function should return the number of characters written,
+ or -1 for errors. */
+
+typedef int (*printf_function) PARAMS ((FILE * __stream,
+ const struct printf_info * __info,
+ const void **const __args));
+typedef int (*printf_arginfo_function) PARAMS ((const struct printf_info
+ *__info,
+ size_t __n,
+ int *__argtypes));
+
+/* Parse FMT, and fill in N elements of ARGTYPES with the
+ types needed for the conversions FMT specifies. Returns
+ the number of arguments required by FMT.
+
+ The ARGINFO function registered with a user-defined format is passed a
+ `struct printf_info' describing the format spec being parsed. A width
+ or precision of INT_MIN means a `*' was used to indicate that the
+ width/precision will come from an arg. The function should fill in the
+ array it is passed with the types of the arguments it wants, and return
+ the number of arguments it wants. */
+
+extern size_t parse_printf_format PARAMS ((const char *__fmt,
+ size_t __n,
+ int *__argtypes));
+
+/* Codes returned by `parse_printf_format' for basic types.
+
+ These values cover all the standard format specifications.
+ Users can add new values after PA_LAST for their own types. */
+
+enum
+{ /* C type: */
+ PA_INT, /* int */
+ PA_CHAR, /* int, cast to char */
+ PA_STRING, /* const char *, a '\0'-terminated string */
+ PA_POINTER, /* void * */
+ PA_FLOAT, /* float */
+ PA_DOUBLE, /* double */
+ PA_LAST
+};
+
+/* Flag bits that can be set in a type returned by `parse_printf_format'. */
+#define PA_FLAG_MASK 0xff00
+#define PA_FLAG_LONG_LONG (1 << 8)
+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
+#define PA_FLAG_LONG (1 << 9)
+#define PA_FLAG_SHORT (1 << 10)
+#define PA_FLAG_PTR (1 << 11)
+
+
+#endif /* printf.h */
diff --git a/lib/stpcpy.c b/lib/stpcpy.c
new file mode 100644
index 0000000..0ad8863
--- /dev/null
+++ b/lib/stpcpy.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 1992, 1995, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#undef __stpcpy
+#undef stpcpy
+
+#ifndef weak_alias
+# define __stpcpy stpcpy
+#endif
+
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
+char *
+__stpcpy (dest, src)
+ char *dest;
+ const char *src;
+{
+ register char *d = dest;
+ register const char *s = src;
+
+ do
+ *d++ = *s;
+ while (*s++ != '\0');
+
+ return d - 1;
+}
+#ifdef weak_alias
+weak_alias (__stpcpy, stpcpy)
+#endif
diff --git a/lib/stpncpy.c b/lib/stpncpy.c
new file mode 100644
index 0000000..fcbdfe5
--- /dev/null
+++ b/lib/stpncpy.c
@@ -0,0 +1,101 @@
+/* Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+/* This is almost copied from strncpy.c, written by Torbjorn Granlund. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# include <string.h>
+#else
+# include <sys/types.h>
+#endif
+
+#ifndef weak_alias
+# define __stpncpy stpncpy
+#endif
+
+/* Copy no more than N characters of SRC to DEST, returning the address of
+ the terminating '\0' in DEST, if any, or else DEST + N. */
+char *
+__stpncpy (dest, src, n)
+ char *dest;
+ const char *src;
+ size_t n;
+{
+ char c;
+ char *s = dest;
+
+ if (n >= 4)
+ {
+ size_t n4 = n >> 2;
+
+ for (;;)
+ {
+ c = *src++;
+ *dest++ = c;
+ if (c == '\0')
+ break;
+ c = *src++;
+ *dest++ = c;
+ if (c == '\0')
+ break;
+ c = *src++;
+ *dest++ = c;
+ if (c == '\0')
+ break;
+ c = *src++;
+ *dest++ = c;
+ if (c == '\0')
+ break;
+ if (--n4 == 0)
+ goto last_chars;
+ }
+ n -= dest - s;
+ goto zero_fill;
+ }
+
+ last_chars:
+ n &= 3;
+ if (n == 0)
+ return dest;
+
+ for (;;)
+ {
+ c = *src++;
+ --n;
+ *dest++ = c;
+ if (c == '\0')
+ break;
+ if (n == 0)
+ return dest;
+ }
+
+ zero_fill:
+ while (n-- > 0)
+ dest[n] = '\0';
+
+ return dest - 1;
+}
+#ifdef weak_alias
+weak_alias (__stpncpy, stpncpy)
+#endif
diff --git a/lib/strcasecmp.c b/lib/strcasecmp.c
new file mode 100644
index 0000000..776d62a
--- /dev/null
+++ b/lib/strcasecmp.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#ifndef weak_alias
+# define __strcasecmp strcasecmp
+# define TOLOWER(Ch) tolower (Ch)
+#else
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define __strcasecmp __strcasecmp_l
+# define TOLOWER(Ch) __tolower_l ((Ch), loc)
+# else
+# define TOLOWER(Ch) tolower (Ch)
+# endif
+#endif
+
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define LOCALE_PARAM , loc
+# define LOCALE_PARAM_DECL __locale_t loc;
+#else
+# define LOCALE_PARAM
+# define LOCALE_PARAM_DECL
+#endif
+
+/* Compare S1 and S2, ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less than,
+ equal to or greater than S2. */
+int
+__strcasecmp (s1, s2 LOCALE_PARAM)
+ const char *s1;
+ const char *s2;
+ LOCALE_PARAM_DECL
+{
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ if (p1 == p2)
+ return 0;
+
+ do
+ {
+ c1 = TOLOWER (*p1++);
+ c2 = TOLOWER (*p2++);
+ if (c1 == '\0')
+ break;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
+#ifndef __strcasecmp
+weak_alias (__strcasecmp, strcasecmp)
+#endif
diff --git a/lib/strcspn.c b/lib/strcspn.c
new file mode 100644
index 0000000..6c2e0b8
--- /dev/null
+++ b/lib/strcspn.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1991, 1994, 1996, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _LIBC || HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#undef strcspn
+
+/* Return the length of the maximum initial segment of S
+ which contains no characters from REJECT. */
+size_t
+strcspn (s, reject)
+ const char *s;
+ const char *reject;
+{
+ size_t count = 0;
+
+ while (*s != '\0')
+ if (strchr (reject, *s++) == NULL)
+ ++count;
+ else
+ return count;
+
+ return count;
+}
diff --git a/lib/strncasecmp.c b/lib/strncasecmp.c
new file mode 100644
index 0000000..52af434
--- /dev/null
+++ b/lib/strncasecmp.c
@@ -0,0 +1,80 @@
+/* Compare at most N characters of two strings without taking care for
+ the case.
+ Copyright (C) 1992, 1996, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#ifndef weak_alias
+# define __strncasecmp strncasecmp
+# define TOLOWER(Ch) tolower (Ch)
+#else
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define __strncasecmp __strncasecmp_l
+# define TOLOWER(Ch) __tolower_l ((Ch), loc)
+# else
+# define TOLOWER(Ch) tolower (Ch)
+# endif
+#endif
+
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define LOCALE_PARAM , loc
+# define LOCALE_PARAM_DECL __locale_t loc;
+#else
+# define LOCALE_PARAM
+# define LOCALE_PARAM_DECL
+#endif
+
+/* Compare no more than N characters of S1 and S2,
+ ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less
+ than, equal to or greater than S2. */
+int
+__strncasecmp (s1, s2, n LOCALE_PARAM)
+ const char *s1;
+ const char *s2;
+ size_t n;
+ LOCALE_PARAM_DECL
+{
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ if (p1 == p2 || n == 0)
+ return 0;
+
+ do
+ {
+ c1 = TOLOWER (*p1++);
+ c2 = TOLOWER (*p2++);
+ if (c1 == '\0' || c1 != c2)
+ return c1 - c2;
+ } while (--n > 0);
+
+ return c1 - c2;
+}
+#ifndef __strncasecmp
+weak_alias (__strncasecmp, strncasecmp)
+#endif
diff --git a/lib/strstr.c b/lib/strstr.c
new file mode 100644
index 0000000..03d6c8e
--- /dev/null
+++ b/lib/strstr.c
@@ -0,0 +1,125 @@
+/* Return the offset of one string within another.
+ Copyright (C) 1994, 1996, 1997 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * My personal strstr() implementation that beats most other algorithms.
+ * Until someone tells me otherwise, I assume that this is the
+ * fastest implementation of strstr() in C.
+ * I deliberately chose not to comment it. You should have at least
+ * as much fun trying to understand it, as I had to write it :-).
+ *
+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _LIBC || defined HAVE_STRING_H
+# include <string.h>
+#endif
+
+typedef unsigned chartype;
+
+#undef strstr
+
+char *
+strstr (phaystack, pneedle)
+ const char *phaystack;
+ const char *pneedle;
+{
+ register const unsigned char *haystack, *needle;
+ register chartype b, c;
+
+ haystack = (const unsigned char *) phaystack;
+ needle = (const unsigned char *) pneedle;
+
+ b = *needle;
+ if (b != '\0')
+ {
+ haystack--; /* possible ANSI violation */
+ do
+ {
+ c = *++haystack;
+ if (c == '\0')
+ goto ret0;
+ }
+ while (c != b);
+
+ c = *++needle;
+ if (c == '\0')
+ goto foundneedle;
+ ++needle;
+ goto jin;
+
+ for (;;)
+ {
+ register chartype a;
+ register const unsigned char *rhaystack, *rneedle;
+
+ do
+ {
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+ if (a == b)
+ break;
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+shloop: }
+ while (a != b);
+
+jin: a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+
+ if (a != c)
+ goto shloop;
+
+ rhaystack = haystack-- + 1;
+ rneedle = needle;
+ a = *rneedle;
+
+ if (*rhaystack == a)
+ do
+ {
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = *++needle;
+ if (*rhaystack != a)
+ break;
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = *++needle;
+ }
+ while (*rhaystack == a);
+
+ needle = rneedle; /* took the register-poor approach */
+
+ if (a == '\0')
+ break;
+ }
+ }
+foundneedle:
+ return (char*) haystack;
+ret0:
+ return 0;
+}
diff --git a/lib/strtol.c b/lib/strtol.c
new file mode 100644
index 0000000..d49f1c6
--- /dev/null
+++ b/lib/strtol.c
@@ -0,0 +1,445 @@
+/* Convert string representation of a number into an integer value.
+ Copyright (C) 1991, 92, 94, 95, 96, 97, 98 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define USE_NUMBER_GROUPING
+# define STDC_HEADERS
+# define HAVE_LIMITS_H
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef NULL
+# define NULL 0
+# endif
+#endif
+
+#ifdef USE_NUMBER_GROUPING
+# include "../locale/localeinfo.h"
+#endif
+
+/* Nonzero if we are defining `strtoul' or `strtoull', operating on
+ unsigned integers. */
+#ifndef UNSIGNED
+# define UNSIGNED 0
+# define INT LONG int
+#else
+# define INT unsigned LONG int
+#endif
+
+/* Determine the name. */
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol __wcstoull_l
+# else
+# define strtol __wcstoul_l
+# endif
+# else
+# ifdef QUAD
+# define strtol __strtoull_l
+# else
+# define strtol __strtoul_l
+# endif
+# endif
+# else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol __wcstoll_l
+# else
+# define strtol __wcstol_l
+# endif
+# else
+# ifdef QUAD
+# define strtol __strtoll_l
+# else
+# define strtol __strtol_l
+# endif
+# endif
+# endif
+#else
+# if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoull
+# else
+# define strtol wcstoul
+# endif
+# else
+# ifdef QUAD
+# define strtol strtoull
+# else
+# define strtol strtoul
+# endif
+# endif
+# else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoll
+# else
+# define strtol wcstol
+# endif
+# else
+# ifdef QUAD
+# define strtol strtoll
+# endif
+# endif
+# endif
+#endif
+
+/* If QUAD is defined, we are defining `strtoll' or `strtoull',
+ operating on `long long int's. */
+#ifdef QUAD
+# define LONG long long
+# undef LONG_MIN
+# define LONG_MIN LONG_LONG_MIN
+# undef LONG_MAX
+# define LONG_MAX LONG_LONG_MAX
+# undef ULONG_MAX
+# define ULONG_MAX ULONG_LONG_MAX
+# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
+ /* Work around gcc bug with using this constant. */
+ static const unsigned long long int maxquad = ULONG_LONG_MAX;
+# undef ULONG_MAX
+# define ULONG_MAX maxquad
+# endif
+#else
+# define LONG long
+
+#ifndef ULONG_MAX
+# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
+#endif
+#ifndef LONG_MAX
+# define LONG_MAX ((long int) (ULONG_MAX >> 1))
+#endif
+#endif
+
+
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# undef _NL_CURRENT
+# define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+# define LOCALE_PARAM , loc
+# define LOCALE_PARAM_DECL __locale_t loc;
+#else
+# define LOCALE_PARAM
+# define LOCALE_PARAM_DECL
+#endif
+
+#if defined _LIBC || defined HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#ifdef USE_WIDE_CHAR
+# include <wctype.h>
+# define L_(Ch) L##Ch
+# define UCHAR_TYPE wint_t
+# define STRING_TYPE wchar_t
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
+# define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __towupper_l ((Ch), loc)
+# else
+# define ISSPACE(Ch) iswspace (Ch)
+# define ISALPHA(Ch) iswalpha (Ch)
+# define TOUPPER(Ch) towupper (Ch)
+# endif
+# else
+# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+# else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+# endif
+# define L_(Ch) Ch
+# define UCHAR_TYPE unsigned char
+# define STRING_TYPE char
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define ISSPACE(Ch) __isspace_l ((Ch), loc)
+# define ISALPHA(Ch) __isalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __toupper_l ((Ch), loc)
+# else
+# define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch))
+# define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch))
+# define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch))
+# endif
+#endif
+
+#ifdef __STDC__
+# define INTERNAL(X) INTERNAL1(X)
+# define INTERNAL1(X) __##X##_internal
+# define WEAKNAME(X) WEAKNAME1(X)
+#else
+# define INTERNAL(X) __/**/X/**/_internal
+#endif
+
+#ifdef USE_NUMBER_GROUPING
+/* This file defines a function to check for correct grouping. */
+# include "grouping.h"
+#endif
+
+
+
+/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+ If BASE is 0 the base is determined by the presence of a leading
+ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+ If BASE is < 2 or > 36, it is reset to 10.
+ If ENDPTR is not NULL, a pointer to the character after the last
+ one converted is stored in *ENDPTR. */
+
+INT
+INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int base;
+ int group;
+ LOCALE_PARAM_DECL
+{
+ int negative;
+ register unsigned LONG int cutoff;
+ register unsigned int cutlim;
+ register unsigned LONG int i;
+ register const STRING_TYPE *s;
+ register UCHAR_TYPE c;
+ const STRING_TYPE *save, *end;
+ int overflow;
+
+#ifdef USE_NUMBER_GROUPING
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+ struct locale_data *current = loc->__locales[LC_NUMERIC];
+# endif
+ /* The thousands character of the current locale. */
+ wchar_t thousands = L'\0';
+ /* The numeric grouping specification of the current locale,
+ in the format described in <locale.h>. */
+ const char *grouping;
+
+ if (group)
+ {
+ grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+ if (*grouping <= 0 || *grouping == CHAR_MAX)
+ grouping = NULL;
+ else
+ {
+ /* Figure out the thousands separator character. */
+# if defined _LIBC || defined _HAVE_BTOWC
+ thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
+ if (thousands == WEOF)
+ thousands = L'\0';
+# endif
+ if (thousands == L'\0')
+ grouping = NULL;
+ }
+ }
+ else
+ grouping = NULL;
+#endif
+
+ if (base < 0 || base == 1 || base > 36)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (ISSPACE (*s))
+ ++s;
+ if (*s == L_('\0'))
+ goto noconv;
+
+ /* Check for a sign. */
+ if (*s == L_('-'))
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == L_('+'))
+ {
+ negative = 0;
+ ++s;
+ }
+ else
+ negative = 0;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == L_('0'))
+ {
+ if (TOUPPER (s[1]) == L_('X'))
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+
+#ifdef USE_NUMBER_GROUPING
+ if (group)
+ {
+ /* Find the end of the digit string and check its grouping. */
+ end = s;
+ for (c = *end; c != L_('\0'); c = *++end)
+ if ((wchar_t) c != thousands
+ && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
+ && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
+ break;
+ if (*s == thousands)
+ end = s;
+ else
+ end = correctly_grouped_prefix (s, end, thousands, grouping);
+ }
+ else
+#endif
+ end = NULL;
+
+ cutoff = ULONG_MAX / (unsigned LONG int) base;
+ cutlim = ULONG_MAX % (unsigned LONG int) base;
+
+ overflow = 0;
+ i = 0;
+ for (c = *s; c != L_('\0'); c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= L_('0') && c <= L_('9'))
+ c -= L_('0');
+ else if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (unsigned LONG int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (STRING_TYPE *) s;
+
+#if !UNSIGNED
+ /* Check for a value that is within the range of
+ `unsigned LONG int', but outside the range of `LONG int'. */
+ if (overflow == 0
+ && i > (negative
+ ? -((unsigned LONG int) (LONG_MIN + 1)) + 1
+ : (unsigned LONG int) LONG_MAX))
+ overflow = 1;
+#endif
+
+ if (overflow)
+ {
+ __set_errno (ERANGE);
+#if UNSIGNED
+ return ULONG_MAX;
+#else
+ return negative ? LONG_MIN : LONG_MAX;
+#endif
+ }
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -i : i;
+
+noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr != NULL)
+ if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
+ && save[-2] == L_('0'))
+ *endptr = (STRING_TYPE *) &save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = (STRING_TYPE *) nptr;
+
+ return 0L;
+}
+
+/* External user entry point. */
+
+#if _LIBC - 0 == 0
+# undef PARAMS
+# if defined (__STDC__) && __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+
+/* Prototype. */
+INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base));
+#endif
+
+
+INT
+#ifdef weak_function
+weak_function
+#endif
+strtol (nptr, endptr, base LOCALE_PARAM)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int base;
+ LOCALE_PARAM_DECL
+{
+ return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
+}
diff --git a/lib/strtoul.c b/lib/strtoul.c
new file mode 100644
index 0000000..873f540
--- /dev/null
+++ b/lib/strtoul.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#define UNSIGNED 1
+
+#include <strtol.c>
diff --git a/lib/system.h b/lib/system.h
new file mode 100644
index 0000000..75c2ed8
--- /dev/null
+++ b/lib/system.h
@@ -0,0 +1,139 @@
+/* Header for GNU gettext libiberty
+ Copyright (C) 1995, 1996, 1997 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _SYSTEM_H
+#define _SYSTEM_H 1
+
+#ifndef PARAMS
+# if __STDC__
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+# include <malloc.h>
+# endif
+unsigned long strtoul ();
+#endif
+
+/* Prototypes for helper functions. */
+extern FILE *open_po_file PARAMS ((const char *__input_name,
+ char **__file_name));
+
+/* Wrapper functions with error checking for standard functions. */
+extern char *xgetcwd PARAMS ((void));
+extern void *xmalloc PARAMS ((size_t __n));
+extern void *xrealloc PARAMS ((void *__p, size_t __n));
+extern char *xstrdup PARAMS ((const char *__string));
+extern char *stpcpy PARAMS ((char *__dst, const char *__src));
+extern char *stpncpy PARAMS ((char *__dst, const char *__src, size_t __n));
+extern size_t parse_printf_format PARAMS ((const char *__fmt, size_t __n,
+ int *__argtypes));
+extern int asprintf PARAMS ((char **, const char *, ...));
+extern int strcasecmp PARAMS ((const char *__s1, const char *__s2));
+extern int strncasecmp PARAMS ((const char *__s1, const char *__s2,
+ size_t __n));
+extern char *strstr PARAMS ((const char *__str, const char *__sub));
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+#else
+# include <strings.h>
+#endif
+#if !HAVE_MEMCPY
+# ifndef memcpy
+# define memcpy(D, S, N) bcopy ((S), (D), (N))
+# endif
+#endif
+#if !HAVE_STRCHR
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#ifdef __GNUC__
+# ifndef alloca
+# define alloca __builtin_alloca
+# endif
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifdef __hpux /* This section must match that of bison generated files. */
+# ifdef __cplusplus
+extern "C" void *alloca (unsigned int);
+# else /* not __cplusplus */
+void *alloca ();
+# endif /* not __cplusplus */
+# else /* not __hpux */
+# ifndef alloca
+char *alloca ();
+# endif
+# endif /* __hpux */
+# endif
+# endif
+#endif
+
+/* Before we define the following symbols we get the <limits.h> file if
+ available since otherwise we get redefinitions on some systems. */
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifndef MAX
+# if __STDC__ && defined __GNUC__ && __GNUC__ >= 2
+# define MAX(a,b) (__extension__ \
+ ({__typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; \
+ }))
+# else
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+# endif
+#endif
+
+/* Some systems do not define EXIT_*, even with STDC_HEADERS. */
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+
+/* When not using the GNU libc we use the basename implementation we
+ provide here. */
+#ifndef __GNU_LIBRARY__
+extern char *gnu_basename PARAMS ((const char *));
+# define basename(Arg) gnu_basename (Arg)
+#endif
+
+#endif
diff --git a/lib/vasprintf.c b/lib/vasprintf.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/vasprintf.c
diff --git a/lib/xgetcwd.c b/lib/xgetcwd.c
new file mode 100644
index 0000000..7ab2204
--- /dev/null
+++ b/lib/xgetcwd.c
@@ -0,0 +1,79 @@
+/* xgetcwd.c -- return current directory with unlimited length
+ Copyright (C) 1992, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include <sys/types.h>
+#include "pathmax.h"
+
+#if HAVE_GETCWD
+char *getcwd ();
+#else
+char *getwd ();
+# define getcwd(Buf, Max) getwd (Buf)
+#endif
+
+/* Amount to increase buffer size by in each try. */
+#define PATH_INCR 32
+
+char *xmalloc ();
+char *xrealloc ();
+void free ();
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error. */
+
+char *
+xgetcwd ()
+{
+ char *cwd;
+ char *ret;
+ unsigned path_max;
+
+ errno = 0;
+ path_max = (unsigned) PATH_MAX;
+ path_max += 2; /* The getcwd docs say to do this. */
+
+ cwd = xmalloc (path_max);
+
+ errno = 0;
+ while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE)
+ {
+ path_max += PATH_INCR;
+ cwd = xrealloc (cwd, path_max);
+ errno = 0;
+ }
+
+ if (ret == NULL)
+ {
+ int save_errno = errno;
+ free (cwd);
+ errno = save_errno;
+ return NULL;
+ }
+ return cwd;
+}
diff --git a/lib/xmalloc.c b/lib/xmalloc.c
new file mode 100644
index 0000000..8217c99
--- /dev/null
+++ b/lib/xmalloc.c
@@ -0,0 +1,129 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 91, 92, 93, 94, 95, 96 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if __STDC__
+# define VOID void
+#else
+# define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+VOID *calloc ();
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define textdomain(Domain)
+# define _(Text) Text
+#endif
+
+#include "error.h"
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+/* Prototypes for functions defined here. */
+#if defined (__STDC__) && __STDC__
+static VOID *fixup_null_alloc (size_t n);
+VOID *xmalloc (size_t n);
+VOID *xcalloc (size_t n, size_t s);
+VOID *xrealloc (VOID *p, size_t n);
+#endif
+
+
+/* Exit value when the requested amount of memory is not available.
+ The caller may set it to some other value. */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error ();
+#endif
+
+static VOID *
+fixup_null_alloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = 0;
+ if (n == 0)
+ p = malloc ((size_t) 1);
+ if (p == 0)
+ error (xmalloc_exit_failure, 0, _("Memory exhausted"));
+ return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+VOID *
+xmalloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = malloc (n);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
+
+/* Allocate memory for N elements of S bytes, with error checking. */
+
+VOID *
+xcalloc (n, s)
+ size_t n, s;
+{
+ VOID *p;
+
+ p = calloc (n, s);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc. */
+
+VOID *
+xrealloc (p, n)
+ VOID *p;
+ size_t n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ p = realloc (p, n);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
diff --git a/lib/xstrdup.c b/lib/xstrdup.c
new file mode 100644
index 0000000..d5bcaf3
--- /dev/null
+++ b/lib/xstrdup.c
@@ -0,0 +1,42 @@
+/* xstrdup.c -- copy a string with out of memory checking
+ Copyright (C) 1990, 1996 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if defined (__STDC__) && __STDC__
+char *xmalloc (size_t);
+char *xstrdup (char *string);
+#else
+char *xmalloc ();
+#endif
+
+/* Return a newly allocated copy of STRING. */
+
+char *
+xstrdup (string)
+ char *string;
+{
+ return strcpy (xmalloc (strlen (string) + 1), string);
+}