diff options
author | Ulrich Drepper <drepper@cygnus.com> | 2000-06-16 07:49:23 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@cygnus.com> | 2000-06-16 07:49:23 +0000 |
commit | 60d2084de5dc3b65e6657f695f0f26df24b0f565 (patch) | |
tree | 224f21c30351570d6d7f06a385e829d5ab320f67 /lib | |
download | external_gettext-60d2084de5dc3b65e6657f695f0f26df24b0f565.zip external_gettext-60d2084de5dc3b65e6657f695f0f26df24b0f565.tar.gz external_gettext-60d2084de5dc3b65e6657f695f0f26df24b0f565.tar.bz2 |
Initial revision
Diffstat (limited to 'lib')
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); +} |