summaryrefslogtreecommitdiff
path: root/xc/util
diff options
context:
space:
mode:
Diffstat (limited to 'xc/util')
-rw-r--r--xc/util/compress/Makefile66
-rw-r--r--xc/util/compress/README283
-rw-r--r--xc/util/compress/USERMEM1
-rw-r--r--xc/util/compress/compress.1252
-rw-r--r--xc/util/compress/compress.c1550
-rw-r--r--xc/util/compress/usermem.sh94
-rw-r--r--xc/util/memleak/Imakefile71
-rw-r--r--xc/util/memleak/README70
-rwxr-xr-xxc/util/memleak/find-rtns.sh28
-rw-r--r--xc/util/memleak/fmalloc.c1135
-rw-r--r--xc/util/memleak/ftest.c49
-rw-r--r--xc/util/memleak/getreti386.c36
-rw-r--r--xc/util/memleak/getretmips.c191
-rw-r--r--xc/util/memleak/getretspar.c62
-rw-r--r--xc/util/memleak/getrettest.c44
-rw-r--r--xc/util/memleak/mipsstack.s39
-rw-r--r--xc/util/memleak/sparcsolstack.s11
-rw-r--r--xc/util/memleak/sparcstack.s11
-rw-r--r--xc/util/memleak/stackbottom.c123
-rw-r--r--xc/util/misc/dlsym.c29
-rw-r--r--xc/util/misc/rt.stdarg.h8
-rw-r--r--xc/util/misc/thr_stubs.c27
-rw-r--r--xc/util/patch/ChangeLog290
-rwxr-xr-xxc/util/patch/Configure1476
-rw-r--r--xc/util/patch/EXTERN.h21
-rw-r--r--xc/util/patch/INTERN.h19
-rw-r--r--xc/util/patch/MANIFEST27
-rw-r--r--xc/util/patch/Makefile.SH116
-rw-r--r--xc/util/patch/Makefile.nt41
-rw-r--r--xc/util/patch/README98
-rw-r--r--xc/util/patch/backupfile.c340
-rw-r--r--xc/util/patch/backupfile.h37
-rw-r--r--xc/util/patch/common.h214
-rw-r--r--xc/util/patch/config.H33
-rw-r--r--xc/util/patch/config.h.SH146
-rw-r--r--xc/util/patch/config.h.nt82
-rw-r--r--xc/util/patch/inp.c387
-rw-r--r--xc/util/patch/inp.h18
-rw-r--r--xc/util/patch/malloc.c469
-rw-r--r--xc/util/patch/patch.c941
-rw-r--r--xc/util/patch/patch.man551
-rw-r--r--xc/util/patch/patchlevel.h2
-rw-r--r--xc/util/patch/pch.c1313
-rw-r--r--xc/util/patch/pch.h38
-rw-r--r--xc/util/patch/util.c474
-rw-r--r--xc/util/patch/util.h88
-rw-r--r--xc/util/patch/version.c25
-rw-r--r--xc/util/patch/version.h9
-rw-r--r--xc/util/patch/winnt.h25
49 files changed, 11460 insertions, 0 deletions
diff --git a/xc/util/compress/Makefile b/xc/util/compress/Makefile
new file mode 100644
index 000000000..8fd79e577
--- /dev/null
+++ b/xc/util/compress/Makefile
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 1987 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that the above copyright notice and this paragraph are
+# duplicated in all such forms and that any documentation,
+# advertising materials, and other materials related to such
+# distribution and use acknowledge that the software was developed
+# by the University of California, Berkeley. The name of the
+# University may not be used to endorse or promote products derived
+# from this software without specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+# @(#)Makefile 5.9 (Berkeley) 10/15/88
+#
+CFLAGS= -O -DBSD4_2 -DSACREDMEM=256000 -DUSERMEM=`cat USERMEM`
+LIBC= /lib/libc.a
+SRCS= compress.c
+OBJS=
+MAN= compress.0
+
+all: compress
+
+compress: USERMEM ${LIBC}
+ ${CC} ${CFLAGS} -o $@ $@.c
+
+#this one is for OS/2, change location of BINMODE
+BINMODE=/emx/lib/binmode.o
+compress.exe: compress.c
+ gcc -O -o compress.exe compress.c ${BINMODE}
+
+# USERMEM may have to be set by hand. It should contain the amount of
+# available user memory in bytes. Set it to zero, for physical memory
+# less than 1 Meg.
+USERMEM: FRC
+ sh usermem.sh > USERMEM
+
+clean:
+ rm -f ${OBJS} core compress
+
+cleandir: clean
+ rm -f ${MAN} tags .depend
+
+depend: ${SRCS}
+ mkdep -p ${CFLAGS} ${SRCS}
+
+install: ${MAN}
+ install -s -o bin -g bin -m 755 compress ${DESTDIR}/usr/ucb/compress
+ rm -f ${DESTDIR}/usr/ucb/uncompress ${DESTDIR}/usr/ucb/zcat
+ ln ${DESTDIR}/usr/ucb/compress ${DESTDIR}/usr/ucb/uncompress
+ ln ${DESTDIR}/usr/ucb/compress ${DESTDIR}/usr/ucb/zcat
+ rm -f ${DESTDIR}/usr/man/cat1/uncompress.0 ${DESTDIR}/usr/man/cat1/zcat.0
+ install -c -o bin -g bin -m 444 compress.0 ${DESTDIR}/usr/man/cat1
+ ln ${DESTDIR}/usr/man/cat1/compress.0 ${DESTDIR}/usr/man/cat1/uncompress.0
+ ln ${DESTDIR}/usr/man/cat1/compress.0 ${DESTDIR}/usr/man/cat1/zcat.0
+
+lint: ${SRCS}
+ lint ${CFLAGS} ${SRCS}
+
+tags: ${SRCS}
+ ctags ${SRCS}
+
+FRC:
diff --git a/xc/util/compress/README b/xc/util/compress/README
new file mode 100644
index 000000000..c8375c85c
--- /dev/null
+++ b/xc/util/compress/README
@@ -0,0 +1,283 @@
+
+ @(#)README 5.3 (Berkeley) 9/17/85
+
+Compress version 4.0 improvements over 3.0:
+ o compress() speedup (10-50%) by changing division hash to xor
+ o decompress() speedup (5-10%)
+ o Memory requirements reduced (3-30%)
+ o Stack requirements reduced to less than 4kb
+ o Removed 'Big+Fast' compress code (FBITS) because of compress speedup
+ o Portability mods for Z8000 and PC/XT (but not zeus 3.2)
+ o Default to 'quiet' mode
+ o Unification of 'force' flags
+ o Manual page overhaul
+ o Portability enhancement for M_XENIX
+ o Removed text on #else and #endif
+ o Added "-V" switch to print version and options
+ o Added #defines for SIGNED_COMPARE_SLOW
+ o Added Makefile and "usermem" program
+ o Removed all floating point computations
+ o New programs: [deleted]
+
+The "usermem" script attempts to determine the maximum process size. Some
+editing of the script may be necessary (see the comments). [It should work
+fine on 4.3 bsd.] If you can't get it to work at all, just create file
+"USERMEM" containing the maximum process size in decimal.
+
+The following preprocessor symbols control the compilation of "compress.c":
+
+ o USERMEM Maximum process memory on the system
+ o SACREDMEM Amount to reserve for other proceses
+ o SIGNED_COMPARE_SLOW Unsigned compare instructions are faster
+ o NO_UCHAR Don't use "unsigned char" types
+ o BITS Overrules default set by USERMEM-SACREDMEM
+ o vax Generate inline assembler
+ o interdata Defines SIGNED_COMPARE_SLOW
+ o M_XENIX Makes arrays < 65536 bytes each
+ o pdp11 BITS=12, NO_UCHAR
+ o z8000 BITS=12
+ o pcxt BITS=12
+ o BSD4_2 Allow long filenames ( > 14 characters) &
+ Call setlinebuf(stderr)
+
+The difference "usermem-sacredmem" determines the maximum BITS that can be
+specified with the "-b" flag.
+
+memory: at least BITS
+------ -- ----- ----
+ 433,484 16
+ 229,600 15
+ 127,536 14
+ 73,464 13
+ 0 12
+
+The default is BITS=16.
+
+The maximum bits can be overrulled by specifying "-DBITS=bits" at
+compilation time.
+
+WARNING: files compressed on a large machine with more bits than allowed by
+a version of compress on a smaller machine cannot be decompressed! Use the
+"-b12" flag to generate a file on a large machine that can be uncompressed
+on a 16-bit machine.
+
+The output of compress 4.0 is fully compatible with that of compress 3.0.
+In other words, the output of compress 4.0 may be fed into uncompress 3.0 or
+the output of compress 3.0 may be fed into uncompress 4.0.
+
+The output of compress 4.0 not compatible with that of
+compress 2.0. However, compress 4.0 still accepts the output of
+compress 2.0. To generate output that is compatible with compress
+2.0, use the undocumented "-C" flag.
+
+ -from mod.sources, submitted by vax135!petsd!joe (Joe Orost), 8/1/85
+--------------------------------
+
+Enclosed is compress version 3.0 with the following changes:
+
+1. "Block" compression is performed. After the BITS run out, the
+ compression ratio is checked every so often. If it is decreasing,
+ the table is cleared and a new set of substrings are generated.
+
+ This makes the output of compress 3.0 not compatible with that of
+ compress 2.0. However, compress 3.0 still accepts the output of
+ compress 2.0. To generate output that is compatible with compress
+ 2.0, use the undocumented "-C" flag.
+
+2. A quiet "-q" flag has been added for use by the news system.
+
+3. The character chaining has been deleted and the program now uses
+ hashing. This improves the speed of the program, especially
+ during decompression. Other speed improvements have been made,
+ such as using putc() instead of fwrite().
+
+4. A large table is used on large machines when a relatively small
+ number of bits is specified. This saves much time when compressing
+ for a 16-bit machine on a 32-bit virtual machine. Note that the
+ speed improvement only occurs when the input file is > 30000
+ characters, and the -b BITS is less than or equal to the cutoff
+ described below.
+
+Most of these changes were made by James A. Woods (ames!jaw). Thank you
+James!
+
+To compile compress:
+
+ cc -O -DUSERMEM=usermem -o compress compress.c
+
+Where "usermem" is the amount of physical user memory available (in bytes).
+If any physical memory is to be reserved for other processes, put in
+"-DSACREDMEM sacredmem", where "sacredmem" is the amount to be reserved.
+
+The difference "usermem-sacredmem" determines the maximum BITS that can be
+specified, and the cutoff bits where the large+fast table is used.
+
+memory: at least BITS cutoff
+------ -- ----- ---- ------
+ 4,718,592 16 13
+ 2,621,440 16 12
+ 1,572,864 16 11
+ 1,048,576 16 10
+ 631,808 16 --
+ 329,728 15 --
+ 178,176 14 --
+ 99,328 13 --
+ 0 12 --
+
+The default memory size is 750,000 which gives a maximum BITS=16 and no
+large+fast table.
+
+The maximum bits can be overruled by specifying "-DBITS=bits" at
+compilation time.
+
+If your machine doesn't support unsigned characters, define "NO_UCHAR"
+when compiling.
+
+If your machine has "int" as 16-bits, define "SHORT_INT" when compiling.
+
+After compilation, move "compress" to a standard executable location, such
+as /usr/local. Then:
+ cd /usr/local
+ ln compress uncompress
+ ln compress zcat
+
+On machines that have a fixed stack size (such as Perkin-Elmer), set the
+stack to at least 12kb. ("setstack compress 12" on Perkin-Elmer).
+
+Next, install the manual (compress.l).
+ cp compress.l /usr/man/manl
+ cd /usr/man/manl
+ ln compress.l uncompress.l
+ ln compress.l zcat.l
+
+ - or -
+
+ cp compress.l /usr/man/man1/compress.1
+ cd /usr/man/man1
+ ln compress.1 uncompress.1
+ ln compress.1 zcat.1
+
+ regards,
+ petsd!joe
+
+Here is a note from the net:
+
+>From hplabs!pesnta!amd!turtlevax!ken Sat Jan 5 03:35:20 1985
+Path: ames!hplabs!pesnta!amd!turtlevax!ken
+From: ken@turtlevax.UUCP (Ken Turkowski)
+Newsgroups: net.sources
+Subject: Re: Compress release 3.0 : sample Makefile
+Organization: CADLINC, Inc. @ Menlo Park, CA
+
+In the compress 3.0 source recently posted to mod.sources, there is a
+#define variable which can be set for optimum performance on a machine
+with a large amount of memory. A program (usermem) to calculate the
+useable amount of physical user memory is enclosed, as well as a sample
+4.2bsd Vax Makefile for compress.
+
+Here is the README file from the previous version of compress (2.0):
+
+>Enclosed is compress.c version 2.0 with the following bugs fixed:
+>
+>1. The packed files produced by compress are different on different
+> machines and dependent on the vax sysgen option.
+> The bug was in the different byte/bit ordering on the
+> various machines. This has been fixed.
+>
+> This version is NOT compatible with the original vax posting
+> unless the '-DCOMPATIBLE' option is specified to the C
+> compiler. The original posting has a bug which I fixed,
+> causing incompatible files. I recommend you NOT to use this
+> option unless you already have a lot of packed files from
+> the original posting by thomas.
+>2. The exit status is not well defined (on some machines) causing the
+> scripts to fail.
+> The exit status is now 0,1 or 2 and is documented in
+> compress.l.
+>3. The function getopt() is not available in all C libraries.
+> The function getopt() is no longer referenced by the
+> program.
+>4. Error status is not being checked on the fwrite() and fflush() calls.
+> Fixed.
+>
+>The following enhancements have been made:
+>
+>1. Added facilities of "compact" into the compress program. "Pack",
+> "Unpack", and "Pcat" are no longer required (no longer supplied).
+>2. Installed work around for C compiler bug with "-O".
+>3. Added a magic number header (\037\235). Put the bits specified
+> in the file.
+>4. Added "-f" flag to force overwrite of output file.
+>5. Added "-c" flag and "zcat" program. 'ln compress zcat' after you
+> compile.
+>6. The 'uncompress' script has been deleted; simply
+> 'ln compress uncompress' after you compile and it will work.
+>7. Removed extra bit masking for machines that support unsigned
+> characters. If your machine doesn't support unsigned characters,
+> define "NO_UCHAR" when compiling.
+>
+>Compile "compress.c" with "-O -o compress" flags. Move "compress" to a
+>standard executable location, such as /usr/local. Then:
+> cd /usr/local
+> ln compress uncompress
+> ln compress zcat
+>
+>On machines that have a fixed stack size (such as Perkin-Elmer), set the
+>stack to at least 12kb. ("setstack compress 12" on Perkin-Elmer).
+>
+>Next, install the manual (compress.l).
+> cp compress.l /usr/man/manl - or -
+> cp compress.l /usr/man/man1/compress.1
+>
+>Here is the README that I sent with my first posting:
+>
+>>Enclosed is a modified version of compress.c, along with scripts to make it
+>>run identically to pack(1), unpack(1), an pcat(1). Here is what I
+>>(petsd!joe) and a colleague (petsd!peora!srd) did:
+>>
+>>1. Removed VAX dependencies.
+>>2. Changed the struct to separate arrays; saves mucho memory.
+>>3. Did comparisons in unsigned, where possible. (Faster on Perkin-Elmer.)
+>>4. Sorted the character next chain and changed the search to stop
+>>prematurely. This saves a lot on the execution time when compressing.
+>>
+>>This version is totally compatible with the original version. Even though
+>>lint(1) -p has no complaints about compress.c, it won't run on a 16-bit
+>>machine, due to the size of the arrays.
+>>
+>>Here is the README file from the original author:
+>>
+>>>Well, with all this discussion about file compression (for news batching
+>>>in particular) going around, I decided to implement the text compression
+>>>algorithm described in the June Computer magazine. The author claimed
+>>>blinding speed and good compression ratios. It's certainly faster than
+>>>compact (but, then, what wouldn't be), but it's also the same speed as
+>>>pack, and gets better compression than both of them. On 350K bytes of
+>>>unix-wizards, compact took about 8 minutes of CPU, pack took about 80
+>>>seconds, and compress (herein) also took 80 seconds. But, compact and
+>>>pack got about 30% compression, whereas compress got over 50%. So, I
+>>>decided I had something, and that others might be interested, too.
+>>>
+>>>As is probably true of compact and pack (although I haven't checked),
+>>>the byte order within a word is probably relevant here, but as long as
+>>>you stay on a single machine type, you should be ok. (Can anybody
+>>>elucidate on this?) There are a couple of asm's in the code (extv and
+>>>insv instructions), so anyone porting it to another machine will have to
+>>>deal with this anyway (and could probably make it compatible with Vax
+>>>byte order at the same time). Anyway, I've linted the code (both with
+>>>and without -p), so it should run elsewhere. Note the longs in the
+>>>code, you can take these out if you reduce BITS to <= 15.
+>>>
+>>>Have fun, and as always, if you make good enhancements, or bug fixes,
+>>>I'd like to see them.
+>>>
+>>>=Spencer (thomas@utah-20, {harpo,hplabs,arizona}!utah-cs!thomas)
+>>
+>> regards,
+>> joe
+>>
+>>--
+>>Full-Name: Joseph M. Orost
+>>UUCP: ..!{decvax,ucbvax,ihnp4}!vax135!petsd!joe
+>>US Mail: MS 313; Perkin-Elmer; 106 Apple St; Tinton Falls, NJ 07724
+>>Phone: (201) 870-5844
diff --git a/xc/util/compress/USERMEM b/xc/util/compress/USERMEM
new file mode 100644
index 000000000..79ee5ef74
--- /dev/null
+++ b/xc/util/compress/USERMEM
@@ -0,0 +1 @@
+6144000
diff --git a/xc/util/compress/compress.1 b/xc/util/compress/compress.1
new file mode 100644
index 000000000..572e078f9
--- /dev/null
+++ b/xc/util/compress/compress.1
@@ -0,0 +1,252 @@
+.\" Copyright (c) 1986 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" James A. Woods, derived from original work by Spencer Thomas
+.\" and Joseph Orost.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" @(#)compress.1 6.6 (Berkeley) 10/15/88
+.\"
+.TH COMPRESS 1 "October 15, 1988"
+.UC 6
+.SH NAME
+compress, uncompress, zcat \- compress and expand data
+.SH SYNOPSIS
+.PU
+.ll +8
+.B compress
+[
+.B \-f
+] [
+.B \-v
+] [
+.B \-c
+] [
+.B \-b
+.I bits
+] [
+.I "name \&..."
+]
+.ll -8
+.br
+.B uncompress
+[
+.B \-f
+] [
+.B \-v
+] [
+.B \-c
+] [
+.I "name \&..."
+]
+.br
+.B zcat
+[
+.I "name \&..."
+]
+.SH DESCRIPTION
+.I Compress
+reduces the size of the named files using adaptive Lempel-Ziv coding.
+Whenever possible,
+each file is replaced by one with the extension
+.B "\&.Z,"
+while keeping the same ownership modes, access and modification times.
+If no files are specified, the standard input is compressed to the
+standard output.
+Compressed files can be restored to their original form using
+.I uncompress
+or
+.I zcat.
+.PP
+The
+.B \-f
+option will force compression of
+.IR name ,
+even if it does not actually shrink
+or the corresponding
+.IR name .Z
+file already exists.
+Except when run in the background under
+.IR /bin/sh ,
+if
+.B \-f
+is not given the user is prompted as to whether an existing
+.IR name .Z
+file should be overwritten.
+.PP
+The
+.B \-c
+(``cat'') option makes
+.I compress/uncompress
+write to the standard output; no files are changed.
+The nondestructive behavior of
+.I zcat
+is identical to that of
+.I uncompress
+.B \-c.
+.PP
+.I Compress
+uses the modified Lempel-Ziv algorithm popularized in
+"A Technique for High Performance Data Compression",
+Terry A. Welch,
+.I "IEEE Computer,"
+vol. 17, no. 6 (June 1984), pp. 8-19.
+Common substrings in the file are first replaced by 9-bit codes 257 and up.
+When code 512 is reached, the algorithm switches to 10-bit codes and
+continues to use more bits until the
+limit specified by the
+.B \-b
+flag is reached (default 16).
+.I Bits
+must be between 9 and 16. The default can be changed in the source to allow
+.I compress
+to be run on a smaller machine.
+.PP
+After the
+.I bits
+limit is attained,
+.I compress
+periodically checks the compression ratio. If it is increasing,
+.I compress
+continues to use the existing code dictionary. However,
+if the compression ratio decreases,
+.I compress
+discards the table of substrings and rebuilds it from scratch. This allows
+the algorithm to adapt to the next "block" of the file.
+.PP
+Note that the
+.B \-b
+flag is omitted for
+.I uncompress,
+since the
+.I bits
+parameter specified during compression
+is encoded within the output, along with
+a magic number to ensure that neither decompression of random data nor
+recompression of compressed data is attempted.
+.PP
+.ne 8
+The amount of compression obtained depends on the size of the
+input, the number of
+.I bits
+per code, and the distribution of common substrings.
+Typically, text such as source code or English
+is reduced by 50\-60%.
+Compression is generally much better than that achieved by
+Huffman coding (as used in
+.IR pack ),
+or adaptive Huffman coding
+.RI ( compact ),
+and takes less time to compute.
+.PP
+The
+.B \-v
+option causes
+the printing of the percentage reduction of each file.
+.PP
+If an error occurs, exit status is 1, else
+if the last file was not compressed because it became larger, the status
+is 2; else the status is 0.
+.SH "DIAGNOSTICS"
+Usage: compress [\-fvc] [\-b maxbits] [file ...]
+.in +8
+Invalid options were specified on the command line.
+.in -8
+Missing maxbits
+.in +8
+Maxbits must follow
+.BR \-b \.
+.in -8
+.IR file :
+not in compressed format
+.in +8
+The file specified to
+.I uncompress
+has not been compressed.
+.in -8
+.IR file :
+compressed with
+.I xx
+bits, can only handle
+.I yy
+bits
+.in +8
+.I File
+was compressed by a program that could deal with
+more
+.I bits
+than the compress code on this machine.
+Recompress the file with smaller
+.IR bits \.
+.in -8
+.IR file :
+already has .Z suffix -- no change
+.in +8
+The file is assumed to be already compressed.
+Rename the file and try again.
+.in -8
+.IR file :
+filename too long to tack on .Z
+.in +8
+The file cannot be compressed because its name is longer than
+12 characters.
+Rename and try again.
+This message does not occur on BSD systems.
+.in -8
+.I file
+already exists; do you wish to overwrite (y or n)?
+.in +8
+Respond "y" if you want the output file to be replaced; "n" if not.
+.in -8
+uncompress: corrupt input
+.in +8
+A SIGSEGV violation was detected which usually means that the input file is
+corrupted.
+.in -8
+Compression:
+.I "xx.xx%"
+.in +8
+Percentage of the input saved by compression.
+(Relevant only for
+.BR \-v \.)
+.in -8
+-- not a regular file: unchanged
+.in +8
+When the input file is not a regular file,
+(e.g. a directory), it is
+left unaltered.
+.in -8
+-- has
+.I xx
+other links: unchanged
+.in +8
+The input file has links; it is left unchanged. See
+.IR ln "(1)"
+for more information.
+.in -8
+-- file unchanged
+.in +8
+No savings is achieved by
+compression. The input remains virgin.
+.in -8
+.SH "BUGS"
+Although compressed files are compatible between machines with large memory,
+.BR \-b \12
+should be used for file transfer to architectures with
+a small process data space (64KB or less, as exhibited by the DEC PDP
+series, the Intel 80286, etc.)
+.PP
+.I compress
+should be more flexible about the existence of the `.Z' suffix.
diff --git a/xc/util/compress/compress.c b/xc/util/compress/compress.c
new file mode 100644
index 000000000..1d4fb1ed3
--- /dev/null
+++ b/xc/util/compress/compress.c
@@ -0,0 +1,1550 @@
+/*
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1985, 1986 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)compress.c 5.10 (Berkeley) 10/15/88";
+#endif /* not lint */
+
+/*
+ * Compress - data compression program
+ */
+#define min(a,b) ((a>b) ? b : a)
+
+/*
+ * machine variants which require cc -Dmachine: pdp11, z8000, pcxt
+ */
+
+/*
+ * Set USERMEM to the maximum amount of physical user memory available
+ * in bytes. USERMEM is used to determine the maximum BITS that can be used
+ * for compression.
+ *
+ * SACREDMEM is the amount of physical memory saved for others; compress
+ * will hog the rest.
+ */
+#ifndef SACREDMEM
+#define SACREDMEM 0
+#endif
+
+#ifndef USERMEM
+# define USERMEM 450000 /* default user memory */
+#endif
+
+#ifdef interdata /* (Perkin-Elmer) */
+#define SIGNED_COMPARE_SLOW /* signed compare is slower than unsigned */
+#endif
+
+#ifdef pdp11
+# define BITS 12 /* max bits/code for 16-bit machine */
+# define NO_UCHAR /* also if "unsigned char" functions as signed char */
+# undef USERMEM
+#endif /* pdp11 */ /* don't forget to compile with -i */
+
+#ifdef z8000
+# define BITS 12
+# undef vax /* weird preprocessor */
+# undef USERMEM
+#endif /* z8000 */
+
+#ifdef pcxt
+# define BITS 12
+# undef USERMEM
+#endif /* pcxt */
+
+#ifdef USERMEM
+# if USERMEM >= (433484+SACREDMEM)
+# define PBITS 16
+# else
+# if USERMEM >= (229600+SACREDMEM)
+# define PBITS 15
+# else
+# if USERMEM >= (127536+SACREDMEM)
+# define PBITS 14
+# else
+# if USERMEM >= (73464+SACREDMEM)
+# define PBITS 13
+# else
+# define PBITS 12
+# endif
+# endif
+# endif
+# endif
+# undef USERMEM
+#endif /* USERMEM */
+
+#ifdef PBITS /* Preferred BITS for this memory size */
+# ifndef BITS
+# define BITS PBITS
+# endif /* BITS */
+#endif /* PBITS */
+
+#if BITS == 16
+# define HSIZE 69001 /* 95% occupancy */
+#endif
+#if BITS == 15
+# define HSIZE 35023 /* 94% occupancy */
+#endif
+#if BITS == 14
+# define HSIZE 18013 /* 91% occupancy */
+#endif
+#if BITS == 13
+# define HSIZE 9001 /* 91% occupancy */
+#endif
+#if BITS <= 12
+# define HSIZE 5003 /* 80% occupancy */
+#endif
+
+#ifdef M_XENIX /* Stupid compiler can't handle arrays with */
+# if BITS == 16 /* more than 65535 bytes - so we fake it */
+# define XENIX_16
+# else
+# if BITS > 13 /* Code only handles BITS = 12, 13, or 16 */
+# define BITS 13
+# endif
+# endif
+#endif
+
+/*
+ * a code_int must be able to hold 2**BITS values of type int, and also -1
+ */
+#if BITS > 15
+typedef long int code_int;
+#else
+typedef int code_int;
+#endif
+
+#ifdef SIGNED_COMPARE_SLOW
+typedef unsigned long int count_int;
+typedef unsigned short int count_short;
+#else
+typedef long int count_int;
+#endif
+
+#ifdef NO_UCHAR
+ typedef char char_type;
+#else
+ typedef unsigned char char_type;
+#endif /* UCHAR */
+char_type magic_header[] = { "\037\235" }; /* 1F 9D */
+
+/* Defines for third byte of header */
+#define BIT_MASK 0x1f
+#define BLOCK_MASK 0x80
+/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
+ a fourth header byte (for expansion).
+*/
+#define INIT_BITS 9 /* initial number of bits/code */
+
+/*
+ * compress.c - File compression ala IEEE Computer, June 1984.
+ *
+ * Authors: Spencer W. Thomas (decvax!utah-cs!thomas)
+ * Jim McKie (decvax!mcvax!jim)
+ * Steve Davies (decvax!vax135!petsd!peora!srd)
+ * Ken Turkowski (decvax!decwrl!turtlevax!ken)
+ * James A. Woods (decvax!ihnp4!ames!jaw)
+ * Joe Orost (decvax!vax135!petsd!joe)
+ *
+ * Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release
+ * Log: compress.c,v
+ * Revision 4.0 85/07/30 12:50:00 joe
+ * Removed ferror() calls in output routine on every output except first.
+ * Prepared for release to the world.
+ *
+ * Revision 3.6 85/07/04 01:22:21 joe
+ * Remove much wasted storage by overlaying hash table with the tables
+ * used by decompress: tab_suffix[1<<BITS], stack[8000]. Updated USERMEM
+ * computations. Fixed dump_tab() DEBUG routine.
+ *
+ * Revision 3.5 85/06/30 20:47:21 jaw
+ * Change hash function to use exclusive-or. Rip out hash cache. These
+ * speedups render the megamemory version defunct, for now. Make decoder
+ * stack global. Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
+ *
+ * Revision 3.4 85/06/27 12:00:00 ken
+ * Get rid of all floating-point calculations by doing all compression ratio
+ * calculations in fixed point.
+ *
+ * Revision 3.3 85/06/24 21:53:24 joe
+ * Incorporate portability suggestion for M_XENIX. Got rid of text on #else
+ * and #endif lines. Cleaned up #ifdefs for vax and interdata.
+ *
+ * Revision 3.2 85/06/06 21:53:24 jaw
+ * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
+ * Default to "quiet" output (no compression statistics).
+ *
+ * Revision 3.1 85/05/12 18:56:13 jaw
+ * Integrate decompress() stack speedups (from early pointer mods by McKie).
+ * Repair multi-file USERMEM gaffe. Unify 'force' flags to mimic semantics
+ * of SVR2 'pack'. Streamline block-compress table clear logic. Increase
+ * output byte count by magic number size.
+ *
+ * Revision 3.0 84/11/27 11:50:00 petsd!joe
+ * Set HSIZE depending on BITS. Set BITS depending on USERMEM. Unrolled
+ * loops in clear routines. Added "-C" flag for 2.0 compatibility. Used
+ * unsigned compares on Perkin-Elmer. Fixed foreground check.
+ *
+ * Revision 2.7 84/11/16 19:35:39 ames!jaw
+ * Cache common hash codes based on input statistics; this improves
+ * performance for low-density raster images. Pass on #ifdef bundle
+ * from Turkowski.
+ *
+ * Revision 2.6 84/11/05 19:18:21 ames!jaw
+ * Vary size of hash tables to reduce time for small files.
+ * Tune PDP-11 hash function.
+ *
+ * Revision 2.5 84/10/30 20:15:14 ames!jaw
+ * Junk chaining; replace with the simpler (and, on the VAX, faster)
+ * double hashing, discussed within. Make block compression standard.
+ *
+ * Revision 2.4 84/10/16 11:11:11 ames!jaw
+ * Introduce adaptive reset for block compression, to boost the rate
+ * another several percent. (See mailing list notes.)
+ *
+ * Revision 2.3 84/09/22 22:00:00 petsd!joe
+ * Implemented "-B" block compress. Implemented REVERSE sorting of tab_next.
+ * Bug fix for last bits. Changed fwrite to putchar loop everywhere.
+ *
+ * Revision 2.2 84/09/18 14:12:21 ames!jaw
+ * Fold in news changes, small machine typedef from thomas,
+ * #ifdef interdata from joe.
+ *
+ * Revision 2.1 84/09/10 12:34:56 ames!jaw
+ * Configured fast table lookup for 32-bit machines.
+ * This cuts user time in half for b <= FBITS, and is useful for news batching
+ * from VAX to PDP sites. Also sped up decompress() [fwrite->putc] and
+ * added signal catcher [plus beef in writeerr()] to delete effluvia.
+ *
+ * Revision 2.0 84/08/28 22:00:00 petsd!joe
+ * Add check for foreground before prompting user. Insert maxbits into
+ * compressed file. Force file being uncompressed to end with ".Z".
+ * Added "-c" flag and "zcat". Prepared for release.
+ *
+ * Revision 1.10 84/08/24 18:28:00 turtlevax!ken
+ * Will only compress regular files (no directories), added a magic number
+ * header (plus an undocumented -n flag to handle old files without headers),
+ * added -f flag to force overwriting of possibly existing destination file,
+ * otherwise the user is prompted for a response. Will tack on a .Z to a
+ * filename if it doesn't have one when decompressing. Will only replace
+ * file if it was compressed.
+ *
+ * Revision 1.9 84/08/16 17:28:00 turtlevax!ken
+ * Removed scanargs(), getopt(), added .Z extension and unlimited number of
+ * filenames to compress. Flags may be clustered (-Ddvb12) or separated
+ * (-D -d -v -b 12), or combination thereof. Modes and other status is
+ * copied with copystat(). -O bug for 4.2 seems to have disappeared with
+ * 1.8.
+ *
+ * Revision 1.8 84/08/09 23:15:00 joe
+ * Made it compatible with vax version, installed jim's fixes/enhancements
+ *
+ * Revision 1.6 84/08/01 22:08:00 joe
+ * Sped up algorithm significantly by sorting the compress chain.
+ *
+ * Revision 1.5 84/07/13 13:11:00 srd
+ * Added C version of vax asm routines. Changed structure to arrays to
+ * save much memory. Do unsigned compares where possible (faster on
+ * Perkin-Elmer)
+ *
+ * Revision 1.4 84/07/05 03:11:11 thomas
+ * Clean up the code a little and lint it. (Lint complains about all
+ * the regs used in the asm, but I'm not going to "fix" this.)
+ *
+ * Revision 1.3 84/07/05 02:06:54 thomas
+ * Minor fixes.
+ *
+ * Revision 1.2 84/07/05 00:27:27 thomas
+ * Add variable bit length output.
+ *
+ */
+static char rcs_ident[] = "Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release";
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef notdef
+#include <sys/ioctl.h>
+#endif
+
+#define ARGVAL() (*++(*argv) || (--argc && *++argv))
+
+int n_bits; /* number of bits/code */
+int maxbits = BITS; /* user settable max # bits/code */
+code_int maxcode; /* maximum code, given n_bits */
+code_int maxmaxcode = 1 << BITS; /* should NEVER generate this code */
+#ifdef COMPATIBLE /* But wrong! */
+# define MAXCODE(n_bits) (1 << (n_bits) - 1)
+#else
+# define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
+#endif /* COMPATIBLE */
+
+#ifdef XENIX_16
+count_int htab0[8192];
+count_int htab1[8192];
+count_int htab2[8192];
+count_int htab3[8192];
+count_int htab4[8192];
+count_int htab5[8192];
+count_int htab6[8192];
+count_int htab7[8192];
+count_int htab8[HSIZE-65536];
+count_int * htab[9] = {
+ htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8 };
+
+#define htabof(i) (htab[(i) >> 13][(i) & 0x1fff])
+unsigned short code0tab[16384];
+unsigned short code1tab[16384];
+unsigned short code2tab[16384];
+unsigned short code3tab[16384];
+unsigned short code4tab[16384];
+unsigned short * codetab[5] = {
+ code0tab, code1tab, code2tab, code3tab, code4tab };
+
+#define codetabof(i) (codetab[(i) >> 14][(i) & 0x3fff])
+
+#else /* Normal machine */
+
+#ifdef sel /* gould base register braindamage */
+/*NOBASE*/
+count_int htab [HSIZE];
+unsigned short codetab [HSIZE];
+/*NOBASE*/
+#else
+count_int htab [HSIZE];
+unsigned short codetab [HSIZE];
+#endif /* sel */
+
+#define htabof(i) htab[i]
+#define codetabof(i) codetab[i]
+#endif /* XENIX_16 */
+code_int hsize = HSIZE; /* for dynamic table sizing */
+count_int fsize;
+
+/*
+ * To save much memory, we overlay the table used by compress() with those
+ * used by decompress(). The tab_prefix table is the same size and type
+ * as the codetab. The tab_suffix table needs 2**BITS characters. We
+ * get this from the beginning of htab. The output stack uses the rest
+ * of htab, and contains characters. There is plenty of room for any
+ * possible stack (stack used to be 8000 characters).
+ */
+
+#define tab_prefixof(i) codetabof(i)
+#ifdef XENIX_16
+# define tab_suffixof(i) ((char_type *)htab[(i)>>15])[(i) & 0x7fff]
+# define de_stack ((char_type *)(htab2))
+#else /* Normal machine */
+# define tab_suffixof(i) ((char_type *)(htab))[i]
+# define de_stack ((char_type *)&tab_suffixof(1<<BITS))
+#endif /* XENIX_16 */
+
+code_int free_ent = 0; /* first unused entry */
+int exit_stat = 0; /* per-file status */
+int perm_stat = 0; /* permanent status */
+
+code_int getcode();
+
+Usage() {
+#ifdef DEBUG
+fprintf(stderr,"Usage: compress [-dDVfc] [-b maxbits] [file ...]\n");
+}
+int debug = 0;
+#else
+fprintf(stderr,"Usage: compress [-fvc] [-b maxbits] [file ...]\n");
+}
+#endif /* DEBUG */
+int nomagic = 0; /* Use a 3-byte magic number header, unless old file */
+int zcat_flg = 0; /* Write output on stdout, suppress messages */
+int precious = 1; /* Don't unlink output file on interrupt */
+int quiet = 1; /* don't tell me about compression */
+
+/*
+ * block compression parameters -- after all codes are used up,
+ * and compression rate changes, start over.
+ */
+int block_compress = BLOCK_MASK;
+int clear_flg = 0;
+long int ratio = 0;
+#define CHECK_GAP 10000 /* ratio check interval */
+count_int checkpoint = CHECK_GAP;
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define FIRST 257 /* first free entry */
+#define CLEAR 256 /* table clear output code */
+
+int force = 0;
+char ofname [100];
+#ifdef DEBUG
+int verbose = 0;
+#endif /* DEBUG */
+int (*oldint)();
+int bgnd_flag;
+
+int do_decomp = 0;
+
+/*****************************************************************
+ * TAG( main )
+ *
+ * Algorithm from "A Technique for High Performance Data Compression",
+ * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
+ *
+ * Usage: compress [-dfvc] [-b bits] [file ...]
+ * Inputs:
+ * -d: If given, decompression is done instead.
+ *
+ * -c: Write output on stdout, don't remove original.
+ *
+ * -b: Parameter limits the max number of bits/code.
+ *
+ * -f: Forces output file to be generated, even if one already
+ * exists, and even if no space is saved by compressing.
+ * If -f is not used, the user will be prompted if stdin is
+ * a tty, otherwise, the output file will not be overwritten.
+ *
+ * -v: Write compression statistics
+ *
+ * file ...: Files to be compressed. If none specified, stdin
+ * is used.
+ * Outputs:
+ * file.Z: Compressed form of file with same mode, owner, and utimes
+ * or stdout (if stdin used as input)
+ *
+ * Assumptions:
+ * When filenames are given, replaces with the compressed version
+ * (.Z suffix) only if the file decreases in size.
+ * Algorithm:
+ * Modified Lempel-Ziv method (LZW). Basically finds common
+ * substrings and replaces them with a variable size code. This is
+ * deterministic, and can be done on the fly. Thus, the decompression
+ * procedure needs no input table, but tracks the way the table was built.
+ */
+
+main( argc, argv )
+register int argc; char **argv;
+{
+ int overwrite = 0; /* Do not overwrite unless given -f flag */
+ char tempname[100];
+ char **filelist, **fileptr;
+ char *cp, *rindex(), *malloc();
+ struct stat statbuf;
+ extern onintr(), oops();
+
+ /* This bg check only works for sh. */
+ if ( (oldint = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
+ signal ( SIGINT, onintr );
+ signal ( SIGSEGV, oops );
+ }
+ bgnd_flag = oldint != SIG_DFL;
+#ifdef notdef /* This works for csh but we don't want it. */
+ { int tgrp;
+ if (bgnd_flag == 0 && ioctl(2, TIOCGPGRP, (char *)&tgrp) == 0 &&
+ getpgrp(0) != tgrp)
+ bgnd_flag = 1;
+ }
+#endif
+
+#ifdef COMPATIBLE
+ nomagic = 1; /* Original didn't have a magic number */
+#endif /* COMPATIBLE */
+
+ filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
+ *filelist = NULL;
+
+ if((cp = rindex(argv[0], '/')) != 0) {
+ cp++;
+ } else {
+ cp = argv[0];
+ }
+ if(strcmp(cp, "uncompress") == 0) {
+ do_decomp = 1;
+ } else if(strcmp(cp, "zcat") == 0) {
+ do_decomp = 1;
+ zcat_flg = 1;
+ }
+
+#if defined(BSD4_2) && !defined(__EMX__)
+ /* 4.2BSD dependent - take it out if not */
+ setlinebuf( stderr );
+#endif /* BSD4_2 */
+
+ /* Argument Processing
+ * All flags are optional.
+ * -D => debug
+ * -V => print Version; debug verbose
+ * -d => do_decomp
+ * -v => unquiet
+ * -f => force overwrite of output file
+ * -n => no header: useful to uncompress old files
+ * -b maxbits => maxbits. If -b is specified, then maxbits MUST be
+ * given also.
+ * -c => cat all output to stdout
+ * -C => generate output compatible with compress 2.0.
+ * if a string is left, must be an input filename.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (**argv == '-') { /* A flag argument */
+ while (*++(*argv)) { /* Process all flags in this arg */
+ switch (**argv) {
+#ifdef DEBUG
+ case 'D':
+ debug = 1;
+ break;
+ case 'V':
+ verbose = 1;
+ version();
+ break;
+#else
+ case 'V':
+ version();
+ break;
+#endif /* DEBUG */
+ case 'v':
+ quiet = 0;
+ break;
+ case 'd':
+ do_decomp = 1;
+ break;
+ case 'f':
+ case 'F':
+ overwrite = 1;
+ force = 1;
+ break;
+ case 'n':
+ nomagic = 1;
+ break;
+ case 'C':
+ block_compress = 0;
+ break;
+ case 'b':
+ if (!ARGVAL()) {
+ fprintf(stderr, "Missing maxbits\n");
+ Usage();
+ exit(1);
+ }
+ maxbits = atoi(*argv);
+ goto nextarg;
+ case 'c':
+ zcat_flg = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ default:
+ fprintf(stderr, "Unknown flag: '%c'; ", **argv);
+ Usage();
+ exit(1);
+ }
+ }
+ }
+ else { /* Input file name */
+ *fileptr++ = *argv; /* Build input file list */
+ *fileptr = NULL;
+ /* process nextarg; */
+ }
+ nextarg: continue;
+ }
+
+ if(maxbits < INIT_BITS) maxbits = INIT_BITS;
+ if (maxbits > BITS) maxbits = BITS;
+ maxmaxcode = 1 << maxbits;
+
+ if (*filelist != NULL) {
+ for (fileptr = filelist; *fileptr; fileptr++) {
+ exit_stat = 0;
+ if (do_decomp) { /* DECOMPRESSION */
+ /* Check for .Z suffix */
+ if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) {
+ /* No .Z: tack one on */
+ strcpy(tempname, *fileptr);
+ strcat(tempname, ".Z");
+ *fileptr = tempname;
+ }
+ /* Open input file */
+ if ((freopen(*fileptr, "r", stdin)) == NULL) {
+ perror(*fileptr);
+ perm_stat = 1;
+ continue;
+ }
+ /* Check the magic number */
+ if (nomagic == 0) {
+ if ((getchar() != (magic_header[0] & 0xFF))
+ || (getchar() != (magic_header[1] & 0xFF))) {
+ fprintf(stderr, "%s: not in compressed format\n",
+ *fileptr);
+ continue;
+ }
+ maxbits = getchar(); /* set -b from file */
+ block_compress = maxbits & BLOCK_MASK;
+ maxbits &= BIT_MASK;
+ maxmaxcode = 1 << maxbits;
+ if(maxbits > BITS) {
+ fprintf(stderr,
+ "%s: compressed with %d bits, can only handle %d bits\n",
+ *fileptr, maxbits, BITS);
+ continue;
+ }
+ }
+ /* Generate output filename */
+ strcpy(ofname, *fileptr);
+ ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */
+ } else { /* COMPRESSION */
+ if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) {
+ fprintf(stderr, "%s: already has .Z suffix -- no change\n",
+ *fileptr);
+ continue;
+ }
+ /* Open input file */
+ if ((freopen(*fileptr, "r", stdin)) == NULL) {
+ perror(*fileptr);
+ perm_stat = 1;
+ continue;
+ }
+ stat ( *fileptr, &statbuf );
+ fsize = (long) statbuf.st_size;
+ /*
+ * tune hash table size for small files -- ad hoc,
+ * but the sizes match earlier #defines, which
+ * serve as upper bounds on the number of output codes.
+ */
+ hsize = HSIZE;
+ if ( fsize < (1 << 12) )
+ hsize = min ( 5003, HSIZE );
+ else if ( fsize < (1 << 13) )
+ hsize = min ( 9001, HSIZE );
+ else if ( fsize < (1 << 14) )
+ hsize = min ( 18013, HSIZE );
+ else if ( fsize < (1 << 15) )
+ hsize = min ( 35023, HSIZE );
+ else if ( fsize < 47000 )
+ hsize = min ( 50021, HSIZE );
+
+ /* Generate output filename */
+ strcpy(ofname, *fileptr);
+#ifndef BSD4_2 /* Short filenames */
+ if ((cp=rindex(ofname,'/')) != NULL) cp++;
+ else cp = ofname;
+ if (strlen(cp) > 12) {
+ fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
+ continue;
+ }
+#endif /* BSD4_2 Long filenames allowed */
+ strcat(ofname, ".Z");
+ }
+ /* Check for overwrite of existing file */
+ if (overwrite == 0 && zcat_flg == 0) {
+ if (stat(ofname, &statbuf) == 0) {
+ char response[2];
+ response[0] = 'n';
+ fprintf(stderr, "%s already exists;", ofname);
+ if (bgnd_flag == 0 && isatty(2)) {
+ fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
+ ofname);
+ fflush(stderr);
+ read(2, response, 2);
+ while (response[1] != '\n') {
+ if (read(2, response+1, 1) < 0) { /* Ack! */
+ perror("stderr"); break;
+ }
+ }
+ }
+ if (response[0] != 'y') {
+ fprintf(stderr, "\tnot overwritten\n");
+ continue;
+ }
+ }
+ }
+ if(zcat_flg == 0) { /* Open output file */
+ if (freopen(ofname, "w", stdout) == NULL) {
+ perror(ofname);
+ perm_stat = 1;
+ continue;
+ }
+ precious = 0;
+ if(!quiet)
+ fprintf(stderr, "%s: ", *fileptr);
+ }
+
+#ifdef __EMX__
+ /* force setting binary mode */
+ _fsetmode(stdin,"b");
+ _fsetmode(stdout,"b");
+#endif
+
+ /* Actually do the compression/decompression */
+ if (do_decomp == 0) compress();
+#ifndef DEBUG
+ else decompress();
+#else
+ else if (debug == 0) decompress();
+ else printcodes();
+ if (verbose) dump_tab();
+#endif /* DEBUG */
+ if(zcat_flg == 0) {
+ copystat(*fileptr, ofname); /* Copy stats */
+ precious = 1;
+ if((exit_stat == 1) || (!quiet))
+ putc('\n', stderr);
+ }
+ }
+ } else { /* Standard input */
+#ifdef __EMX__
+ /* force setting binary mode */
+ _fsetmode(stdin,"b");
+ _fsetmode(stdout,"b");
+#endif
+ if (do_decomp == 0) {
+ compress();
+#ifdef DEBUG
+ if(verbose) dump_tab();
+#endif /* DEBUG */
+ if(!quiet)
+ putc('\n', stderr);
+ } else {
+ /* Check the magic number */
+ if (nomagic == 0) {
+ if ((getchar()!=(magic_header[0] & 0xFF))
+ || (getchar()!=(magic_header[1] & 0xFF))) {
+ fprintf(stderr, "stdin: not in compressed format\n");
+ exit(1);
+ }
+ maxbits = getchar(); /* set -b from file */
+ block_compress = maxbits & BLOCK_MASK;
+ maxbits &= BIT_MASK;
+ maxmaxcode = 1 << maxbits;
+ fsize = 100000; /* assume stdin large for USERMEM */
+ if(maxbits > BITS) {
+ fprintf(stderr,
+ "stdin: compressed with %d bits, can only handle %d bits\n",
+ maxbits, BITS);
+ exit(1);
+ }
+ }
+#ifndef DEBUG
+ decompress();
+#else
+ if (debug == 0) decompress();
+ else printcodes();
+ if (verbose) dump_tab();
+#endif /* DEBUG */
+ }
+ }
+ exit(perm_stat ? perm_stat : exit_stat);
+}
+
+static int offset;
+long int in_count = 1; /* length of input */
+long int bytes_out; /* length of compressed output */
+long int out_count = 0; /* # of codes output (for debugging) */
+
+/*
+ * compress stdin to stdout
+ *
+ * Algorithm: use open addressing double hashing (no chaining) on the
+ * prefix code / next character combination. We do a variant of Knuth's
+ * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ * secondary probe. Here, the modular division first probe is gives way
+ * to a faster exclusive-or manipulation. Also do block compression with
+ * an adaptive reset, whereby the code table is cleared when the compression
+ * ratio decreases, but after the table fills. The variable-length output
+ * codes are re-sized at this point, and a special CLEAR code is generated
+ * for the decompressor. Late addition: construct the table according to
+ * file size for noticeable speed improvement on small files. Please direct
+ * questions about this implementation to ames!jaw.
+ */
+
+compress() {
+ register long fcode;
+ register code_int i = 0;
+ register int c;
+ register code_int ent;
+#ifdef XENIX_16
+ register code_int disp;
+#else /* Normal machine */
+ register int disp;
+#endif
+ register code_int hsize_reg;
+ register int hshift;
+
+#ifndef COMPATIBLE
+ if (nomagic == 0) {
+ putchar(magic_header[0]); putchar(magic_header[1]);
+ putchar((char)(maxbits | block_compress));
+ if(ferror(stdout))
+ writeerr();
+ }
+#endif /* COMPATIBLE */
+
+ offset = 0;
+ bytes_out = 3; /* includes 3-byte header mojo */
+ out_count = 0;
+ clear_flg = 0;
+ ratio = 0;
+ in_count = 1;
+ checkpoint = CHECK_GAP;
+ maxcode = MAXCODE(n_bits = INIT_BITS);
+ free_ent = ((block_compress) ? FIRST : 256 );
+
+ ent = getchar ();
+
+ hshift = 0;
+ for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
+ hshift++;
+ hshift = 8 - hshift; /* set hash code range bound */
+
+ hsize_reg = hsize;
+ cl_hash( (count_int) hsize_reg); /* clear hash table */
+
+#ifdef SIGNED_COMPARE_SLOW
+ while ( (c = getchar()) != (unsigned) EOF ) {
+#else
+ while ( (c = getchar()) != EOF ) {
+#endif
+ in_count++;
+ fcode = (long) (((long) c << maxbits) + ent);
+ i = ((c << hshift) ^ ent); /* xor hashing */
+
+ if ( htabof (i) == fcode ) {
+ ent = codetabof (i);
+ continue;
+ } else if ( (long)htabof (i) < 0 ) /* empty slot */
+ goto nomatch;
+ disp = hsize_reg - i; /* secondary hash (after G. Knott) */
+ if ( i == 0 )
+ disp = 1;
+probe:
+ if ( (i -= disp) < 0 )
+ i += hsize_reg;
+
+ if ( htabof (i) == fcode ) {
+ ent = codetabof (i);
+ continue;
+ }
+ if ( (long)htabof (i) > 0 )
+ goto probe;
+nomatch:
+ output ( (code_int) ent );
+ out_count++;
+ ent = c;
+#ifdef SIGNED_COMPARE_SLOW
+ if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
+#else
+ if ( free_ent < maxmaxcode ) {
+#endif
+ codetabof (i) = free_ent++; /* code -> hashtable */
+ htabof (i) = fcode;
+ }
+ else if ( (count_int)in_count >= checkpoint && block_compress )
+ cl_block ();
+ }
+ /*
+ * Put out the final code.
+ */
+ output( (code_int)ent );
+ out_count++;
+ output( (code_int)-1 );
+
+ /*
+ * Print out stats on stderr
+ */
+ if(zcat_flg == 0 && !quiet) {
+#ifdef DEBUG
+ fprintf( stderr,
+ "%ld chars in, %ld codes (%ld bytes) out, compression factor: ",
+ in_count, out_count, bytes_out );
+ prratio( stderr, in_count, bytes_out );
+ fprintf( stderr, "\n");
+ fprintf( stderr, "\tCompression as in compact: " );
+ prratio( stderr, in_count-bytes_out, in_count );
+ fprintf( stderr, "\n");
+ fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n",
+ free_ent - 1, n_bits );
+#else /* !DEBUG */
+ fprintf( stderr, "Compression: " );
+ prratio( stderr, in_count-bytes_out, in_count );
+#endif /* DEBUG */
+ }
+ if(bytes_out > in_count) /* exit(2) if no savings */
+ exit_stat = 2;
+ return;
+}
+
+/*****************************************************************
+ * TAG( output )
+ *
+ * Output the given code.
+ * Inputs:
+ * code: A n_bits-bit integer. If == -1, then EOF. This assumes
+ * that n_bits =< (long)wordsize - 1.
+ * Outputs:
+ * Outputs code to the file.
+ * Assumptions:
+ * Chars are 8 bits long.
+ * Algorithm:
+ * Maintain a BITS character long buffer (so that 8 codes will
+ * fit in it exactly). Use the VAX insv instruction to insert each
+ * code in turn. When the buffer fills up empty it and start over.
+ */
+
+static char buf[BITS];
+
+#ifndef vax
+char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
+char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
+#endif /* vax */
+
+output( code )
+code_int code;
+{
+#ifdef DEBUG
+ static int col = 0;
+#endif /* DEBUG */
+
+ /*
+ * On the VAX, it is important to have the register declarations
+ * in exactly the order given, or the asm will break.
+ */
+ register int r_off = offset, bits= n_bits;
+ register char * bp = buf;
+
+#ifdef DEBUG
+ if ( verbose )
+ fprintf( stderr, "%5d%c", code,
+ (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
+#endif /* DEBUG */
+ if ( code >= 0 ) {
+#ifdef vax
+ /* VAX DEPENDENT!! Implementation on other machines is below.
+ *
+ * Translation: Insert BITS bits from the argument starting at
+ * offset bits from the beginning of buf.
+ */
+ 0; /* Work around for pcc -O bug with asm and if stmt */
+ asm( "insv 4(ap),r11,r10,(r9)" );
+#else /* not a vax */
+/*
+ * byte/bit numbering on the VAX is simulated by the following code
+ */
+ /*
+ * Get to the first byte.
+ */
+ bp += (r_off >> 3);
+ r_off &= 7;
+ /*
+ * Since code is always >= 8 bits, only need to mask the first
+ * hunk on the left.
+ */
+ *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
+ bp++;
+ bits -= (8 - r_off);
+ code >>= 8 - r_off;
+ /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+ if ( bits >= 8 ) {
+ *bp++ = code;
+ code >>= 8;
+ bits -= 8;
+ }
+ /* Last bits. */
+ if(bits)
+ *bp = code;
+#endif /* vax */
+ offset += n_bits;
+ if ( offset == (n_bits << 3) ) {
+ bp = buf;
+ bits = n_bits;
+ bytes_out += bits;
+ do
+ putchar(*bp++);
+ while(--bits);
+ offset = 0;
+ }
+
+ /*
+ * If the next entry is going to be too big for the code size,
+ * then increase it, if possible.
+ */
+ if ( free_ent > maxcode || (clear_flg > 0))
+ {
+ /*
+ * Write the whole buffer, because the input side won't
+ * discover the size increase until after it has read it.
+ */
+ if ( offset > 0 ) {
+ if( fwrite( buf, 1, n_bits, stdout ) != n_bits)
+ writeerr();
+ bytes_out += n_bits;
+ }
+ offset = 0;
+
+ if ( clear_flg ) {
+ maxcode = MAXCODE (n_bits = INIT_BITS);
+ clear_flg = 0;
+ }
+ else {
+ n_bits++;
+ if ( n_bits == maxbits )
+ maxcode = maxmaxcode;
+ else
+ maxcode = MAXCODE(n_bits);
+ }
+#ifdef DEBUG
+ if ( debug ) {
+ fprintf( stderr, "\nChange to %d bits\n", n_bits );
+ col = 0;
+ }
+#endif /* DEBUG */
+ }
+ } else {
+ /*
+ * At EOF, write the rest of the buffer.
+ */
+ if ( offset > 0 )
+ fwrite( buf, 1, (offset + 7) / 8, stdout );
+ bytes_out += (offset + 7) / 8;
+ offset = 0;
+ fflush( stdout );
+#ifdef DEBUG
+ if ( verbose )
+ fprintf( stderr, "\n" );
+#endif /* DEBUG */
+ if( ferror( stdout ) )
+ writeerr();
+ }
+}
+
+/*
+ * Decompress stdin to stdout. This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file. The tables used herein are shared
+ * with those of the compress() routine. See the definitions above.
+ */
+
+decompress() {
+ register char_type *stackp;
+ register int finchar;
+ register code_int code, oldcode, incode;
+
+ /*
+ * As above, initialize the first 256 entries in the table.
+ */
+ maxcode = MAXCODE(n_bits = INIT_BITS);
+ for ( code = 255; code >= 0; code-- ) {
+ tab_prefixof(code) = 0;
+ tab_suffixof(code) = (char_type)code;
+ }
+ free_ent = ((block_compress) ? FIRST : 256 );
+
+ finchar = oldcode = getcode();
+ if(oldcode == -1) /* EOF already? */
+ return; /* Get out of here */
+ putchar( (char)finchar ); /* first code must be 8 bits = char */
+ if(ferror(stdout)) /* Crash if can't write */
+ writeerr();
+ stackp = de_stack;
+
+ while ( (code = getcode()) > -1 ) {
+
+ if ( (code == CLEAR) && block_compress ) {
+ for ( code = 255; code >= 0; code-- )
+ tab_prefixof(code) = 0;
+ clear_flg = 1;
+ free_ent = FIRST - 1;
+ if ( (code = getcode ()) == -1 ) /* O, untimely death! */
+ break;
+ }
+ incode = code;
+ /*
+ * Special case for KwKwK string.
+ */
+ if ( code >= free_ent ) {
+ *stackp++ = finchar;
+ code = oldcode;
+ }
+
+ /*
+ * Generate output characters in reverse order
+ */
+#ifdef SIGNED_COMPARE_SLOW
+ while ( ((unsigned long)code) >= ((unsigned long)256) ) {
+#else
+ while ( code >= 256 ) {
+#endif
+ *stackp++ = tab_suffixof(code);
+ code = tab_prefixof(code);
+ }
+ *stackp++ = finchar = tab_suffixof(code);
+
+ /*
+ * And put them out in forward order
+ */
+ do
+ putchar ( *--stackp );
+ while ( stackp > de_stack );
+
+ /*
+ * Generate the new entry.
+ */
+ if ( (code=free_ent) < maxmaxcode ) {
+ tab_prefixof(code) = (unsigned short)oldcode;
+ tab_suffixof(code) = finchar;
+ free_ent = code+1;
+ }
+ /*
+ * Remember previous code.
+ */
+ oldcode = incode;
+ }
+ fflush( stdout );
+ if(ferror(stdout))
+ writeerr();
+}
+
+/*****************************************************************
+ * TAG( getcode )
+ *
+ * Read one code from the standard input. If EOF, return -1.
+ * Inputs:
+ * stdin
+ * Outputs:
+ * code or -1 is returned.
+ */
+
+code_int
+getcode() {
+ /*
+ * On the VAX, it is important to have the register declarations
+ * in exactly the order given, or the asm will break.
+ */
+ register code_int code;
+ static int offset = 0, size = 0;
+ static char_type buf[BITS];
+ register int r_off, bits;
+ register char_type *bp = buf;
+
+ if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
+ /*
+ * If the next entry will be too big for the current code
+ * size, then we must increase the size. This implies reading
+ * a new buffer full, too.
+ */
+ if ( free_ent > maxcode ) {
+ n_bits++;
+ if ( n_bits == maxbits )
+ maxcode = maxmaxcode; /* won't get any bigger now */
+ else
+ maxcode = MAXCODE(n_bits);
+ }
+ if ( clear_flg > 0) {
+ maxcode = MAXCODE (n_bits = INIT_BITS);
+ clear_flg = 0;
+ }
+ size = fread( buf, 1, n_bits, stdin );
+ if ( size <= 0 )
+ return -1; /* end of file */
+ offset = 0;
+ /* Round size down to integral number of codes */
+ size = (size << 3) - (n_bits - 1);
+ }
+ r_off = offset;
+ bits = n_bits;
+#ifdef vax
+ asm( "extzv r10,r9,(r8),r11" );
+#else /* not a vax */
+ /*
+ * Get to the first byte.
+ */
+ bp += (r_off >> 3);
+ r_off &= 7;
+ /* Get first part (low order bits) */
+#ifdef NO_UCHAR
+ code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
+#else
+ code = (*bp++ >> r_off);
+#endif /* NO_UCHAR */
+ bits -= (8 - r_off);
+ r_off = 8 - r_off; /* now, offset into code word */
+ /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+ if ( bits >= 8 ) {
+#ifdef NO_UCHAR
+ code |= (*bp++ & 0xff) << r_off;
+#else
+ code |= *bp++ << r_off;
+#endif /* NO_UCHAR */
+ r_off += 8;
+ bits -= 8;
+ }
+ /* high order bits. */
+ code |= (*bp & rmask[bits]) << r_off;
+#endif /* vax */
+ offset += n_bits;
+
+ return code;
+}
+
+char *
+rindex(s, c) /* For those who don't have it in libc.a */
+register char *s, c;
+{
+ char *p;
+ for (p = NULL; *s; s++)
+ if (*s == c)
+ p = s;
+ return(p);
+}
+
+#ifdef DEBUG
+printcodes()
+{
+ /*
+ * Just print out codes from input file. For debugging.
+ */
+ code_int code;
+ int col = 0, bits;
+
+ bits = n_bits = INIT_BITS;
+ maxcode = MAXCODE(n_bits);
+ free_ent = ((block_compress) ? FIRST : 256 );
+ while ( ( code = getcode() ) >= 0 ) {
+ if ( (code == CLEAR) && block_compress ) {
+ free_ent = FIRST - 1;
+ clear_flg = 1;
+ }
+ else if ( free_ent < maxmaxcode )
+ free_ent++;
+ if ( bits != n_bits ) {
+ fprintf(stderr, "\nChange to %d bits\n", n_bits );
+ bits = n_bits;
+ col = 0;
+ }
+ fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' );
+ }
+ putc( '\n', stderr );
+ exit( 0 );
+}
+
+code_int sorttab[1<<BITS]; /* sorted pointers into htab */
+
+dump_tab() /* dump string table */
+{
+ register int i, first;
+ register ent;
+#define STACK_SIZE 15000
+ int stack_top = STACK_SIZE;
+ register c;
+
+ if(do_decomp == 0) { /* compressing */
+ register int flag = 1;
+
+ for(i=0; i<hsize; i++) { /* build sort pointers */
+ if((long)htabof(i) >= 0) {
+ sorttab[codetabof(i)] = i;
+ }
+ }
+ first = block_compress ? FIRST : 256;
+ for(i = first; i < free_ent; i++) {
+ fprintf(stderr, "%5d: \"", i);
+ de_stack[--stack_top] = '\n';
+ de_stack[--stack_top] = '"';
+ stack_top = in_stack((htabof(sorttab[i])>>maxbits)&0xff,
+ stack_top);
+ for(ent=htabof(sorttab[i]) & ((1<<maxbits)-1);
+ ent > 256;
+ ent=htabof(sorttab[ent]) & ((1<<maxbits)-1)) {
+ stack_top = in_stack(htabof(sorttab[ent]) >> maxbits,
+ stack_top);
+ }
+ stack_top = in_stack(ent, stack_top);
+ fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr);
+ stack_top = STACK_SIZE;
+ }
+ } else if(!debug) { /* decompressing */
+
+ for ( i = 0; i < free_ent; i++ ) {
+ ent = i;
+ c = tab_suffixof(ent);
+ if ( isascii(c) && isprint(c) )
+ fprintf( stderr, "%5d: %5d/'%c' \"",
+ ent, tab_prefixof(ent), c );
+ else
+ fprintf( stderr, "%5d: %5d/\\%03o \"",
+ ent, tab_prefixof(ent), c );
+ de_stack[--stack_top] = '\n';
+ de_stack[--stack_top] = '"';
+ for ( ; ent != NULL;
+ ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) {
+ stack_top = in_stack(tab_suffixof(ent), stack_top);
+ }
+ fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr );
+ stack_top = STACK_SIZE;
+ }
+ }
+}
+
+int
+in_stack(c, stack_top)
+ register c, stack_top;
+{
+ if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) {
+ de_stack[--stack_top] = c;
+ } else {
+ switch( c ) {
+ case '\n': de_stack[--stack_top] = 'n'; break;
+ case '\t': de_stack[--stack_top] = 't'; break;
+ case '\b': de_stack[--stack_top] = 'b'; break;
+ case '\f': de_stack[--stack_top] = 'f'; break;
+ case '\r': de_stack[--stack_top] = 'r'; break;
+ case '\\': de_stack[--stack_top] = '\\'; break;
+ default:
+ de_stack[--stack_top] = '0' + c % 8;
+ de_stack[--stack_top] = '0' + (c / 8) % 8;
+ de_stack[--stack_top] = '0' + c / 64;
+ break;
+ }
+ de_stack[--stack_top] = '\\';
+ }
+ return stack_top;
+}
+#endif /* DEBUG */
+
+writeerr()
+{
+ perror ( ofname );
+ unlink ( ofname );
+ exit ( 1 );
+}
+
+copystat(ifname, ofname)
+char *ifname, *ofname;
+{
+ struct stat statbuf;
+ int mode;
+ time_t timep[2];
+
+ fclose(stdout);
+ if (stat(ifname, &statbuf)) { /* Get stat on input file */
+ perror(ifname);
+ return;
+ }
+ if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) {
+ if(quiet)
+ fprintf(stderr, "%s: ", ifname);
+ fprintf(stderr, " -- not a regular file: unchanged");
+ exit_stat = 1;
+ perm_stat = 1;
+ } else if (statbuf.st_nlink > 1) {
+ if(quiet)
+ fprintf(stderr, "%s: ", ifname);
+ fprintf(stderr, " -- has %d other links: unchanged",
+ statbuf.st_nlink - 1);
+ exit_stat = 1;
+ perm_stat = 1;
+ } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
+ if(!quiet)
+ fprintf(stderr, " -- file unchanged");
+ } else { /* ***** Successful Compression ***** */
+ exit_stat = 0;
+ mode = statbuf.st_mode & 07777;
+ if (chmod(ofname, mode)) /* Copy modes */
+ perror(ofname);
+#ifndef __EMX__
+ chown(ofname, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */
+#endif
+ timep[0] = statbuf.st_atime;
+ timep[1] = statbuf.st_mtime;
+ utime(ofname, timep); /* Update last accessed and modified times */
+#ifdef __EMX__
+ fclose(stdin);
+#endif
+ if (unlink(ifname)) /* Remove input file */
+ perror(ifname);
+ if(!quiet)
+ fprintf(stderr, " -- replaced with %s", ofname);
+ return; /* Successful return */
+ }
+
+ /* Unsuccessful return -- one of the tests failed */
+ if (unlink(ofname))
+ perror(ofname);
+}
+
+onintr ( )
+{
+ if (!precious)
+ unlink ( ofname );
+ exit ( 1 );
+}
+
+oops ( ) /* wild pointer -- assume bad input */
+{
+ if ( do_decomp )
+ fprintf ( stderr, "uncompress: corrupt input\n" );
+ unlink ( ofname );
+ exit ( 1 );
+}
+
+cl_block () /* table clear for block compress */
+{
+ register long int rat;
+
+ checkpoint = in_count + CHECK_GAP;
+#ifdef DEBUG
+ if ( debug ) {
+ fprintf ( stderr, "count: %ld, ratio: ", in_count );
+ prratio ( stderr, in_count, bytes_out );
+ fprintf ( stderr, "\n");
+ }
+#endif /* DEBUG */
+
+ if(in_count > 0x007fffff) { /* shift will overflow */
+ rat = bytes_out >> 8;
+ if(rat == 0) { /* Don't divide by zero */
+ rat = 0x7fffffff;
+ } else {
+ rat = in_count / rat;
+ }
+ } else {
+ rat = (in_count << 8) / bytes_out; /* 8 fractional bits */
+ }
+ if ( rat > ratio ) {
+ ratio = rat;
+ } else {
+ ratio = 0;
+#ifdef DEBUG
+ if(verbose)
+ dump_tab(); /* dump string table */
+#endif
+ cl_hash ( (count_int) hsize );
+ free_ent = FIRST;
+ clear_flg = 1;
+ output ( (code_int) CLEAR );
+#ifdef DEBUG
+ if(debug)
+ fprintf ( stderr, "clear\n" );
+#endif /* DEBUG */
+ }
+}
+
+cl_hash(hsize) /* reset code table */
+ register count_int hsize;
+{
+#ifndef XENIX_16 /* Normal machine */
+ register count_int *htab_p = htab+hsize;
+#else
+ register j;
+ register long k = hsize;
+ register count_int *htab_p;
+#endif
+ register long i;
+ register long m1 = -1;
+
+#ifdef XENIX_16
+ for(j=0; j<=8 && k>=0; j++,k-=8192) {
+ i = 8192;
+ if(k < 8192) {
+ i = k;
+ }
+ htab_p = &(htab[j][i]);
+ i -= 16;
+ if(i > 0) {
+#else
+ i = hsize - 16;
+#endif
+ do { /* might use Sys V memset(3) here */
+ *(htab_p-16) = m1;
+ *(htab_p-15) = m1;
+ *(htab_p-14) = m1;
+ *(htab_p-13) = m1;
+ *(htab_p-12) = m1;
+ *(htab_p-11) = m1;
+ *(htab_p-10) = m1;
+ *(htab_p-9) = m1;
+ *(htab_p-8) = m1;
+ *(htab_p-7) = m1;
+ *(htab_p-6) = m1;
+ *(htab_p-5) = m1;
+ *(htab_p-4) = m1;
+ *(htab_p-3) = m1;
+ *(htab_p-2) = m1;
+ *(htab_p-1) = m1;
+ htab_p -= 16;
+ } while ((i -= 16) >= 0);
+#ifdef XENIX_16
+ }
+ }
+#endif
+ for ( i += 16; i > 0; i-- )
+ *--htab_p = m1;
+}
+
+prratio(stream, num, den)
+FILE *stream;
+long int num, den;
+{
+ register int q; /* Doesn't need to be long */
+
+ if(num > 214748L) { /* 2147483647/10000 */
+ q = num / (den / 10000L);
+ } else {
+ q = 10000L * num / den; /* Long calculations, though */
+ }
+ if (q < 0) {
+ putc('-', stream);
+ q = -q;
+ }
+ fprintf(stream, "%d.%02d%%", q / 100, q % 100);
+}
+
+version()
+{
+ fprintf(stderr, "%s, Berkeley 5.10 10/15/88\n", rcs_ident);
+ fprintf(stderr, "Options: ");
+#ifdef vax
+ fprintf(stderr, "vax, ");
+#endif
+#ifdef NO_UCHAR
+ fprintf(stderr, "NO_UCHAR, ");
+#endif
+#ifdef SIGNED_COMPARE_SLOW
+ fprintf(stderr, "SIGNED_COMPARE_SLOW, ");
+#endif
+#ifdef XENIX_16
+ fprintf(stderr, "XENIX_16, ");
+#endif
+#ifdef COMPATIBLE
+ fprintf(stderr, "COMPATIBLE, ");
+#endif
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG, ");
+#endif
+#ifdef BSD4_2
+ fprintf(stderr, "BSD4_2, ");
+#endif
+ fprintf(stderr, "BITS = %d\n", BITS);
+}
diff --git a/xc/util/compress/usermem.sh b/xc/util/compress/usermem.sh
new file mode 100644
index 000000000..e6e976325
--- /dev/null
+++ b/xc/util/compress/usermem.sh
@@ -0,0 +1,94 @@
+#!/bin/sh -
+#
+# Copyright (c) 1985 The Regents of the University of California.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# James A. Woods, derived from original work by Spencer Thomas
+# and Joseph Orost.
+#
+# Redistribution and use in source and binary forms are permitted
+# provided that the above copyright notice and this paragraph are
+# duplicated in all such forms and that any documentation,
+# advertising materials, and other materials related to such
+# distribution and use acknowledge that the software was developed
+# by the University of California, Berkeley. The name of the
+# University may not be used to endorse or promote products derived
+# from this software without specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+# @(#)usermem.sh 5.5 (Berkeley) 10/15/88
+#
+: This shell script snoops around to find the maximum amount of available
+: user memory. These variables need to be set only if there is no
+: /usr/adm/messages. KMEM, UNIX, and CLICKSIZE can be set on the command
+: line, if desired, e.g. UNIX=/unix
+KMEM=/dev/kmem # User needs read access to KMEM
+UNIX=
+# VAX CLICKSIZE=512, UNIX=/vmunix
+# PDP-11 CLICKSIZE=64, UNIX=/unix
+# CADLINC 68000 CLICKSIZE=4096, UNIX=/unix
+# Perkin-Elmer 3205 CLICKSIZE=4096, UNIX=/edition7
+# Perkin-Elmer all others, CLICKSIZE=2048, UNIX=/edition7
+CLICKSIZE=512
+eval $*
+
+if test -n "$UNIX"
+then
+ : User must have specified it already.
+elif test -r /vmunix
+then
+ UNIX=/vmunix
+ CLICKSIZE=512 # Probably VAX
+elif test -r /edition7
+then
+ UNIX=/edition7
+ CLICKSIZE=2048 # Perkin-Elmer: change to 4096 on a 3205
+elif test -r /unix
+then
+ UNIX=/unix # Could be anything
+fi
+
+SIZE=0
+# messages: probably the most transportable
+if test -r /usr/adm/messages -a -s /usr/adm/messages
+then
+ SIZE=`grep avail /usr/adm/messages | sed -n '$s/.*[ ]//p'`
+fi
+
+if test 0$SIZE -le 0 # no SIZE in /usr/adm/messages
+then
+ if test -r $KMEM # Readable KMEM
+ then
+ if test -n "$UNIX"
+ then
+ SIZE=`echo maxmem/D | adb $UNIX $KMEM | sed -n '$s/.*[ ]//p'`
+ if test 0$SIZE -le 0
+ then
+ SIZE=`echo physmem/D | adb $UNIX $KMEM | sed -n '$s/.*[ ]//p'`
+ fi
+ SIZE=`expr 0$SIZE '*' $CLICKSIZE`
+ fi
+ fi
+fi
+
+case $UNIX in
+ /vmunix) # Assume 4.2bsd: check for resource limits
+ MAXSIZE=`csh -c limit | awk 'BEGIN { MAXSIZE = 1000000 }
+/datasize|memoryuse/ && NF == 3 { if ($2 < MAXSIZE) MAXSIZE = $2 }
+END { print MAXSIZE * 1000 }'`
+ if test $MAXSIZE -lt $SIZE
+ then
+ SIZE=$MAXSIZE
+ fi
+ ;;
+esac
+
+if test 0$SIZE -le 0
+then
+ echo 0;exit 1
+else
+ echo $SIZE
+fi
diff --git a/xc/util/memleak/Imakefile b/xc/util/memleak/Imakefile
new file mode 100644
index 000000000..cfab3781b
--- /dev/null
+++ b/xc/util/memleak/Imakefile
@@ -0,0 +1,71 @@
+XCOMM $XConsortium: Imakefile /main/9 1996/09/28 17:19:05 rws $
+XCOMM $XFree86: xc/util/memleak/Imakefile,v 3.2 1996/12/23 07:19:34 dawes Exp $
+#define DoNormalLib YES
+#define DoSharedLib NO
+#define DoDebugLib NO
+#define DoProfileLib NO
+#define IncSubdir X11
+#include <Library.tmpl>
+
+#ifdef MipsArchitecture
+#define TopOfStack 0x7fffbbb0
+#define BottomOfData 0x10000000
+#define HasGetReturnAddress YES
+GRA_OBJS = getretmips.o mipsstack.o
+GRA_SRCS = getretmips.c
+#endif
+
+#ifdef SparcArchitecture
+#define HasGetReturnAddress YES
+#define BottomOfData \&environ
+#ifdef SystemV4
+GRA_OBJS = getretspar.o sparcsolstack.o
+#define TopOfStack 0xeffffc70
+#else
+LOCAL_DEFS = -Datexit=on_exit
+GRA_OBJS = getretspar.o sparcstack.o
+#define TopOfStack 0xf7fffbdc
+#endif
+GRA_SRCS = getretspar.c
+#endif
+
+#ifdef i386BsdArchitecture
+#define HasGetReturnAddress YES
+#define TopOfStack 'GC_get_stack_base()'
+#define BottomOfData \&etext
+GRA_OBJS = getreti386.o stackbottom.o
+GRA_SRCS = getreti386.c stackbottom.c
+#endif
+
+#ifndef HasGetReturnAddress
+#define HasGetReturnAddress NO
+#endif
+
+#if HasGetReturnAddress
+ GRA_DEFS = -DHAS_GET_RETURN_ADDRESS
+#endif
+
+DEFINES = -DTOP_OF_STACK=TopOfStack -DBOTTOM_OF_DATA=BottomOfData\
+ $(GRA_DEFS) $(LOCAL_DEFS)
+
+CDEBUGFLAGS = DebuggableCDebugFlags
+
+SRCS = fmalloc.c $(GRA_SRCS)
+
+OBJS = fmalloc.o $(GRA_OBJS)
+
+LibraryObjectRule()
+
+#if DoNormalLib
+NormalLibraryTarget(memleak,$(OBJS))
+InstallLibrary(memleak,$(USRLIBDIR))
+#endif
+
+InstallNamedProg(find-rtns.sh,find-routines,$(BINDIR))
+
+LintLibraryTarget(memleak,$(SRCS))
+InstallLintLibrary(memleak,$(LINTLIBDIR))
+
+DependTarget()
+
+NormalLintTarget($(SRCS))
diff --git a/xc/util/memleak/README b/xc/util/memleak/README
new file mode 100644
index 000000000..70bbaae6b
--- /dev/null
+++ b/xc/util/memleak/README
@@ -0,0 +1,70 @@
+.\" $XConsortium: README,v 1.3 92/05/15 14:04:04 keith Exp $
+
+This library replaces the C library allocator;
+providing malloc, free, realloc and calloc (sorry, no valloc)
+
+In doing so, it provides extensive memory bug checking, locating:
+
+ Lost memory; memory which has not been freed and which has no
+ references
+
+ In use free memory; memorhy which has been freed and still has
+ references to it.
+
+ Stores to freed memory
+
+ free/realloc with invalid pointers -- if you pass in a pointer to
+ the middle of an allocated block, it will even tell you which one
+
+For each of these errors, a report entry is generated which includes
+the stack backtrace of either the allocation or free (which ever occured
+last) along with the current stack, when relevant.
+
+Unreferenced allocated memory, stores to freed memory and referenced freed
+memory are only caught when CheckMemory is called. It is automatically
+called each time 1m of data has been freed, and is called when the program
+exits (by registering with atexit(3)/on_exit(3)). You can call it whenever
+you want.
+
+Both the X server and font servers call CheckMemory after each reset when
+their respective os/utils.c are compiled -DMEMBUG.
+
+There are a few global variables you can set with the debugger to
+help isolate problems:
+
+ FindLeakWarnMiddlePointers
+ Normally, memleak ignores pointers to the middle of
+ freed memory. These are frequently simply random data
+ which happens to look like a pointer. Turning this
+ on will generate additional messages.
+ FindLeakAllocBreakpoint
+ At each allocation, memleak increments a serial number
+ and stores it in the allocation header. By rerunning
+ the program, you can stop when that piece of memory
+ is going to be allocated. Store the serial number
+ in this global variable and put a debugger breakpoint inside
+ AddActiveBlock at the indicated line.
+ FindLeakFreeBreakpoint
+ Similarly for freeing memory.
+ FindLeakTime
+ The current serial number
+ FindLeakCheckAlways
+ When set, memleak checks the entire memory system after
+ each allocation or free. This is very expensive, but
+ may catch errors not otherwise found until too late.
+
+To include this in your application, simply place libmemleak.a before the
+end of the link line; it will then override the C library allocator.
+
+To port this system to a new machine, you must provide two values, one
+indicating the lowest data address in a program and one indicating the
+highest stack address. In addition, to get return stack traces (which are
+almost essential for debugging), you must provide the function
+getReturnStack. Samples for MIPS and SPARC are included already.
+
+The output from the leak tracer includes only PC values in the stack
+traces. To convert these into useful values, run the output of
+the leak tracer through the find-routines script; after making sure you have
+built the modified version of gdb-4.4 on your machine.
+
+-keith
diff --git a/xc/util/memleak/find-rtns.sh b/xc/util/memleak/find-rtns.sh
new file mode 100755
index 000000000..1d5ee62ee
--- /dev/null
+++ b/xc/util/memleak/find-rtns.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# $TOG: find-rtns.sh /main/2 1998/02/09 11:39:44 kaleb $
+#
+# find-routines - convert leak tracer stack traces into file/lineno traces
+# using a modified version of gdb-4.4
+#
+# Usage: find-routines <program-name> {leak-tracing-output-files}
+#
+TMP1=find-routine.tmp1
+TMP=find-routine.tmp
+trap "rm -f $TMP $TMP1" 0
+OBJ=$1
+shift
+grep 'return stack:' $* |
+ tr ' ' '\012' |
+ grep 0x | sort -u | sed 's;^;x/i ;' |
+ gdb $OBJ | grep '>:' |
+ sed 's/>.*$/>/' | sed 's/(gdb) //' > $TMP1
+
+awk '/^"/ { printf("s;%s;%s line %s %s;\n", $4, $1, $3, $5) }
+/^0/ { printf("s;%s;%s %s;\n", $1, $2, $1);}' $TMP1 > $TMP
+
+awk '/return stack/ { printf ("return stack\n");
+ for (i = 3; i <= NF; i++)
+ printf ("\troutine %s\n", $i); }
+ /^[A-Z]/ { print }' $* |
+ sed -f $TMP
diff --git a/xc/util/memleak/fmalloc.c b/xc/util/memleak/fmalloc.c
new file mode 100644
index 000000000..abad3452a
--- /dev/null
+++ b/xc/util/memleak/fmalloc.c
@@ -0,0 +1,1135 @@
+/*
+ * $TOG: fmalloc.c /main/8 1998/02/09 11:39:50 kaleb $
+ *
+Copyright 1992, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/* $XFree86: xc/util/memleak/fmalloc.c,v 3.4 1998/10/04 08:19:36 dawes Exp $ */
+
+
+/*
+ * Leak tracing allocator -- using C lib malloc/free, tracks
+ * all allocations. When requested, performs a garbage-collection
+ * style mark/sweep on static memory (data and stack), locating
+ * objects referenced therein. Recursively marks objects.
+ * Sweeps through all allocations, warning of possible violations
+ * (unreferenced allocated, referenced freed etc).
+ */
+
+#include <stdio.h>
+
+extern char **environ;
+extern etext;
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifdef X_NOT_POSIX
+#define NO_ATEXIT
+#endif
+
+typedef unsigned long mem;
+
+#ifdef HAS_GET_RETURN_ADDRESS
+#define MAX_RETURN_STACK 16
+#endif
+
+#define MAX_FREED_MEMORY (1*1024*1024)
+
+#define ACTIVE_HEAD_MAGIC 0xff1111ff
+#define ACTIVE_TAIL_MAGIC 0xee2222ee
+#define ACTIVE_DATA_MAGIC 0xdd3333dd
+#define FREED_HEAD_MAGIC 0xcc4444cc
+#define FREED_TAIL_MAGIC 0xbb5555bb
+#define FREED_DATA_MAGIC 0xcc6666cc
+
+/*
+ * the marked fields in each head have two bits - one indicating
+ * references to the head of the block, and one indicating references
+ * to the middle of the block
+ */
+#define UNREFERENCED 0
+#define REFERENCED_HEAD 1
+#define REFERENCED_MIDDLE 2
+
+typedef struct _head {
+ struct _head *left, *right;
+ struct _head *next;
+ int balance;
+#ifdef HAS_GET_RETURN_ADDRESS
+ mem returnStack[MAX_RETURN_STACK];
+#endif
+ mem *from;
+ unsigned long allocTime;
+ unsigned long freeTime;
+ int size;
+ int desiredsize;
+ int actualSize;
+ int marked;
+ int headMagic;
+} HeadRec, *HeadPtr;
+
+typedef struct _tail {
+ int tailMagic;
+#if defined(__alpha) || defined(__alpha__)
+ int tailPad;
+#endif
+} TailRec, *TailPtr;
+
+#define Header(p) ((HeadPtr) (((char *) (p)) - sizeof (HeadRec)))
+#define DataForHead(h) ((mem *) ((h) + 1))
+#define Tailer(p) ((TailPtr) (((char *) (p)) + Header(p)->size))
+#define TailForHead(h) (Tailer(DataForHead(h)))
+#define RoundSize (sizeof (mem))
+#define RoundUp(s) (((s) + RoundSize - 1) & ~(RoundSize - 1))
+#define TotalSize(s) ((s) + sizeof (HeadRec) + sizeof (TailRec))
+#define CheckInit() if (!endOfStaticMemory) endOfStaticMemory = sbrk(0)
+#define BlockContains(h,p) (DataForHead(h) <= (p) && (p) < (mem *) TailForHead(h))
+
+typedef HeadRec tree;
+typedef mem *tree_data;
+
+#define COMPARE_ADDR(a,b,op) (((unsigned) (a)) op ((unsigned) (b)))
+#define COMPARE(a,b,op,s) ((!s) ? \
+ COMPARE_ADDR(a,b,op) :\
+ (((a)->actualSize op (b)->actualSize) || \
+ ((a)->actualSize == (b)->actualSize && \
+ COMPARE_ADDR(a,b,op))))
+
+
+#define LESS_THAN(a,b,s) COMPARE(a,b,<,s)
+#define GREATER_THAN(a,b,s) COMPARE(a,b,>,s)
+
+#define SEARCH(top,result,p) for (result = top; result;) {\
+ if ((mem *) (p) < DataForHead(result)) \
+ result = result->left; \
+ else if ((mem *) TailForHead(result) < (mem *) (p)) \
+ result = result->right; \
+ else \
+ break; \
+}
+
+
+static tree *activeMemory, *freedMemory, *deadMemory;
+
+static mem *endOfStaticMemory;
+static mem *highestAllocatedMemory;
+
+static int freedMemoryTotal;
+static int freedMemoryCount;
+static int activeMemoryTotal;
+static int activeMemoryCount;
+static int deadMemoryTotal;
+
+int FindLeakWarnMiddlePointers = 0;
+unsigned long FindLeakAllocBreakpoint = ~0;
+unsigned long FindLeakFreeBreakpoint = ~0;
+unsigned long FindLeakTime;
+int FindLeakCheckAlways = 0;
+
+static void MarkActiveBlock ();
+static int tree_insert (), tree_delete ();
+void CheckMemory ();
+char *malloc (), *realloc (), *calloc ();
+void free ();
+extern char *sbrk ();
+
+#ifdef HAS_GET_RETURN_ADDRESS
+static void
+PrintReturnStack (m, ra)
+ char *m;
+ mem *ra;
+{
+ int i;
+
+ fprintf (stderr, " %s:", m);
+ for (i = 0; i < MAX_RETURN_STACK && ra[i]; i++)
+ fprintf (stderr, " 0x%lx", ra[i]);
+ fprintf (stderr, "\n");
+}
+#endif
+
+static void
+MemError (s, h, ourRet)
+ char *s;
+ HeadPtr h;
+ int ourRet;
+{
+ mem *ra;
+ int i;
+
+ if (h)
+ {
+ fprintf (stderr, "%s 0x%08lx (size %d) (from 0x%lx)\n",
+ s, DataForHead(h), h->desiredsize, h->from);
+#ifdef HAS_GET_RETURN_ADDRESS
+ PrintReturnStack ("Saved return stack", h->returnStack);
+#endif
+ }
+ else
+ fprintf (stderr, "%s\n", s);
+#ifdef HAS_GET_RETURN_ADDRESS
+ if (ourRet)
+ {
+ mem returnStack[MAX_RETURN_STACK];
+
+ getStackTrace (returnStack, MAX_RETURN_STACK);
+ PrintReturnStack ("Current return stack", returnStack);
+ }
+#endif
+}
+
+static void
+MarkMemoryRegion (low, high)
+ mem *low, *high;
+{
+ mem **start = (mem **) low, **end = (mem **) high;
+ mem *p;
+
+ while (start < end) {
+ p = *start;
+ if (endOfStaticMemory <= p && p < highestAllocatedMemory)
+ MarkActiveBlock (p, (mem *) start);
+ start++;
+ }
+}
+
+static void
+MarkActiveBlock (p, from)
+ mem *p, *from;
+{
+ HeadPtr h;
+ int marked;
+ int oldMarked;
+
+ SEARCH(activeMemory, h, p)
+ if (h) {
+ marked = REFERENCED_HEAD;
+ if (p != DataForHead(h))
+ marked = REFERENCED_MIDDLE;
+ oldMarked = h->marked;
+ if (!(oldMarked & marked))
+ {
+ h->marked |= marked;
+ h->from = from;
+ if (!oldMarked)
+ MarkMemoryRegion (DataForHead(h), (mem *) TailForHead(h));
+ }
+ return;
+ }
+ SEARCH(freedMemory, h, p)
+ if (h)
+ {
+ marked = REFERENCED_HEAD;
+ if (p != DataForHead(h))
+ marked = REFERENCED_MIDDLE;
+ if (!(h->marked & marked))
+ {
+ h->marked |= marked;
+ h->from = from;
+ }
+ return;
+ }
+}
+
+static void
+ClearTree (t)
+ tree *t;
+{
+ if (!t)
+ return;
+ ClearTree (t->left);
+ t->marked = 0;
+ t->from = 0;
+ ClearTree (t->right);
+}
+
+static void
+SweepActiveTree (t)
+ tree *t;
+{
+ if (!t)
+ return;
+ SweepActiveTree (t->left);
+ if (!t->marked)
+ MemError ("Unreferenced allocated", t, FALSE);
+ else if (!(t->marked & REFERENCED_HEAD))
+ MemError ("Referenced allocated middle", t, FALSE);
+ SweepActiveTree (t->right);
+}
+
+/*
+ * run a thread through the tree at the same time
+ * - the thread runs
+ *
+ * root -> left_child ... -> right_child ... -> null
+ */
+
+static tree *
+SweepFreedTree (t)
+ tree *t;
+{
+ tree *left_last, *right_last;
+
+ if (!t)
+ return 0;
+
+ left_last = SweepFreedTree (t->left);
+ if (t->marked)
+ {
+ if (t->marked & REFERENCED_HEAD)
+ MemError ("Referenced freed base", t, FALSE);
+ else if (FindLeakWarnMiddlePointers)
+ MemError ("Referenced freed middle", t, FALSE);
+ }
+ right_last = SweepFreedTree (t->right);
+
+ if (t->left)
+ t->next = t->left;
+ else
+ t->next = t->right;
+ if (left_last)
+ left_last->next = t->right;
+ if (!right_last)
+ right_last = left_last;
+ if (!right_last)
+ right_last = t;
+ return right_last;
+}
+
+static void
+SweepFreedMemory ()
+{
+ tree *t, *n;
+ int count, shouldCount;
+
+ (void) SweepFreedTree (freedMemory);
+ count = 0;
+ shouldCount = freedMemoryCount;
+ for (t = freedMemory; t; t = n) {
+ n = t->next;
+ count++;
+ if (!t->marked)
+ {
+ (void) tree_delete (&freedMemory, t, FALSE);
+ freedMemoryTotal -= t->desiredsize;
+ freedMemoryCount--;
+ tree_insert (&deadMemory, t, TRUE);
+ }
+ }
+ if (count != shouldCount)
+ abort ();
+}
+
+static void
+ValidateTree (head, headMagic, tailMagic, bodyMagic, mesg)
+ tree *head;
+ mem headMagic, tailMagic, bodyMagic;
+ char *mesg;
+{
+ TailPtr tail;
+ mem *p;
+ int i;
+
+ if (!head)
+ return;
+ ValidateTree (head->left, headMagic, tailMagic, bodyMagic, mesg);
+ tail = TailForHead (head);
+ if (head->headMagic != headMagic)
+ MemError (mesg, head, FALSE);
+ if (tail->tailMagic != tailMagic)
+ MemError (mesg, head, FALSE);
+ if (bodyMagic) {
+ i = head->size / sizeof (mem);
+ p = DataForHead(head);
+ while (i--) {
+ if (*p++ != bodyMagic)
+ MemError (mesg, head, FALSE);
+ }
+ }
+ ValidateTree (head->right, headMagic, tailMagic, bodyMagic, mesg);
+}
+
+static void
+ValidateActiveMemory ()
+{
+ ValidateTree (activeMemory, ACTIVE_HEAD_MAGIC, ACTIVE_TAIL_MAGIC,
+ 0, "Store outside of active memory");
+}
+
+static void
+ValidateFreedMemory ()
+{
+ ValidateTree (freedMemory, FREED_HEAD_MAGIC, FREED_TAIL_MAGIC,
+ FREED_DATA_MAGIC, "Store into freed memory");
+}
+
+static void
+AddActiveBlock (h)
+ HeadPtr h;
+{
+ TailPtr t = TailForHead(h);
+ mem *p;
+ int i;
+
+ tree_insert (&activeMemory, h, FALSE);
+ if ((mem *) t > highestAllocatedMemory)
+ highestAllocatedMemory = (mem *) t;
+
+ /*
+ * Breakpoint position - assign FindLeakAllocBreakpoint with
+ * debugger and set a breakpoint in the conditional clause below
+ */
+ if (FindLeakTime == FindLeakAllocBreakpoint)
+ h->headMagic = ACTIVE_HEAD_MAGIC; /* set breakpoint here */
+
+ h->allocTime = FindLeakTime++;
+
+ h->headMagic = ACTIVE_HEAD_MAGIC;
+ t->tailMagic = ACTIVE_TAIL_MAGIC;
+ i = h->size / sizeof (mem);
+ p = DataForHead(h);
+ while (i--)
+ *p++ = ACTIVE_DATA_MAGIC;
+ activeMemoryTotal += h->desiredsize;
+ activeMemoryCount++;
+}
+
+static void
+RemoveActiveBlock (h)
+ HeadPtr h;
+{
+ activeMemoryTotal -= h->desiredsize;
+ activeMemoryCount--;
+ tree_delete (&activeMemory, h, FALSE);
+}
+
+static void
+AddFreedBlock (h)
+ HeadPtr h;
+{
+ TailPtr t = TailForHead(h);
+ int i;
+ mem *p;
+
+ tree_insert (&freedMemory, h, FALSE);
+
+ /*
+ * Breakpoint position - assign FindLeakFreeBreakpoint with
+ * debugger and set a breakpoint in the conditional clause below
+ */
+ if (FindLeakTime == FindLeakFreeBreakpoint)
+ h->headMagic = FREED_HEAD_MAGIC; /* set breakpoint here */
+
+ h->freeTime = FindLeakTime++;
+
+ h->headMagic = FREED_HEAD_MAGIC;
+ t->tailMagic = FREED_TAIL_MAGIC;
+ i = h->size / sizeof (mem);
+ p = DataForHead(h);
+ while (i--)
+ *p++ = FREED_DATA_MAGIC;
+ freedMemoryTotal += h->desiredsize;
+ freedMemoryCount++;
+ /* GC if we've got piles of unused memory */
+ if (freedMemoryTotal - deadMemoryTotal >= MAX_FREED_MEMORY)
+ CheckMemory ();
+}
+
+/*
+ * Entry points:
+ *
+ * CheckMemory () -- Verifies heap
+ * malloc (size) -- Allocates memory
+ * free (old) -- Deallocates memory
+ * realloc (old, size) -- Allocate, copy, free
+ * calloc (num, size_per) -- Allocate and zero
+ */
+
+void
+CheckMemory ()
+{
+ mem foo;
+
+ fprintf (stderr, "\nCheckMemory\n");
+ fprintf (stderr, "%d bytes active memory in %d allocations\n",
+ activeMemoryTotal, activeMemoryCount);
+ fprintf (stderr, "%d bytes freed memory held from %d allocations\n",
+ freedMemoryTotal, freedMemoryCount);
+ ValidateActiveMemory ();
+ ValidateFreedMemory ();
+ ClearTree (activeMemory);
+ ClearTree (freedMemory);
+ MarkMemoryRegion (BOTTOM_OF_DATA, endOfStaticMemory);
+ MarkMemoryRegion (&foo, TOP_OF_STACK);
+ SweepActiveTree (activeMemory);
+ SweepFreedMemory ();
+ fprintf (stderr, "%d bytes freed memory still held from %d allocations\n",
+ freedMemoryTotal, freedMemoryCount);
+ deadMemoryTotal = freedMemoryTotal;
+ fprintf (stderr, "CheckMemory done\n");
+}
+
+/*
+ * Allocator interface -- malloc and free (others in separate files)
+ */
+
+#define CORE_CHUNK 16384
+
+static char *core;
+static unsigned core_left;
+static unsigned total_core_used;
+
+static char *
+morecore (size)
+ unsigned size;
+{
+ unsigned alloc_size;
+ char *alloc, *newcore;
+
+ if (core_left < size)
+ {
+ alloc_size = (size + CORE_CHUNK - 1) & ~(CORE_CHUNK-1);
+ newcore = sbrk (alloc_size);
+ if (((int) newcore) == -1)
+ return 0;
+ core = newcore;
+ core_left = alloc_size;
+ total_core_used += alloc_size;
+ }
+ alloc = core;
+ core += size;
+ core_left -= size;
+ return alloc;
+}
+
+char *
+malloc (desiredsize)
+ unsigned desiredsize;
+{
+ char *ret;
+ unsigned size;
+ unsigned totalsize;
+ HeadPtr h;
+
+ if (!endOfStaticMemory)
+ endOfStaticMemory = (mem *) sbrk(0);
+ if (FindLeakCheckAlways)
+ CheckMemory ();
+ size = RoundUp(desiredsize);
+ totalsize = TotalSize (size);
+
+ h = deadMemory;
+ while (h)
+ {
+ if (h->actualSize == size)
+ break;
+ else if (h->actualSize < size)
+ h = h->right;
+ else {
+ if (!h->left)
+ break;
+ h = h->left;
+ }
+ }
+ if (h)
+ {
+ tree_delete (&deadMemory, h, TRUE);
+ }
+ else
+ {
+ h = (HeadPtr) morecore (totalsize);
+ if (!h)
+ return NULL;
+ h->actualSize = size;
+ }
+ h->desiredsize = desiredsize;
+ h->size = size;
+#ifdef HAS_GET_RETURN_ADDRESS
+ getStackTrace (h->returnStack, MAX_RETURN_STACK);
+#endif
+ AddActiveBlock (h);
+ return (char *) DataForHead(h);
+}
+
+void
+free (p)
+ char *p;
+{
+ HeadPtr h;
+ static int beenHere;
+
+#ifndef NO_ATEXIT
+ /* do it at free instead of malloc to avoid recursion? */
+ if (!beenHere)
+ {
+ beenHere = TRUE;
+ atexit (CheckMemory);
+ }
+#endif
+ if (!p)
+ {
+ MemError ("Freeing NULL", (HeadPtr) 0, TRUE);
+ return;
+ }
+ SEARCH (activeMemory, h, p);
+ if (!h)
+ {
+ SEARCH(freedMemory, h, p);
+ if (h)
+ MemError ("Freeing something twice", h, TRUE);
+ else
+ MemError ("Freeing something never allocated", h, TRUE);
+ return;
+ }
+ if (DataForHead(h) != (mem *) p)
+ {
+ MemError ("Freeing pointer to middle of allocated block", h, TRUE);
+ return;
+ }
+ if (h->headMagic != ACTIVE_HEAD_MAGIC ||
+ TailForHead(h)->tailMagic != ACTIVE_TAIL_MAGIC)
+ MemError ("Freeing corrupted data", h, TRUE);
+ RemoveActiveBlock (h);
+#ifdef HAS_GET_RETURN_ADDRESS
+ getStackTrace (h->returnStack, MAX_RETURN_STACK);
+#endif
+ AddFreedBlock (h);
+ if (FindLeakCheckAlways)
+ CheckMemory ();
+}
+
+char *
+realloc (old, desiredsize)
+ char *old;
+ unsigned desiredsize;
+{
+ char *new;
+ HeadPtr h, fh;
+ int copysize;
+
+ new = malloc (desiredsize);
+ if (!new)
+ return NULL;
+ SEARCH(activeMemory, h, old);
+ if (!h)
+ {
+ SEARCH(freedMemory, fh, old);
+ if (fh)
+ MemError ("Reallocing from freed data", fh, TRUE);
+ else
+ MemError ("Reallocing from something not allocated", h, TRUE);
+ }
+ else
+ {
+ if (DataForHead(h) != (mem *) old)
+ {
+ MemError ("Reallocing from pointer to middle of allocated block", h, TRUE);
+ }
+ else
+ {
+ if (h->headMagic != ACTIVE_HEAD_MAGIC ||
+ TailForHead(h)->tailMagic != ACTIVE_TAIL_MAGIC)
+ MemError ("Reallocing corrupted data", h, TRUE);
+ copysize = desiredsize;
+ if (h->desiredsize < desiredsize)
+ copysize = h->desiredsize;
+#ifdef SVR4
+ memmove (new, old, copysize);
+#else
+ bcopy (old, new, copysize);
+#endif
+ RemoveActiveBlock (h);
+#ifdef HAS_GET_RETURN_ADDRESS
+ getStackTrace (h->returnStack, MAX_RETURN_STACK);
+#endif
+ AddFreedBlock (h);
+ }
+ }
+ return new;
+}
+
+char *
+calloc (num, size)
+ unsigned num, size;
+{
+ char *ret;
+
+ size *= num;
+ ret = malloc (size);
+ if (!ret)
+ return NULL;
+#ifdef SVR4
+ memset (ret, 0, size);
+#else
+ bzero (ret, size);
+#endif
+ return ret;
+}
+
+/*
+ * Semi-Balanced trees (avl). This only contains two
+ * routines - insert and delete. Searching is
+ * reserved for the client to write.
+ */
+
+static rebalance_right (), rebalance_left ();
+
+/*
+ * insert a new node
+ *
+ * this routine returns non-zero if the tree has grown
+ * taller
+ */
+
+static int
+tree_insert (treep, new, bySize)
+tree **treep;
+tree *new;
+int bySize;
+{
+ if (!(*treep)) {
+ (*treep) = new;
+ (*treep)->left = 0;
+ (*treep)->right = 0;
+ (*treep)->balance = 0;
+ return 1;
+ } else {
+ if (LESS_THAN (*treep, new, bySize)) {
+ if (tree_insert (&((*treep)->right), new, bySize))
+ switch (++(*treep)->balance) {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ (void) rebalance_right (treep);
+ }
+ return 0;
+ } else if (GREATER_THAN(*treep, new, bySize)) {
+ if (tree_insert (&((*treep)->left), new, bySize))
+ switch (--(*treep)->balance) {
+ case 0:
+ return 0;
+ case -1:
+ return 1;
+ case -2:
+ (void) rebalance_left (treep);
+ }
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * delete a node from a tree
+ *
+ * this routine return non-zero if the tree has been shortened
+ */
+
+static int
+tree_delete (treep, old, bySize)
+tree **treep;
+tree *old;
+int bySize;
+{
+ tree *to_be_deleted;
+ tree *replacement;
+ tree *replacement_parent;
+ int replacement_direction;
+ int delete_direction;
+ tree *swap_temp;
+ int balance_temp;
+
+ if (!*treep)
+ /* node not found */
+ return 0;
+ if (LESS_THAN(*treep, old, bySize)) {
+ if (tree_delete (&(*treep)->right, old, bySize))
+ /*
+ * check the balance factors
+ * Note that the conditions are
+ * inverted from the insertion case
+ */
+ switch (--(*treep)->balance) {
+ case 0:
+ return 1;
+ case -1:
+ return 0;
+ case -2:
+ return rebalance_left (treep);
+ }
+ return 0;
+ } else if (GREATER_THAN(*treep, old, bySize)) {
+ if (tree_delete (&(*treep)->left, old, bySize))
+ switch (++(*treep)->balance) {
+ case 0:
+ return 1;
+ case 1:
+ return 0;
+ case 2:
+ return rebalance_right (treep);
+ }
+ return 0;
+ } else {
+ to_be_deleted = *treep;
+ /*
+ * find an empty down pointer (if any)
+ * and rehook the tree
+ */
+ if (!to_be_deleted->right) {
+ (*treep) = to_be_deleted->left;
+ return 1;
+ } else if (!to_be_deleted->left) {
+ (*treep) = to_be_deleted->right;
+ return 1;
+ } else {
+ /*
+ * if both down pointers are full, then
+ * move a node from the bottom of the tree up here.
+ *
+ * This builds an incorrect tree -- the replacement
+ * node and the to_be_deleted node will not
+ * be in correct order. This doesn't matter as
+ * the to_be_deleted node will obviously not leave
+ * this routine alive.
+ */
+ /*
+ * if the tree is left heavy, then go left
+ * else go right
+ */
+ replacement_parent = to_be_deleted;
+ if (to_be_deleted->balance == -1) {
+ delete_direction = -1;
+ replacement_direction = -1;
+ replacement = to_be_deleted->left;
+ while (replacement->right) {
+ replacement_parent = replacement;
+ replacement_direction = 1;
+ replacement = replacement->right;
+ }
+ } else {
+ delete_direction = 1;
+ replacement_direction = 1;
+ replacement = to_be_deleted->right;
+ while (replacement->left) {
+ replacement_parent = replacement;
+ replacement_direction = -1;
+ replacement = replacement->left;
+ }
+ }
+ /*
+ * swap the replacement node into
+ * the tree where the node is to be removed
+ *
+ * this would be faster if only the data
+ * element was swapped -- but that
+ * won't work for findleak. The alternate
+ * code would be:
+ data_temp = to_be_deleted->data;
+ to _be_deleted->data = replacement->data;
+ replacement->data = data_temp;
+ */
+ swap_temp = to_be_deleted->left;
+ to_be_deleted->left = replacement->left;
+ replacement->left = swap_temp;
+ swap_temp = to_be_deleted->right;
+ to_be_deleted->right = replacement->right;
+ replacement->right = swap_temp;
+ balance_temp = to_be_deleted->balance;
+ to_be_deleted->balance = replacement->balance;
+ replacement->balance = balance_temp;
+ /*
+ * if the replacement node is directly below
+ * the to-be-removed node, hook the to_be_deleted
+ * node below it (instead of below itself!)
+ */
+ if (replacement_parent == to_be_deleted)
+ replacement_parent = replacement;
+ if (replacement_direction == -1)
+ replacement_parent->left = to_be_deleted;
+ else
+ replacement_parent->right = to_be_deleted;
+ (*treep) = replacement;
+ /*
+ * delete the node from the sub-tree
+ */
+ if (delete_direction == -1) {
+ if (tree_delete (&(*treep)->left, old, bySize)) {
+ switch (++(*treep)->balance) {
+ case 2:
+ abort ();
+ case 1:
+ return 0;
+ case 0:
+ return 1;
+ }
+ }
+ return 0;
+ } else {
+ if (tree_delete (&(*treep)->right, old, bySize)) {
+ switch (--(*treep)->balance) {
+ case -2:
+ abort ();
+ case -1:
+ return 0;
+ case 0:
+ return 1;
+ }
+ }
+ return 0;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * two routines to rebalance the tree.
+ *
+ * rebalance_right -- the right sub-tree is too long
+ * rebalance_left -- the left sub-tree is too long
+ *
+ * These routines are the heart of avl trees, I've tried
+ * to make their operation reasonably clear with comments,
+ * but some study will be necessary to understand the
+ * algorithm.
+ *
+ * these routines return non-zero if the resultant
+ * tree is shorter than the un-balanced version. This
+ * is only of interest to the delete routine as the
+ * balance after insertion can never actually shorten
+ * the tree.
+ */
+
+static
+rebalance_right (treep)
+tree **treep;
+{
+ tree *temp;
+ /*
+ * rebalance the tree
+ */
+ if ((*treep)->right->balance == -1) {
+ /*
+ * double whammy -- the inner sub-sub tree
+ * is longer than the outer sub-sub tree
+ *
+ * this is the "double rotation" from
+ * knuth. Scheme: replace the tree top node
+ * with the inner sub-tree top node and
+ * adjust the maze of pointers and balance
+ * factors accordingly.
+ */
+ temp = (*treep)->right->left;
+ (*treep)->right->left = temp->right;
+ temp->right = (*treep)->right;
+ switch (temp->balance) {
+ case -1:
+ temp->right->balance = 1;
+ (*treep)->balance = 0;
+ break;
+ case 0:
+ temp->right->balance = 0;
+ (*treep)->balance = 0;
+ break;
+ case 1:
+ temp->right->balance = 0;
+ (*treep)->balance = -1;
+ break;
+ }
+ temp->balance = 0;
+ (*treep)->right = temp->left;
+ temp->left = (*treep);
+ (*treep) = temp;
+ return 1;
+ } else {
+ /*
+ * a simple single rotation
+ *
+ * Scheme: replace the tree top node
+ * with the sub-tree top node
+ */
+ temp = (*treep)->right->left;
+ (*treep)->right->left = (*treep);
+ (*treep) = (*treep)->right;
+ (*treep)->left->right = temp;
+ /*
+ * only two possible configurations --
+ * if the right sub-tree was balanced, then
+ * *both* sides of it were longer than the
+ * left side, so the resultant tree will
+ * have a long leg (the left inner leg being
+ * the same length as the right leg)
+ */
+ if ((*treep)->balance == 0) {
+ (*treep)->balance = -1;
+ (*treep)->left->balance = 1;
+ return 0;
+ } else {
+ (*treep)->balance = 0;
+ (*treep)->left->balance = 0;
+ return 1;
+ }
+ }
+}
+
+static
+rebalance_left (treep)
+tree **treep;
+{
+ tree *temp;
+ /*
+ * rebalance the tree
+ */
+ if ((*treep)->left->balance == 1) {
+ /*
+ * double whammy -- the inner sub-sub tree
+ * is longer than the outer sub-sub tree
+ *
+ * this is the "double rotation" from
+ * knuth. Scheme: replace the tree top node
+ * with the inner sub-tree top node and
+ * adjust the maze of pointers and balance
+ * factors accordingly.
+ */
+ temp = (*treep)->left->right;
+ (*treep)->left->right = temp->left;
+ temp->left = (*treep)->left;
+ switch (temp->balance) {
+ case 1:
+ temp->left->balance = -1;
+ (*treep)->balance = 0;
+ break;
+ case 0:
+ temp->left->balance = 0;
+ (*treep)->balance = 0;
+ break;
+ case -1:
+ temp->left->balance = 0;
+ (*treep)->balance = 1;
+ break;
+ }
+ temp->balance = 0;
+ (*treep)->left = temp->right;
+ temp->right = (*treep);
+ (*treep) = temp;
+ return 1;
+ } else {
+ /*
+ * a simple single rotation
+ *
+ * Scheme: replace the tree top node
+ * with the sub-tree top node
+ */
+ temp = (*treep)->left->right;
+ (*treep)->left->right = (*treep);
+ (*treep) = (*treep)->left;
+ (*treep)->right->left = temp;
+ /*
+ * only two possible configurations --
+ * if the left sub-tree was balanced, then
+ * *both* sides of it were longer than the
+ * right side, so the resultant tree will
+ * have a long leg (the right inner leg being
+ * the same length as the left leg)
+ */
+ if ((*treep)->balance == 0) {
+ (*treep)->balance = 1;
+ (*treep)->right->balance = -1;
+ return 0;
+ } else {
+ (*treep)->balance = 0;
+ (*treep)->right->balance = 0;
+ return 1;
+ }
+ }
+}
+
+#ifdef DEBUG
+
+static
+depth (treep)
+tree *treep;
+{
+ int ldepth, rdepth;
+
+ if (!treep)
+ return 0;
+ ldepth = depth (treep->left);
+ rdepth = depth (treep->right);
+ if (ldepth > rdepth)
+ return ldepth + 1;
+ return rdepth + 1;
+}
+
+static tree *
+left_most (treep)
+tree *treep;
+{
+ while (treep && treep->left)
+ treep = treep->left;
+ return treep;
+}
+
+static tree *
+right_most (treep)
+tree *treep;
+{
+ while (treep && treep->right)
+ treep = treep->right;
+ return treep;
+}
+
+tree_verify (treep)
+tree *treep;
+{
+ tree_data left_data, right_data;
+
+ if (!treep)
+ return 1;
+ if (treep->left)
+ left_data = right_most (treep->left)->data;
+ else
+ left_data = treep->data - 1;
+ if (treep->right)
+ right_data = left_most (treep->right)->data;
+ else
+ right_data = treep->data + 1;
+ if (treep->data < left_data || treep->data > right_data) {
+ abort ();
+ return 0;
+ }
+ if (treep->balance != depth (treep->right) - depth (treep->left)) {
+ abort ();
+ return 0;
+ }
+ return tree_verify (treep->left) && tree_verify (treep->right);
+}
+
+#endif
diff --git a/xc/util/memleak/ftest.c b/xc/util/memleak/ftest.c
new file mode 100644
index 000000000..13d3030d8
--- /dev/null
+++ b/xc/util/memleak/ftest.c
@@ -0,0 +1,49 @@
+/*
+ * $TOG: ftest.c /main/5 1998/02/09 11:39:56 kaleb $
+ *
+Copyright 1992, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+static char *foo, *bar, *bletch;
+static char *glorf[100];
+
+extern char *malloc ();
+
+main ()
+{
+ int i;
+
+ foo = malloc (1000);
+ bar = malloc (2000);
+ bletch = malloc (3000);
+ for (i = 0; i < 100; i++)
+ glorf[i] = malloc (i * 200);
+ for (i = 0; i < 100; i++) {
+ free (glorf[i]);
+ glorf[i] = 0;
+ }
+ free (foo);
+ free (bletch);
+ bletch = 0;
+ *foo = 'a';
+ bar = 0;
+ CheckMemory ();
+}
diff --git a/xc/util/memleak/getreti386.c b/xc/util/memleak/getreti386.c
new file mode 100644
index 000000000..77ac82a05
--- /dev/null
+++ b/xc/util/memleak/getreti386.c
@@ -0,0 +1,36 @@
+/*
+ * some bits copied from mprof by Ben Zorn
+ *
+ * Copyright (c) 1995 Jeffrey Hsu
+ */
+
+/* $XFree86: xc/util/memleak/getreti386.c,v 3.2 1996/10/16 14:46:28 dawes Exp $ */
+
+#define get_current_fp(first_local) ((unsigned)&(first_local) + 4)
+#define prev_fp_from_fp(fp) *((unsigned *) fp)
+#define ret_addr_from_fp(fp) *((unsigned *) (fp+4))
+
+#ifdef __FreeBSD__
+#define CRT0_ADDRESS 0x10d3
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#define CRT0_ADDRESS 0x109a
+#endif
+
+void
+getStackTrace(unsigned long *results, int max)
+{
+
+ int first_local;
+ unsigned long fp, ret_addr;
+
+ fp = get_current_fp(first_local);
+ ret_addr = ret_addr_from_fp(fp);
+
+ while (ret_addr > CRT0_ADDRESS && max--) {
+ *results++ = ret_addr;
+ fp = prev_fp_from_fp(fp);
+ ret_addr = ret_addr_from_fp(fp);
+ }
+
+}
diff --git a/xc/util/memleak/getretmips.c b/xc/util/memleak/getretmips.c
new file mode 100644
index 000000000..7a65fb887
--- /dev/null
+++ b/xc/util/memleak/getretmips.c
@@ -0,0 +1,191 @@
+/*
+ * $TOG: getretmips.c /main/5 1998/02/09 11:40:00 kaleb $
+ *
+Copyright 1992, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/* Return stack generation for MIPS processors
+ * This is tricky as MIPS stack frames aren't
+ * easily unrolled -- we look for pc restoration
+ * and stack adjustment instructions beyond the return
+ * address to discover the correct values
+ */
+
+/* lw $31,const($sp) is : 100 011 11101 11111 const */
+/* 1000 1111 1011 1111 */
+
+#define RESTORE_RETURNVAL 0x8fbf0000
+#define RESTORE_RETURNVAL_MASK 0xffff0000
+
+/* addiu $sp, $sp, const is 001 001 11101 11101 const */
+/* 0010 0111 1011 1101 const */
+
+#define ADJUST_STACKP_C 0x27bd0000
+#define ADJUST_STACKP_C_MASK 0xffff0000
+
+/* addu $sp, $sp, $at is 000 000 11101 00001 11101 00000 100 001 */
+/* 0000 0011 1010 0001 1110 1000 0010 0001 */
+
+#define ADJUST_STACKP_V 0x03a1e821
+#define ADJUST_STACKP_V_MASK 0xffffffff
+
+/* lui $at, const is 001 111 00000 00001 const */
+/* 0011 1100 0000 0001 const */
+
+#define SET_UPPER_C 0x3c010000
+#define SET_UPPER_C_MASK 0xffff0000
+
+/* ori $at, $at, const is 001 101 00001 00001 const */
+/* 0011 0100 0010 0001 const */
+
+#define OR_LOWER_C 0x34210000
+#define OR_LOWER_C_MASK 0xffff0000
+
+/* ori $at, $zero, const is 001 101 00000 00001 const */
+/* 0011 0100 0000 0001 const */
+
+#define SET_LOWER_C 0x34010000
+#define SET_LOWER_C_MASK 0xffff0000
+
+/* jr $ra */
+#define RETURN 0x03e00008
+
+#define CALL(f) (0x0c000000 | (((int) (f)) >> 2))
+
+/*
+ * This computation is expensive, so we cache the results;
+ * a simple hash function and straight-forward replacement.
+ */
+
+#define HASH_SIZE 256
+
+typedef struct _returnCache {
+ unsigned long *returnAddress;
+ long raOffset;
+ long spAdjust;
+} ReturnCacheRec, *ReturnCachePtr;
+
+static ReturnCacheRec returnCache[HASH_SIZE];
+
+#define HASH(ra) ((((int) (ra)) >> 2) & (HASH_SIZE - 1))
+
+typedef int Bool;
+
+#define TRUE 1
+#define FALSE 0
+
+getStackTrace (results, max)
+ unsigned long *results;
+ int max;
+{
+ extern unsigned long *getReturnAddress (), *getStackPointer ();
+ extern int main ();
+ unsigned long *ra, *ra_limit;
+ unsigned long *sp;
+ unsigned long inst;
+ unsigned long mainCall;
+ unsigned short const_upper;
+ unsigned short const_lower;
+ long ra_offset;
+ long sp_adjust;
+ Bool found_ra_offset, found_sp_adjust;
+ Bool found_const_upper, found_const_lower;
+ ReturnCachePtr rc;
+
+ ra = getReturnAddress ();
+ sp = getStackPointer ();
+ mainCall = CALL(main);
+ while (ra && max) {
+ rc = &returnCache[HASH(ra)];
+ if (rc->returnAddress != ra)
+ {
+ found_ra_offset = FALSE;
+ found_sp_adjust = FALSE;
+ found_const_upper = FALSE;
+ found_const_lower = FALSE;
+ const_upper = 0;
+ const_lower = 0;
+ rc->returnAddress = ra;
+ ra_limit = (unsigned long *) 0x10000000;
+ ra_offset = 0;
+ sp_adjust = -1;
+ while ((!found_ra_offset || !found_sp_adjust) && ra < ra_limit)
+ {
+ inst = *ra;
+ /* look for the offset of the PC in the stack frame */
+ if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL)
+ {
+ ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
+ found_ra_offset = TRUE;
+ }
+ else if ((inst & ADJUST_STACKP_C_MASK) == ADJUST_STACKP_C)
+ {
+ sp_adjust = inst & ~ADJUST_STACKP_C_MASK;
+ found_sp_adjust = TRUE;
+ }
+ else if ((inst & ADJUST_STACKP_V_MASK) == ADJUST_STACKP_V)
+ {
+ sp_adjust = 0;
+ found_sp_adjust = TRUE;
+ }
+ else if ((inst & SET_UPPER_C_MASK) == SET_UPPER_C)
+ {
+ const_upper = inst & ~SET_UPPER_C_MASK;
+ const_lower = 0;
+ found_const_upper = TRUE;
+ }
+ else if ((inst & OR_LOWER_C_MASK) == OR_LOWER_C)
+ {
+ const_lower = inst & ~OR_LOWER_C_MASK;
+ found_const_lower = TRUE;
+ }
+ else if ((inst & SET_LOWER_C_MASK) == SET_LOWER_C)
+ {
+ const_lower = inst & ~SET_LOWER_C_MASK;
+ const_upper = 0;
+ found_const_lower = TRUE;
+ }
+ else if (inst == RETURN)
+ ra_limit = ra + 2;
+ ra++;
+ }
+ if (sp_adjust == 0 && (found_const_upper || found_const_lower))
+ sp_adjust = (const_upper << 16) | const_lower;
+ rc->raOffset = ra_offset;
+ rc->spAdjust = sp_adjust;
+ }
+ /* if something went wrong, punt */
+ if (rc->spAdjust <= 0)
+ {
+ *results++ = 0;
+ break;
+ }
+ ra = (unsigned long *) sp[rc->raOffset>>2];
+ sp += rc->spAdjust >> 2;
+ *results++ = ((unsigned long) ra) - 8;
+ if (ra[-2] == mainCall)
+ {
+ *results++ = 0;
+ break;
+ }
+ max--;
+ }
+}
diff --git a/xc/util/memleak/getretspar.c b/xc/util/memleak/getretspar.c
new file mode 100644
index 000000000..c72b1e394
--- /dev/null
+++ b/xc/util/memleak/getretspar.c
@@ -0,0 +1,62 @@
+/*
+ * $TOG: getretspar.c /main/3 1998/02/09 11:40:04 kaleb $
+ *
+Copyright 1992, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/* Trace up the stack and build a call history -- SPARC specific code */
+
+/* hack -- flush out the register windows by recursing */
+
+static void
+flushWindows (depth)
+{
+ if (depth == 0)
+ return;
+ flushWindows (depth-1);
+}
+
+getStackTrace (results, max)
+ unsigned long *results;
+ int max;
+{
+ unsigned long *sp, *getStackPointer (), *getFramePointer();
+ unsigned long *ra, mainCall;
+ extern int main ();
+
+ flushWindows (32);
+ sp = getFramePointer ();
+ while (max)
+ {
+ /* sparc stack traces are easy -- chain up the saved FP/SP values */
+ ra = (unsigned long *) sp[15];
+ sp = (unsigned long *) sp[14];
+ /* stop when we get the call to main */
+ mainCall = ((((unsigned long) main) - ((unsigned long) ra)) >> 2) | 0x40000000;
+ if (ra[0] == mainCall)
+ {
+ *results++ = 0;
+ break;
+ }
+ *results++ = (unsigned long) ra;
+ max--;
+ }
+}
diff --git a/xc/util/memleak/getrettest.c b/xc/util/memleak/getrettest.c
new file mode 100644
index 000000000..671a0b429
--- /dev/null
+++ b/xc/util/memleak/getrettest.c
@@ -0,0 +1,44 @@
+/*
+ * $TOG: getrettest.c /main/5 1998/02/09 11:40:08 kaleb $
+ *
+Copyright 1992, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+main ()
+{
+ f ();
+}
+
+f ()
+{
+ g ();
+}
+
+
+g ()
+{
+ unsigned long returnStack[16];
+ int i;
+
+ getStackTrace (returnStack, 16);
+ for (i = 0; i < 16 && returnStack[i]; i++)
+ printf ("%2d: 0x%lx\n", i, returnStack[i]);
+}
diff --git a/xc/util/memleak/mipsstack.s b/xc/util/memleak/mipsstack.s
new file mode 100644
index 000000000..9dfb94d41
--- /dev/null
+++ b/xc/util/memleak/mipsstack.s
@@ -0,0 +1,39 @@
+/*
+ * $TOG: mipsstack.s /main/4 1998/02/09 11:40:17 kaleb $
+ *
+Copyright 1992, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+ .globl getReturnAddress
+ .ent getReturnAddress
+getReturnAddress:
+ .frame $sp, 0, $31
+ move $2,$31
+ j $31
+ .end getReturnAddress
+
+ .globl getStackPointer
+ .ent getStackPointer
+getStackPointer:
+ .frame $sp, 0, $31
+ move $2,$29
+ j $31
+ .end getStackPointer
diff --git a/xc/util/memleak/sparcsolstack.s b/xc/util/memleak/sparcsolstack.s
new file mode 100644
index 000000000..4eac4ed5f
--- /dev/null
+++ b/xc/util/memleak/sparcsolstack.s
@@ -0,0 +1,11 @@
+! $XConsortium: sparcsolstack.s,v 1.1 93/12/03 09:26:24 kaleb Exp $
+ .seg "text"
+ .proc 16
+ .globl getStackPointer
+getStackPointer:
+ retl
+ mov %sp,%o0
+ .globl getFramePointer
+getFramePointer:
+ retl
+ mov %fp,%o0
diff --git a/xc/util/memleak/sparcstack.s b/xc/util/memleak/sparcstack.s
new file mode 100644
index 000000000..99f5221eb
--- /dev/null
+++ b/xc/util/memleak/sparcstack.s
@@ -0,0 +1,11 @@
+# $XConsortium: sparcstack.s,v 1.2 92/04/08 17:19:18 keith Exp $
+ .seg "text"
+ .proc 16
+ .globl _getStackPointer
+_getStackPointer:
+ retl
+ mov %sp,%o0
+ .globl _getFramePointer
+_getFramePointer:
+ retl
+ mov %fp,%o0
diff --git a/xc/util/memleak/stackbottom.c b/xc/util/memleak/stackbottom.c
new file mode 100644
index 000000000..b29400eb6
--- /dev/null
+++ b/xc/util/memleak/stackbottom.c
@@ -0,0 +1,123 @@
+/*
+ * cut and paste from gc 4.4 by Hans-J. Boehm and Alan J. Demers
+ *
+ * Cutter and Paster: Jeffrey Hsu
+ */
+
+/* $XFree86: xc/util/memleak/stackbottom.c,v 3.1 1996/12/31 05:02:27 dawes Exp $ */
+
+#include <signal.h>
+
+typedef char * ptr_t; /* A generic pointer to which we can add */
+ /* byte displacements. */
+ /* Preferably identical to caddr_t, if it */
+ /* exists. */
+
+#ifndef bool
+typedef int bool;
+#endif
+
+#define VOLATILE volatile
+
+# ifndef STACK_GROWS_UP
+# define STACK_GROWS_DOWN
+# endif
+
+typedef unsigned long word;
+
+#define TRUE 1
+
+#if defined(__alpha) || defined(__alpha__)
+ extern __start
+# define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1)))
+#endif
+
+void GC_noop() {}
+
+ /* Some tools to implement HEURISTIC2 */
+# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
+# include <setjmp.h>
+ /* static */ jmp_buf GC_jmp_buf;
+
+ /*ARGSUSED*/
+ void GC_fault_handler(sig)
+ int sig;
+ {
+ longjmp(GC_jmp_buf, 1);
+ }
+
+# ifdef __STDC__
+ typedef void (*handler)(int);
+# else
+ typedef void (*handler)();
+# endif
+
+ /* Return the first nonaddressible location > p (up) or */
+ /* the smallest location q s.t. [q,p] is addressible (!up). */
+ ptr_t GC_find_limit(p, up)
+ ptr_t p;
+ bool up;
+ {
+ static VOLATILE ptr_t result;
+ /* Needs to be static, since otherwise it may not be */
+ /* preserved across the longjmp. Can safely be */
+ /* static since it's only called once, with the */
+ /* allocation lock held. */
+
+ static handler old_segv_handler, old_bus_handler;
+ /* See above for static declaration. */
+
+ old_segv_handler = signal(SIGSEGV, GC_fault_handler);
+# ifdef SIGBUS
+ old_bus_handler = signal(SIGBUS, GC_fault_handler);
+# endif
+ if (setjmp(GC_jmp_buf) == 0) {
+ result = (ptr_t)(((word)(p))
+ & ~(MIN_PAGE_SIZE-1));
+ for (;;) {
+ if (up) {
+ result += MIN_PAGE_SIZE;
+ } else {
+ result -= MIN_PAGE_SIZE;
+ }
+ GC_noop(*result);
+ }
+ }
+ (void) signal(SIGSEGV, old_segv_handler);
+# ifdef SIGBUS
+ (void) signal(SIGBUS, old_bus_handler);
+# endif
+ if (!up) {
+ result += MIN_PAGE_SIZE;
+ }
+ return(result);
+ }
+
+ptr_t GC_get_stack_base()
+{
+ word dummy;
+ static ptr_t result;
+
+ if (!result) {
+
+# ifdef STACK_GROWS_DOWN
+ result = GC_find_limit((ptr_t)(&dummy), TRUE);
+# ifdef HEURISTIC2_LIMIT
+ if (result > HEURISTIC2_LIMIT
+ && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
+ result = HEURISTIC2_LIMIT;
+ }
+# endif
+# else
+ result = GC_find_limit((ptr_t)(&dummy), FALSE);
+# ifdef HEURISTIC2_LIMIT
+ if (result < HEURISTIC2_LIMIT
+ && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
+ result = HEURISTIC2_LIMIT;
+ }
+# endif
+# endif
+ }
+
+ return(result);
+}
diff --git a/xc/util/misc/dlsym.c b/xc/util/misc/dlsym.c
new file mode 100644
index 000000000..2e66d42a4
--- /dev/null
+++ b/xc/util/misc/dlsym.c
@@ -0,0 +1,29 @@
+/* $XConsortium: dlsym.c,v 1.1 93/12/06 16:24:15 kaleb Exp $ */
+/*
+ * Stub interface to dynamic linker routines
+ * that SunOS uses but didn't ship with 4.1.
+ *
+ * The C library routine wcstombs in SunOS 4.1 tries to dynamically
+ * load some routines using the dlsym interface, described in dlsym(3x).
+ * Unfortunately SunOS 4.1 does not include the necessary library, libdl.
+ *
+ * The R5 Xlib uses wcstombs. If you link dynamcally, your program can
+ * run even with the unresolved reference to dlsym. However, if you
+ * link statically, you will encounter this bug. One workaround
+ * is to include these stub routines when you link.
+ */
+
+void *dlopen()
+{
+ return 0;
+}
+
+void *dlsym()
+{
+ return 0;
+}
+
+int dlclose()
+{
+ return -1;
+}
diff --git a/xc/util/misc/rt.stdarg.h b/xc/util/misc/rt.stdarg.h
new file mode 100644
index 000000000..99cc06e7d
--- /dev/null
+++ b/xc/util/misc/rt.stdarg.h
@@ -0,0 +1,8 @@
+/* $XConsortium: rt.stdarg.h,v 1.1 93/12/06 16:24:27 kaleb Exp $ */
+#ifndef _STDARG_H
+#define _STDARG_H
+typedef int *va_list;
+#define va_start(ap, arg) ap = ((int *)&arg) + ((sizeof(arg) + 3) / 4)
+#define va_end(ap)
+#define va_arg(ap, type) ((type *)(ap += (sizeof(type)+3)/4))[-1]
+#endif
diff --git a/xc/util/misc/thr_stubs.c b/xc/util/misc/thr_stubs.c
new file mode 100644
index 000000000..3e841dc21
--- /dev/null
+++ b/xc/util/misc/thr_stubs.c
@@ -0,0 +1,27 @@
+/* $XConsortium: thr_stubs.c,v 1.3 94/01/13 13:59:50 kaleb Exp $ */
+/*
+ * Stub interface to thread routines that Solaris needs but shipped
+ * broken/buggy versions in 5.2 and 5.3
+ *
+ * One workaround is to include this stub routine when you link.
+ *
+ * These routines don't need to have accurate interfaces -- they will
+ * never be called. They just need to be there in order to be resolved
+ * at link time by non-threaded programs.
+ */
+
+extern int errno;
+
+typedef int thread_t;
+
+thread_t thr_self(void) { errno = -1; return 0; }
+int thr_create(void) { errno = -1; return -1; }
+int mutex_init(void) { errno = -1; return -1; }
+int mutex_destroy(void) { errno = -1; return -1; }
+int mutex_lock(void) { errno = -1; return -1; }
+int mutex_unlock(void) { errno = -1; return -1; }
+int cond_init(void) { errno = -1; return -1; }
+int cond_destroy(void) { errno = -1; return -1; }
+int cond_wait(void) { errno = -1; return -1; }
+int cond_signal(void) { errno = -1; return -1; }
+int cond_broadcast(void) { errno = -1; return -1; }
diff --git a/xc/util/patch/ChangeLog b/xc/util/patch/ChangeLog
new file mode 100644
index 000000000..305293787
--- /dev/null
+++ b/xc/util/patch/ChangeLog
@@ -0,0 +1,290 @@
+Mon May 31 00:49:40 1993 Paul Eggert (eggert@twinsun.com)
+
+ * patchlevel.h: PATCHLEVEL 12u9.
+
+ * inp.c (plan_a): Don't lock the checked-out file if `patch -o'
+ redirected the output elsewhere.
+ * common.h (CHECKOUT_LOCKED, GET_LOCKED): New macros. GET and
+ CHECKOUT now just checkout unlocked copies.
+
+ * Makefile (dist): Use gzip, not compress.
+
+Fri May 28 08:44:50 1993 Paul Eggert (eggert@twinsun.com)
+
+ * backupfile.c (basename): Define even if NODIR isn't defined.
+ * patch.c (main): Ask just once to apply a reversed patch.
+
+Tue Sep 15 00:36:15 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u8.
+
+Mon Sep 14 22:01:23 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * Makefile.SH: Add uninstall target. Simplify install target.
+
+ * util.c (fatal, pfatal): Add some asterisks to make fatal
+ messages stand out more.
+
+Tue Aug 25 22:13:36 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patch.c (main, get_some_switches), common.h, inp.c (plan_a,
+ plan_b), pch.c (there_is_another_patch): Add -t option,
+ similar to -f.
+
+Mon Jul 27 11:27:07 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * inp.c (plan_a, util.c (fetchname): Use a macro to simplify code.
+ * common.h: Define SCCSDIFF and RCSDIFF.
+ * inp.c (plan_a): Use them to make sure it's safe to check out
+ the default RCS or SCCS version.
+ From Paul Eggert.
+
+Wed Jul 22 14:37:08 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * patch.man: Use the standard comment syntax -- '\" -- instead
+ of '''.
+
+Tue Jul 21 15:26:01 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * Configure: Add /etc /usr/lib /lib to pth.
+
+Mon Jul 20 14:10:32 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.h: Declare basename.
+ * inp.c (plan_a), util.c (fetchname): Use it to isolate the
+ leading path when testing for RCS and SCCS files.
+
+Sat Jul 11 18:03:26 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * Configure: Use the user's PATH and build pth from it.
+
+Fri Jul 10 16:03:23 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * Configure: Change cc -S to cc -c and tr '[ - ]' '[\012-\012]'
+ to tr ' ' '\012' for AIX 3.2.
+ From chip@tct.com (Chip Salzenberg).
+
+ * util.c (makedirs): Only make the directories that don't exist.
+ From chip@tct.com (Chip Salzenberg).
+
+Wed Jul 8 01:21:15 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (fatal, pfatal): Print "patch: " before message.
+ * pch.c, inp.c, patch.c, util.c: Remove "patch: " from the
+ callers that had it.
+
+ * util.c (pfatal): New function.
+ * util.h: Declare it and pfatal[1-4] macros.
+ * various files: Use it instead of fatal where appropriate.
+
+ * Configure: Make /usr/local/man/man1 the first choice for the
+ man pages.
+
+ * patch.c (main): Open ofp after checking for ed script.
+ Close ofp and rejfp before trying plan B.
+ From epang@sfu.ca (Eugene Pang).
+
+ * backupfile.h: Declare get_version.
+
+ * Move decls of rindex and popen to common.h.
+
+ * common.h (myuid): New variable.
+ * patch.c (main): Initialize it.
+ * inp.c (myuid): Function removed.
+ (plan_a): Use the variable, not the function.
+
+ * patch.c: Reinstate -E option.
+
+Tue Jul 7 23:19:28 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * inp.c (myuid): New function.
+ (plan_a): Call it. Optimize stat calls. Be smarter about
+ detecting checked out RCS and SCCS files.
+ From Paul Eggert (eggert@twinsun.com).
+
+ * inp.c, util.c, patch.c: Don't bother checking for stat() > 0.
+
+Mon Jul 6 13:01:52 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * version.c (version): Don't print the RCS stuff, since we're
+ not updating it regularly.
+
+ * patch.c (get_some_switches): Make the usage message more accurate.
+
+ * patchlevel.h: PATCHLEVEL 12u7.
+
+ * Makefile.SH (dist): New target.
+ Makedist: File removed.
+
+ * inp.c (plan_a): Check whether the user can write to the
+ file, not whether anyone can write to the file.
+
+Sat Jul 4 00:06:58 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * inp.c (plan_a): Try to check out read-only files from RCS or SCCS.
+
+ * util.c (move_file): If backing up by linking fails, try copying.
+ From cek@sdc.boeing.com (Conrad Kimball).
+
+ * patch.c (get_some_switches): Eliminate -E option; always
+ remove empty output files.
+
+ * util.c (fetchname): Only undo slash removal for relative
+ paths if -p was not given.
+
+ * Makefile.sh: Add mostlyclean target.
+
+Fri Jul 3 23:48:14 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (fetchname): Accept whitespace between `Index:' and filename.
+ Also plug a small memory leak for diffs against /dev/null.
+ From eggert@twinsun.com (Paul Eggert).
+
+ * common.h: Don't define TRUE and FALSE if already defined.
+ From phk@data.fls.dk (Poul-Henning Kamp).
+
+Wed Apr 29 10:19:33 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * backupfile.c (get_version): Exit if given a bad backup type.
+
+Fri Mar 27 09:57:14 1992 Karl Berry (karl at hayley)
+
+ * common.h (S_ISDIR, S_ISREG): define these.
+ * inp.c (plan_a): use S_ISREG, not S_IFREG.
+ * util.c (fetchname): use S_ISDIR, not S_IFDIR.
+
+Mon Mar 16 14:10:42 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u6.
+
+Sat Mar 14 13:13:29 1992 David J. MacKenzie (djm at frob.eng.umd.edu)
+
+ * Configure, config.h.SH: Check for directory header and unistd.h.
+
+ * patch.c (main): If -E was given and output file is empty after
+ patching, remove it.
+ (get_some_switches): Recognize -E option.
+
+ * patch.c (copy_till): Make garbled output an error, not a warning
+ that doesn't change the exit status.
+
+ * common.h: Protect against system declarations of malloc and realloc.
+
+ * Makedist: Add backupfile.[ch].
+
+ * Configure: Look for C library where NeXT and SVR4 put it.
+ Look in /usr/ucb after /bin and /usr/bin for utilities,
+ and look in /usr/ccs/bin, to make SVR4 happier.
+ Recognize m68k predefine.
+
+ * util.c (fetchname): Test of stat return value was backward.
+ From csss@scheme.cs.ubc.ca.
+
+ * version.c (version): Exit with status 0, not 1.
+
+ * Makefile.SH: Add backupfile.[cho].
+ * patch.c (main): Initialize backup file generation.
+ (get_some_switches): Add -V option.
+ * common.h, util,c, patch.c: Replace origext with simple_backup_suffix.
+ * util.c (move_file): Use find_backup_file_name.
+
+Tue Dec 3 11:27:16 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u5.
+
+ * Makefile.SH: Change clean, distclean, and realclean targets a
+ little so they agree with the GNU coding standards.
+ Add Makefile to addedbyconf, so distclean removes it.
+
+ * Configure: Recognize Domain/OS C library in /lib/libc.
+ From mmuegel@mot.com (Michael S. Muegel).
+
+ * pch.c: Fixes from Wayne Davison:
+ Patch now accepts no-context context diffs that are
+ specified with an assumed one line hunk (e.g. "*** 10 ****").
+ Fixed a bug in both context and unified diff processing that would
+ put a zero-context hunk in the wrong place (one line too soon).
+ Fixed a minor problem with p_max in unified diffs where it would
+ set p_max to hunkmax unnecessarily (the only adverse effect was to
+ not supply empty lines at eof by assuming they were truncated).
+
+Tue Jul 2 03:25:51 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * Configure: Check for signal declaration in
+ /usr/include/sys/signal.h as well as /usr/include/signal.h.
+
+ * Configure, common.h, config.h.SH: Comment out the sprintf
+ declaration and tests to determine its return value type. It
+ conflicts with ANSI C systems' prototypes in stdio.h and the
+ return value of sprintf is never used anyway -- it's always cast
+ to void.
+
+Thu Jun 27 13:05:32 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u4.
+
+Thu Feb 21 15:18:14 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * pch.c (another_hunk): Fix off by 1 error. From
+ iverson@xstor.com (Tim Iverson).
+
+Sun Jan 20 20:18:58 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * Makefile.SH (all): Don't make a dummy `all' file.
+
+ * patchlevel.h: PATCHLEVEL 12u3.
+
+ * patch.c (nextarg): New function.
+ (get_some_switches): Use it, to prevent dereferencing a null
+ pointer if an option that takes an arg is not given one (is last
+ on the command line). From Paul Eggert.
+
+ * pch.c (another_hunk): Fix from Wayne Davison to recognize
+ single-line hunks in unified diffs (with a single line number
+ instead of a range).
+
+ * inp.c (rev_in_string): Don't use `s' before defining it. From
+ Wayne Davison.
+
+Mon Jan 7 06:25:11 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * patchlevel.h: PATCHLEVEL 12u2.
+
+ * pch.c (intuit_diff_type): Recognize `+++' in diff headers, for
+ unified diff format. From unidiff patch 1.
+
+Mon Dec 3 00:14:25 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * patch.c (get_some_switches): Make the usage message more
+ informative.
+
+Sun Dec 2 23:20:18 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Configure: When checking for C preprocessor, look for 'abc.*xyz'
+ instead of 'abc.xyz', so ANSI C preprocessors work.
+
+ * Apply fix for -D from ksb@mentor.cc.purdue.edu (Kevin Braunsdorf).
+
+ * Apply unidiff patches from davison@dri.com (Wayne Davison).
+
+Wed Mar 7 23:47:25 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * pch.c: Call malformed instead of goto malformed
+ (just allows easier debugging).
+
+Tue Jan 23 21:27:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu)
+
+ * common.h (TMP*NAME): Make these char *, not char [].
+ patch.c (main): Use TMPDIR (if present) to set TMP*NAME.
+ common.h: Declare getenv.
+
+Sun Dec 17 17:29:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu)
+
+ * patch.c (reverse_flag_specified): New variable.
+ (get_some_switches, reinitialize_almost_everything): Use it.
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+end:
diff --git a/xc/util/patch/Configure b/xc/util/patch/Configure
new file mode 100755
index 000000000..0636a7258
--- /dev/null
+++ b/xc/util/patch/Configure
@@ -0,0 +1,1476 @@
+#! /bin/sh
+#
+# If these # comments don't work, trim them. Don't worry about any other
+# shell scripts, Configure will trim # comments from them for you.
+#
+# (If you are trying to port this package to a machine without sh, I would
+# suggest you cut out the prototypical config.h from the end of Configure
+# and edit it to reflect your system. Some packages may include samples
+# of config.h for certain machines, so you might look for one of those.)
+#
+# oldHeader: Head.U,v 1.0 87/05/22 12:28:10 lwall Exp $
+# $XConsortium: Configure,v 1.1 94/09/09 20:04:01 gildea Exp $
+#
+# Yes, you may rip this off to use in other distribution packages.
+# (Note: this Configure script was generated automatically. Rather than
+# working with this copy of Configure, you may wish to get metaconfig.)
+
+: sanity checks
+: the user has a better chance than we do of setting a reasonable PATH
+: but add some directories we need that are probably not there
+PATH=.:${PATH}:/etc:/usr/lib:/lib
+export PATH || (echo "OOPS, this isn't sh. Desperation time. I will feed myself to sh."; sh $0; kill $$)
+
+if test ! -t 0; then
+ echo "Say 'sh Configure', not 'sh <Configure'"
+ exit 1
+fi
+
+(alias) >/dev/null 2>&1 && \
+ echo "(I see you are using the Korn shell. Some ksh's blow up on Configure," && \
+ echo "especially on exotic machines. If yours does, try the Bourne shell instead.)"
+
+if test ! -d ../UU; then
+ if test ! -d UU; then
+ mkdir UU
+ fi
+ cd UU
+fi
+
+case "$1" in
+-d) shift; fastread='yes';;
+esac
+
+d_eunice=''
+eunicefix=''
+define=''
+loclist=''
+expr=''
+sed=''
+echo=''
+cat=''
+rm=''
+mv=''
+cp=''
+tail=''
+tr=''
+mkdir=''
+sort=''
+uniq=''
+grep=''
+trylist=''
+test=''
+inews=''
+egrep=''
+more=''
+pg=''
+Mcc=''
+vi=''
+mailx=''
+mail=''
+cpp=''
+Log=''
+Header=''
+bin=''
+cc=''
+contains=''
+cppstdin=''
+cppminus=''
+d_charsprf=''
+d_flexfnam=''
+d_index=''
+d_voidsig=''
+d_dirheader=''
+d_unistd=''
+libc=''
+mansrc=''
+manext=''
+models=''
+split=''
+small=''
+medium=''
+large=''
+huge=''
+ccflags=''
+ldflags=''
+n=''
+c=''
+package=''
+registers=''
+reg1=''
+reg2=''
+reg3=''
+reg4=''
+reg5=''
+reg6=''
+reg7=''
+reg8=''
+reg9=''
+reg10=''
+reg11=''
+reg12=''
+reg13=''
+reg14=''
+reg15=''
+reg16=''
+spitshell=''
+shsharp=''
+sharpbang=''
+startsh=''
+voidflags=''
+defvoidused=''
+CONFIG=''
+: set package name
+package=patch
+
+echo " "
+echo "Beginning of configuration questions for $package kit."
+: Eunice requires " " instead of "", can you believe it
+echo " "
+
+define='define'
+undef='/*undef'
+libpth='/usr/lib /usr/local/lib /lib /usr/ccs/lib'
+smallmach='pdp11 i8086 z8000 i80286 iAPX286'
+rmlist='kit[1-9]isdone kit[1-9][0-9]isdone'
+trap 'echo " "; rm -f $rmlist; exit 1' 1 2 3
+
+: We must find out about Eunice early
+eunicefix=':'
+if test -f /etc/unixtovms; then
+ eunicefix=/etc/unixtovms
+fi
+if test -f /etc/unixtovms.exe; then
+ eunicefix=/etc/unixtovms.exe
+fi
+
+attrlist="mc68000 sun gcos unix ibm gimpel interdata tss os mert pyr"
+attrlist="$attrlist vax pdp11 i8086 z8000 u3b2 u3b5 u3b20 u3b200"
+attrlist="$attrlist ns32000 ns16000 iAPX286 mc300 mc500 mc700 sparc"
+attrlist="$attrlist nsc32000 sinix xenix venix posix ansi M_XENIX"
+attrlist="$attrlist mc68k m68k __STDC__"
+pth=`echo $PATH | tr : ' '`
+d_newshome="../../NeWS"
+defvoidused=7
+
+: some greps do not return status, grrr.
+echo "grimblepritz" >grimble
+if grep blurfldyick grimble >/dev/null 2>&1 ; then
+ contains=contains
+elif grep grimblepritz grimble >/dev/null 2>&1 ; then
+ contains=grep
+else
+ contains=contains
+fi
+rm -f grimble
+: the following should work in any shell
+case "$contains" in
+contains*)
+ echo " "
+ echo "AGH! Grep doesn't return a status. Attempting remedial action."
+ cat >contains <<'EOSS'
+grep "$1" "$2" >.greptmp && cat .greptmp && test -s .greptmp
+EOSS
+chmod +x contains
+esac
+
+: first determine how to suppress newline on echo command
+echo "Checking echo to see how to suppress newlines..."
+(echo "hi there\c" ; echo " ") >.echotmp
+if $contains c .echotmp >/dev/null 2>&1 ; then
+ echo "...using -n."
+ n='-n'
+ c=''
+else
+ cat <<'EOM'
+...using \c
+EOM
+ n=''
+ c='\c'
+fi
+echo $n "Type carriage return to continue. Your cursor should be here-->$c"
+read ans
+rm -f .echotmp
+
+: now set up to do reads with possible shell escape and default assignment
+cat <<EOSC >myread
+case "\$fastread" in
+yes) ans=''; echo " " ;;
+*) ans='!';;
+esac
+while expr "X\$ans" : "X!" >/dev/null; do
+ read ans
+ case "\$ans" in
+ !)
+ sh
+ echo " "
+ echo $n "\$rp $c"
+ ;;
+ !*)
+ set \`expr "X\$ans" : "X!\(.*\)\$"\`
+ sh -c "\$*"
+ echo " "
+ echo $n "\$rp $c"
+ ;;
+ esac
+done
+rp='Your answer:'
+case "\$ans" in
+'') ans="\$dflt";;
+esac
+EOSC
+
+: general instructions
+cat <<EOH
+
+This installation shell script will examine your system and ask you questions
+to determine how the $package package should be installed. If you get stuck
+on a question, you may use a ! shell escape to start a subshell or execute
+a command. Many of the questions will have default answers in square
+brackets--typing carriage return will give you the default.
+
+On some of the questions which ask for file or directory names you are
+allowed to use the ~name construct to specify the login directory belonging
+to "name", even if you don't have a shell which knows about that. Questions
+where this is allowed will be marked "(~name ok)".
+
+EOH
+rp="[Type carriage return to continue]"
+echo $n "$rp $c"
+. myread
+cat <<EOH
+
+Much effort has been expended to ensure that this shell script will run
+on any Unix system. If despite that it blows up on you, your best bet is
+to edit Configure and run it again. Also, let me (lwall@netlabs.com)
+know how I blew it. If you can't run Configure for some reason, you'll have
+to generate a config.sh file by hand.
+
+This installation script affects things in two ways: 1) it may do direct
+variable substitutions on some of the files included in this kit, and
+2) it builds a config.h file for inclusion in C programs. You may edit
+any of these files as the need arises after running this script.
+
+If you make a mistake on a question, there is no easy way to back up to it
+currently. The easiest thing to do is to edit config.sh and rerun all the
+SH files. Configure will offer to let you do this before it runs the SH files.
+
+EOH
+rp="[Type carriage return to continue]"
+echo $n "$rp $c"
+. myread
+
+: get old answers, if there is a config file out there
+if test -f ../config.sh; then
+ echo " "
+ dflt=y
+ rp="I see a config.sh file. Did Configure make it on THIS system? [$dflt]"
+ echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ n*) echo "OK, I'll ignore it.";;
+ *) echo "Fetching default answers from your old config.sh file..."
+ tmp="$n"
+ ans="$c"
+ . ../config.sh
+ n="$tmp"
+ c="$ans"
+ ;;
+ esac
+fi
+
+: find out where common programs are
+echo " "
+echo "Locating common programs..."
+cat <<EOSC >loc
+$startsh
+case \$# in
+0) exit 1;;
+esac
+thing=\$1
+shift
+dflt=\$1
+shift
+for dir in \$*; do
+ case "\$thing" in
+ .)
+ if test -d \$dir/\$thing; then
+ echo \$dir
+ exit 0
+ fi
+ ;;
+ *)
+ if test -f \$dir/\$thing; then
+ echo \$dir/\$thing
+ exit 0
+ elif test -f \$dir/\$thing.exe; then
+ : on Eunice apparently
+ echo \$dir/\$thing
+ exit 0
+ fi
+ ;;
+ esac
+done
+echo \$dflt
+exit 1
+EOSC
+chmod +x loc
+$eunicefix loc
+loclist="
+expr
+sed
+echo
+cat
+rm
+tr
+grep
+"
+trylist="
+test
+Mcc
+cpp
+"
+for file in $loclist; do
+ xxx=`loc $file $file $pth`
+ eval $file=$xxx
+ eval _$file=$xxx
+ case "$xxx" in
+ /*)
+ echo $file is in $xxx.
+ ;;
+ *)
+ echo "I don't know where $file is. I hope it's in everyone's PATH."
+ ;;
+ esac
+done
+echo " "
+echo "Don't worry if any of the following aren't found..."
+ans=offhand
+for file in $trylist; do
+ xxx=`loc $file $file $pth`
+ eval $file=$xxx
+ eval _$file=$xxx
+ case "$xxx" in
+ /*)
+ echo $file is in $xxx.
+ ;;
+ *)
+ echo "I don't see $file out there, $ans."
+ ans=either
+ ;;
+ esac
+done
+case "$egrep" in
+egrep)
+ echo "Substituting grep for egrep."
+ egrep=$grep
+ ;;
+esac
+case "$test" in
+test)
+ echo "Hopefully test is built into your sh."
+ ;;
+/bin/test)
+ echo " "
+ dflt=n
+ rp="Is your "'"'"test"'"'" built into sh? [$dflt] (OK to guess)"
+ echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ y*) test=test ;;
+ esac
+ ;;
+*)
+ test=test
+ ;;
+esac
+case "$echo" in
+echo)
+ echo "Hopefully echo is built into your sh."
+ ;;
+/bin/echo)
+ echo " "
+ echo "Checking compatibility between /bin/echo and builtin echo (if any)..."
+ $echo $n "hi there$c" >foo1
+ echo $n "hi there$c" >foo2
+ if cmp foo1 foo2 >/dev/null 2>&1; then
+ echo "They are compatible. In fact, they may be identical."
+ else
+ case "$n" in
+ '-n') n='' c='\c' ans='\c' ;;
+ *) n='-n' c='' ans='-n' ;;
+ esac
+ cat <<FOO
+They are not compatible! You are probably running ksh on a non-USG system.
+I'll have to use /bin/echo instead of the builtin, since Bourne shell doesn't
+have echo built in and we may have to run some Bourne shell scripts. That
+means I'll have to use $ans to suppress newlines now. Life is ridiculous.
+
+FOO
+ rp="Your cursor should be here-->"
+ $echo $n "$rp$c"
+ . myread
+ fi
+ $rm -f foo1 foo2
+ ;;
+*)
+ : cross your fingers
+ echo=echo
+ ;;
+esac
+rmlist="$rmlist loc"
+
+: get list of predefined functions in a handy place
+echo " "
+if test -f /lib/libc.a; then
+ echo "Your C library is in /lib/libc.a. You're normal."
+ libc=/lib/libc.a
+else
+ if test -f /lib/clib -a -f /lib/libc; then
+ echo "Your standard C library is in /lib/libc. Must be Domain/OS."
+ libc=/lib/libc
+ elif test -f /lib/libsys_s.a; then
+ echo "Your C library is in /lib/libsys_s.a. Must be a NeXT."
+ libc=/lib/libsys_s.a
+ else
+ ans=`loc libc.a blurfl/dyick $libpth`
+ if test ! -f $ans; then
+ ans=`loc clib blurfl/dyick $libpth`
+ fi
+ if test ! -f $ans; then
+ ans=`loc libc blurfl/dyick $libpth`
+ fi
+ if test -f $ans; then
+ echo "Your C library is in $ans, of all places."
+ libc=$ans
+ else
+ if test -f "$libc"; then
+ echo "Your C library is in $libc, like you said before."
+ else
+ cat <<EOM
+
+I can't seem to find your C library. I've looked in the following places:
+
+ $libpth
+
+None of these seems to contain your C library. What is the full name
+EOM
+ dflt=None
+ $echo $n "of your C library? $c"
+ rp='C library full name?'
+ . myread
+ libc="$ans"
+ fi
+ fi
+ fi
+fi
+echo " "
+$echo $n "Extracting names from $libc for later perusal...$c"
+nm $libc 2>/dev/null | sed -n -e 's/^.* T _//p' -e 's/^.* T //p' > libc.list
+if $contains '^printf$' libc.list >/dev/null 2>&1; then
+ echo "done"
+else
+ nm $libc 2>/dev/null | sed -n -e 's/^.* D _//p' -e 's/^.* D //p' > libc.list
+ if $contains '^printf$' libc.list >/dev/null 2>&1; then
+ echo "done"
+ else
+ echo " "
+ echo "nm didn't seem to work right."
+ echo "Trying ar instead..."
+ if ar t $libc | sed -e 's/\.o$//' > libc.list; then
+ echo "Ok."
+ else
+ echo "That didn't work either. Giving up."
+ exit 1
+ fi
+ fi
+fi
+rmlist="$rmlist libc.list"
+
+: make some quick guesses about what we are up against
+echo " "
+$echo $n "Hmm... $c"
+if $contains SIGTSTP /usr/include/signal.h >/dev/null 2>&1 ; then
+ echo "Looks kind of like a BSD system, but we'll see..."
+ echo exit 0 >bsd
+ echo exit 1 >usg
+ echo exit 1 >v7
+elif $contains '^fcntl$' libc.list >/dev/null 2>&1 ; then
+ echo "Looks kind of like a USG system, but we'll see..."
+ echo exit 1 >bsd
+ echo exit 0 >usg
+ echo exit 1 >v7
+else
+ echo "Looks kind of like a version 7 system, but we'll see..."
+ echo exit 1 >bsd
+ echo exit 1 >usg
+ echo exit 0 >v7
+fi
+if $contains '^vmssystem$' libc.list >/dev/null 2>&1 ; then
+ cat <<'EOI'
+There is, however, a strange, musty smell in the air that reminds me of
+something...hmm...yes...I've got it...there's a VMS nearby, or I'm a Blit.
+EOI
+ echo "exit 0" >eunice
+ eunicefix=unixtovms
+ d_eunice="$define"
+: it so happens the Eunice I know will not run shell scripts in Unix format
+else
+ echo " "
+ echo "Congratulations. You aren't running Eunice."
+ eunicefix=':'
+ d_eunice="$undef"
+ echo "exit 1" >eunice
+fi
+if test -f /xenix; then
+ echo "Actually, this looks more like a XENIX system..."
+ echo "exit 0" >xenix
+else
+ echo " "
+ echo "It's not Xenix..."
+ echo "exit 1" >xenix
+fi
+chmod +x xenix
+$eunicefix xenix
+if test -f /venix; then
+ echo "Actually, this looks more like a VENIX system..."
+ echo "exit 0" >venix
+else
+ echo " "
+ if xenix; then
+ : null
+ else
+ echo "Nor is it Venix..."
+ fi
+ echo "exit 1" >venix
+fi
+chmod +x bsd usg v7 eunice venix
+$eunicefix bsd usg v7 eunice venix
+rmlist="$rmlist bsd usg v7 eunice venix xenix"
+
+: see if sh knows # comments
+echo " "
+echo "Checking your sh to see if it knows about # comments..."
+if sh -c '#' >/dev/null 2>&1 ; then
+ echo "Your sh handles # comments correctly."
+ shsharp=true
+ spitshell=cat
+ echo " "
+ echo "Okay, let's see if #! works on this system..."
+ echo "#!/bin/echo hi" > try
+ $eunicefix try
+ chmod +x try
+ try > today
+ if $contains hi today >/dev/null 2>&1; then
+ echo "It does."
+ sharpbang='#!'
+ else
+ echo "#! /bin/echo hi" > try
+ $eunicefix try
+ chmod +x try
+ try > today
+ if test -s today; then
+ echo "It does."
+ sharpbang='#! '
+ else
+ echo "It doesn't."
+ sharpbang=': use '
+ fi
+ fi
+else
+ echo "Your sh doesn't grok # comments--I will strip them later on."
+ shsharp=false
+ echo "exec grep -v '^#'" >spitshell
+ chmod +x spitshell
+ $eunicefix spitshell
+ spitshell=`pwd`/spitshell
+ echo "I presume that if # doesn't work, #! won't work either!"
+ sharpbang=': use '
+fi
+
+: figure out how to guarantee sh startup
+echo " "
+echo "Checking out how to guarantee sh startup..."
+startsh=$sharpbang'/bin/sh'
+echo "Let's see if '$startsh' works..."
+cat >try <<EOSS
+$startsh
+set abc
+test "$?abc" != 1
+EOSS
+
+chmod +x try
+$eunicefix try
+if try; then
+ echo "Yup, it does."
+else
+ echo "Nope. You may have to fix up the shell scripts to make sure sh runs them."
+fi
+rm -f try today
+
+#: see if sprintf is declared as int or pointer to char
+#echo " "
+#cat >.ucbsprf.c <<'EOF'
+#main() { char buf[10]; exit((unsigned long)sprintf(buf,"%s","foo") > 10L); }
+#EOF
+#if cc .ucbsprf.c -o .ucbsprf >/dev/null 2>&1 && .ucbsprf; then
+# echo "Your sprintf() returns (int)."
+# d_charsprf="$undef"
+#else
+# echo "Your sprintf() returns (char*)."
+# d_charsprf="$define"
+#fi
+#/bin/rm -f .ucbsprf.c .ucbsprf
+
+: see if we can have long filenames
+echo " "
+rm -f 123456789abcde
+if (echo hi >123456789abcdef) 2>/dev/null; then
+ : not version 8
+ if test -f 123456789abcde; then
+ echo 'You cannot have filenames longer than 14 characters. Sigh.'
+ d_flexfnam="$undef"
+ else
+ echo 'You can have filenames longer than 14 characters.'
+ d_flexfnam="$define"
+ fi
+else
+ : version 8 probably
+ echo "You can't have filenames longer than 14 chars. V8 can't even think about them!"
+ d_flexfnam="$undef"
+fi
+: index or strcpy
+echo " "
+case "$d_index" in
+n) dflt=n;;
+*) dflt=y;;
+esac
+if $contains '^index$' libc.list >/dev/null 2>&1 ; then
+ if $contains '^strchr$' libc.list >/dev/null 2>&1 ; then
+ echo "Your system has both index() and strchr(). Shall I use"
+ rp="index() rather than strchr()? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ n*) d_index="$define" ;;
+ *) d_index="$undef" ;;
+ esac
+ else
+ d_index="$undef"
+ echo "index() found."
+ fi
+else
+ if $contains '^strchr$' libc.list >/dev/null 2>&1 ; then
+ d_index="$define"
+ echo "strchr() found."
+ else
+ echo "No index() or strchr() found!"
+ d_index="$undef"
+ fi
+fi
+
+: see if signal is declared as pointer to function returning int or void
+echo " "
+if $contains 'void.*signal' /usr/include/signal.h >/dev/null 2>&1 ||
+$contains 'void.*signal' /usr/include/sys/signal.h >/dev/null 2>&1 ; then
+ echo "You have void (*signal())() instead of int."
+ d_voidsig="$define"
+else
+ echo "You have int (*signal())() instead of void."
+ d_voidsig="$undef"
+fi
+
+: check for directory library
+echo " "
+if test -f /usr/include/dirent.h; then
+ echo "You have dirent.h."
+ d_dirheader="#define DIRENT"
+elif test -f /usr/include/ndir.h; then
+ echo "You have ndir.h."
+ d_dirheader="#define USG"
+elif test -f /usr/include/sys/ndir.h; then
+ echo "You have sys/ndir.h."
+ d_dirheader="#define SYSNDIR
+#define USG"
+elif test -f /usr/include/sys/dir.h; then
+ echo "You have sys/dir.h; I hope that's the BSD version."
+ d_dirheader="#define SYSDIR"
+else
+ echo "I can't find a directory library header file.
+That means you won't have numbered backups available."
+ d_dirheader="#define NODIR"
+fi
+
+: check for unistd.h
+echo " "
+if test -f /usr/include/unistd.h; then
+ echo "You have unistd.h."
+ d_unistd="$define"
+else
+ echo "I don't see unistd.h, but that's OK."
+ d_unistd="$undef"
+fi
+
+: check for void type
+echo " "
+$cat <<EOM
+Checking to see how well your C compiler groks the void type...
+
+ Support flag bits are:
+ 1: basic void declarations.
+ 2: arrays of pointers to functions returning void.
+ 4: operations between pointers to and addresses of void functions.
+
+EOM
+case "$voidflags" in
+'')
+ $cat >try.c <<'EOCP'
+#if TRY & 1
+void main() {
+#else
+main() {
+#endif
+ extern void *moo();
+ void *(*goo)();
+#if TRY & 2
+ void (*foo[10])();
+#endif
+
+#if TRY & 4
+ if(*goo == moo) {
+ exit(0);
+ }
+#endif
+ exit(0);
+}
+EOCP
+ : Argh -- AIX 3.2 does not have cc -S!
+ if cc -c -DTRY=7 try.c >.out 2>&1 ; then
+ voidflags=7
+ echo "It appears to support void fully."
+ if $contains warning .out >/dev/null 2>&1; then
+ echo "However, you might get some warnings that look like this:"
+ $cat .out
+ fi
+ else
+ echo "Hmm, you compiler has some difficulty with void. Checking further..."
+ if cc -c -DTRY=1 try.c >/dev/null 2>&1 ; then
+ echo "It supports 1..."
+ if cc -c -DTRY=3 try.c >/dev/null 2>&1 ; then
+ voidflags=3
+ echo "And it supports 2 but not 4."
+ else
+ echo "It doesn't support 2..."
+ if cc -c -DTRY=3 try.c >/dev/null 2>&1 ; then
+ voidflags=5
+ echo "But it supports 4."
+ else
+ voidflags=1
+ echo "And it doesn't support 4."
+ fi
+ fi
+ else
+ echo "There is no support at all for void."
+ voidflags=0
+ fi
+ fi
+esac
+dflt="$voidflags";
+rp="Your void support flags add up to what? [$dflt]"
+$echo $n "$rp $c"
+. myread
+voidflags="$ans"
+$rm -f try.* .out
+
+: see how we invoke the C preprocessor
+echo " "
+echo "Now, how can we feed standard input to your C preprocessor..."
+cat <<'EOT' >testcpp.c
+#define ABC abc
+#define XYZ xyz
+ABC.XYZ
+EOT
+echo 'Maybe "'$cpp'" will work...'
+$cpp <testcpp.c >testcpp.out 2>&1
+if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yup, it does."
+ cppstdin="$cpp"
+ cppminus='';
+else
+ echo 'Nope, maybe "'$cpp' -" will work...'
+ $cpp - <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yup, it does."
+ cppstdin="$cpp"
+ cppminus='-';
+ else
+ echo 'No such luck...maybe "cc -E" will work...'
+ cc -E <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "It works!"
+ cppstdin='cc -E'
+ cppminus='';
+ else
+ echo 'Nixed again...maybe "cc -E -" will work...'
+ cc -E - <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Hooray, it works! I was beginning to wonder."
+ cppstdin='cc -E'
+ cppminus='-';
+ else
+ echo 'Nope...maybe "cc -P" will work...'
+ cc -P <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yup, that does."
+ cppstdin='cc -P'
+ cppminus='';
+ else
+ echo 'Nope...maybe "cc -P -" will work...'
+ cc -P - <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yup, that does."
+ cppstdin='cc -P'
+ cppminus='-';
+ else
+ echo 'Hmm...perhaps you already told me...'
+ case "$cppstdin" in
+ '') ;;
+ *) $cppstdin $cppminus <testcpp.c >testcpp.out 2>&1;;
+ esac
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Hooray, you did! I was beginning to wonder."
+ else
+ echo 'Uh-uh. Time to get fancy...'
+ echo 'Trying (cat >/tmp/$$.c; cc -E /tmp/$$.c; rm /tmp/$$.c)'
+ cppstdin='(cat >/tmp/$$.c; cc -E /tmp/$$.c; rm /tmp/$$.c)'
+ cppminus='';
+ $cppstdin <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Eureka!."
+ else
+ dflt=blurfl
+ $echo $n "No dice. I can't find a C preprocessor. Name one: $c"
+ rp='Name a C preprocessor:'
+ . myread
+ cppstdin="$ans"
+ $cppstdin <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "OK, that will do."
+ else
+ echo "Sorry, I can't get that to work. Go find one."
+ exit 1
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+rm -f testcpp.c testcpp.out
+
+: get C preprocessor symbols handy
+echo " "
+: AIX 3.2 rejects tr '[ - ]' because the range endpoints are the same.
+echo $attrlist | $tr ' ' '\012' >Cppsym.know
+$cat <<EOSS >Cppsym
+$startsh
+case "\$1" in
+-l) list=true
+ shift
+ ;;
+esac
+unknown=''
+case "\$list\$#" in
+1|2)
+ for sym do
+ if $contains "^\$1$" Cppsym.true >/dev/null 2>&1; then
+ exit 0
+ elif $contains "^\$1$" Cppsym.know >/dev/null 2>&1; then
+ :
+ else
+ unknown="\$unknown \$sym"
+ fi
+ done
+ set X \$unknown
+ shift
+ ;;
+esac
+case \$# in
+0) exit 1;;
+esac
+echo \$* | $tr ' ' '\012' | $sed -e 's/\(.*\)/\\
+#ifdef \1\\
+exit 0; _ _ _ _\1\\ \1\\
+#endif\\
+/' >/tmp/Cppsym\$\$
+echo exit 1 >>/tmp/Cppsym\$\$
+$cppstdin $cppminus </tmp/Cppsym\$\$ >/tmp/Cppsym2\$\$
+case "\$list" in
+true) awk 'NF > 5 {print substr(\$6,2,100)}' </tmp/Cppsym2\$\$ ;;
+*)
+ sh /tmp/Cppsym2\$\$
+ status=\$?
+ ;;
+esac
+$rm -f /tmp/Cppsym\$\$ /tmp/Cppsym2\$\$
+exit \$status
+EOSS
+chmod +x Cppsym
+$eunicefix Cppsym
+echo "Your C preprocessor defines the following symbols:"
+Cppsym -l $attrlist >Cppsym.true
+cat Cppsym.true
+rmlist="$rmlist Cppsym Cppsym.know Cppsym.true"
+
+: see how many register declarations we want to use
+case "$registers" in
+'')
+ if Cppsym vax; then
+ dflt=6
+ elif Cppsym sun mc68000 mc68k m68k; then
+ dflt=10
+ elif Cppsym pyr; then
+ dflt=14
+ elif Cppsym ns32000 ns16000; then
+ dflt=5
+ elif Cppsym $smallmach; then
+ dflt=3
+ else
+ : if you have any other numbers for me, send them in
+ dflt=6
+ fi
+ ;;
+*) dflt=$registers ;;
+esac
+cat <<EOM
+
+Different C compilers on different machines pay attention to different
+numbers of register declarations. About how many register declarations in
+EOM
+$echo $n "each routine does your C compiler pay attention to? (OK to guess) [$dflt] $c"
+rp="# register declarations used? [$dflt]"
+. myread
+registers=$ans
+reg1=''
+awk "BEGIN { for (i=1; i<=16; i++) printf \"reg%d=''\n\", i}" </dev/null >.foo
+. .foo
+awk "BEGIN { for (i=1; i<=$registers; i++) printf \"reg%d=register\n\", i}" \
+ </dev/null >.foo
+. .foo
+rm -f .foo
+
+: preserve RCS keywords in files with variable substitution, grrr
+Log='$Log'
+Header='$Header'
+
+: set up shell script to do ~ expansion
+cat >filexp <<EOSS
+$startsh
+: expand filename
+case "\$1" in
+ ~/*|~)
+ echo \$1 | $sed "s|~|\${HOME-\$LOGDIR}|"
+ ;;
+ ~*)
+ if $test -f /bin/csh; then
+ /bin/csh -f -c "glob \$1"
+ echo ""
+ else
+ name=\`$expr x\$1 : '..\([^/]*\)'\`
+ dir=\`$sed -n -e "/^\${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'\$'"/\1/" -e p -e q -e '}' </etc/passwd\`
+ if $test ! -d "\$dir"; then
+ me=\`basename \$0\`
+ echo "\$me: can't locate home directory for: \$name" >&2
+ exit 1
+ fi
+ case "\$1" in
+ */*)
+ echo \$dir/\`$expr x\$1 : '..[^/]*/\(.*\)'\`
+ ;;
+ *)
+ echo \$dir
+ ;;
+ esac
+ fi
+ ;;
+*)
+ echo \$1
+ ;;
+esac
+EOSS
+chmod +x filexp
+$eunicefix filexp
+
+: determine where public executables go
+case "$bin" in
+'')
+ dflt=`loc . /bin /usr/local/bin /usr/lbin /usr/local /usr/bin`
+ ;;
+*) dflt="$bin"
+ ;;
+esac
+cont=true
+while $test "$cont" ; do
+ echo " "
+ rp="Where do you want to put the public executables? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ bin="$ans"
+ bin=`filexp $bin`
+ if test -d $bin; then
+ cont=''
+ else
+ dflt=n
+ rp="Directory $bin doesn't exist. Use that name anyway? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ dflt=''
+ case "$ans" in
+ y*) cont='';;
+ esac
+ fi
+done
+
+: determine where manual pages go
+case "$mansrc" in
+'')
+ dflt=`loc . /usr/man/man1 /usr/local/man/man1 /usr/man/mann /usr/man/local/man1 /usr/man/u_man/man1`
+ ;;
+*) dflt="$mansrc"
+ ;;
+esac
+cont=true
+while $test "$cont" ; do
+ echo " "
+ rp="Where do the manual pages (source) go? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ mansrc=`filexp "$ans"`
+ if test -d $mansrc; then
+ cont=''
+ else
+ dflt=n
+ rp="Directory $mansrc doesn't exist. Use that name anyway? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ dflt=''
+ case "$ans" in
+ y*) cont='';;
+ esac
+ fi
+done
+case "$mansrc" in
+*l)
+ manext=l
+ ;;
+*n)
+ manext=n
+ ;;
+*C)
+ manext=C
+ ;;
+*)
+ manext=1
+ ;;
+esac
+
+: see what memory models we can support
+case "$models" in
+'')
+ if Cppsym pdp11; then
+ dflt='unsplit split'
+ else
+ ans=`loc . X /lib/small /lib/large /usr/lib/small /usr/lib/large /lib/medium /usr/lib/medium /lib/huge`
+ case "$ans" in
+ X) dflt='none';;
+ *) if $test -d /lib/small || $test -d /usr/lib/small; then
+ dflt='small'
+ else
+ dflt=''
+ fi
+ if $test -d /lib/medium || $test -d /usr/lib/medium; then
+ dflt="$dflt medium"
+ fi
+ if $test -d /lib/large || $test -d /usr/lib/large; then
+ dflt="$dflt large"
+ fi
+ if $test -d /lib/huge || $test -d /usr/lib/huge; then
+ dflt="$dflt huge"
+ fi
+ esac
+ fi
+ ;;
+*) dflt="$models" ;;
+esac
+$cat <<EOM
+
+Some systems have different model sizes. On most systems they are called
+small, medium, large, and huge. On the PDP11 they are called unsplit and
+split. If your system doesn't support different memory models, say "none".
+If you wish to force everything to one memory model, say "none" here and
+put the appropriate flags later when it asks you for other cc and ld flags.
+Venix systems may wish to put "none" and let the compiler figure things out.
+(In the following question multiple model names should be space separated.)
+
+EOM
+rp="Which models are supported? [$dflt]"
+$echo $n "$rp $c"
+. myread
+models="$ans"
+
+case "$models" in
+none)
+ small=''
+ medium=''
+ large=''
+ huge=''
+ unsplit=''
+ split=''
+ ;;
+*split)
+ case "$split" in
+ '')
+ if $contains '-i' $mansrc/ld.1 >/dev/null 2>&1 || \
+ $contains '-i' $mansrc/cc.1 >/dev/null 2>&1; then
+ dflt='-i'
+ else
+ dflt='none'
+ fi
+ ;;
+ *) dflt="$split";;
+ esac
+ rp="What flag indicates separate I and D space? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ none) ans='';;
+ esac
+ split="$ans"
+ unsplit=''
+ ;;
+*large*|*small*|*medium*|*huge*)
+ case "$model" in
+ *large*)
+ case "$large" in
+ '') dflt='-Ml';;
+ *) dflt="$large";;
+ esac
+ rp="What flag indicates large model? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ none) ans='';
+ esac
+ large="$ans"
+ ;;
+ *) large='';;
+ esac
+ case "$model" in
+ *huge*)
+ case "$huge" in
+ '') dflt='-Mh';;
+ *) dflt="$huge";;
+ esac
+ rp="What flag indicates huge model? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ none) ans='';
+ esac
+ huge="$ans"
+ ;;
+ *) huge="$large";;
+ esac
+ case "$model" in
+ *medium*)
+ case "$medium" in
+ '') dflt='-Mm';;
+ *) dflt="$medium";;
+ esac
+ rp="What flag indicates medium model? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ none) ans='';
+ esac
+ medium="$ans"
+ ;;
+ *) medium="$large";;
+ esac
+ case "$model" in
+ *small*)
+ case "$small" in
+ '') dflt='none';;
+ *) dflt="$small";;
+ esac
+ rp="What flag indicates small model? [$dflt]"
+ $echo $n "$rp $c"
+ . myread
+ case "$ans" in
+ none) ans='';
+ esac
+ small="$ans"
+ ;;
+ *) small='';;
+ esac
+ ;;
+*)
+ echo "Unrecognized memory models--you may have to edit Makefile.SH"
+ ;;
+esac
+
+case "$ccflags" in
+'') dflt='none';;
+*) dflt="$ccflags";;
+esac
+echo " "
+rp="Any additional cc flags? [$dflt]"
+$echo $n "$rp $c"
+. myread
+case "$ans" in
+none) ans='';
+esac
+ccflags="$ans"
+
+case "$ldflags" in
+'') if venix; then
+ dflt='-i -z'
+ elif xenix; then
+ if test -f /usr/include/dirent.h; then
+ dflt='-ldir -lx'
+ else
+ dflt='-lx'
+ fi
+ else
+ dflt='none'
+ fi
+ ;;
+*) dflt="$ldflags";;
+esac
+echo " "
+rp="Any additional ld flags? [$dflt]"
+$echo $n "$rp $c"
+. myread
+case "$ans" in
+none) ans='';
+esac
+ldflags="$ans"
+
+: see if we need a special compiler
+echo " "
+if usg; then
+ case "$cc" in
+ '')
+ case "$Mcc" in
+ /*) dflt='Mcc'
+ ;;
+ *)
+ case "$large" in
+ -M*)
+ dflt='cc'
+ ;;
+ *)
+ if $contains '\-M' $mansrc/cc.1 >/dev/null 2>&1 ; then
+ dflt='cc -M'
+ else
+ dflt='cc'
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ *) dflt="$cc";;
+ esac
+ $cat <<'EOM'
+
+On some systems the default C compiler will not resolve multiple global
+references that happen to have the same name. On some such systems the
+"Mcc" command may be used to force these to be resolved. On other systems
+a "cc -M" command is required. (Note that the -M flag on other systems
+indicates a memory model to use!) What command will force resolution on
+EOM
+ $echo $n "this system? [$dflt] $c"
+ rp="Command to resolve multiple refs? [$dflt]"
+ . myread
+ cc="$ans"
+else
+ echo "Not a USG system--assuming cc can resolve multiple definitions."
+ cc=cc
+fi
+
+echo " "
+echo "End of configuration questions."
+echo " "
+
+: create config.sh file
+echo " "
+if test -d ../UU; then
+ cd ..
+fi
+echo "Creating config.sh..."
+$spitshell <<EOT >config.sh
+$startsh
+# config.sh
+# This file was produced by running the Configure script.
+
+d_eunice='$d_eunice'
+eunicefix='$eunicefix'
+define='$define'
+loclist='$loclist'
+expr='$expr'
+sed='$sed'
+echo='$echo'
+cat='$cat'
+rm='$rm'
+mv='$mv'
+cp='$cp'
+tail='$tail'
+tr='$tr'
+mkdir='$mkdir'
+sort='$sort'
+uniq='$uniq'
+grep='$grep'
+trylist='$trylist'
+test='$test'
+inews='$inews'
+egrep='$egrep'
+more='$more'
+pg='$pg'
+Mcc='$Mcc'
+vi='$vi'
+mailx='$mailx'
+mail='$mail'
+cpp='$cpp'
+Log='$Log'
+Header='$Header'
+bin='$bin'
+cc='$cc'
+contains='$contains'
+cppstdin='$cppstdin'
+cppminus='$cppminus'
+d_charsprf='$d_charsprf'
+d_flexfnam='$d_flexfnam'
+d_index='$d_index'
+d_voidsig='$d_voidsig'
+d_dirheader='$d_dirheader'
+d_unistd='$d_unistd'
+libc='$libc'
+mansrc='$mansrc'
+manext='$manext'
+models='$models'
+split='$split'
+small='$small'
+medium='$medium'
+large='$large'
+huge='$huge'
+ccflags='$ccflags'
+ldflags='$ldflags'
+n='$n'
+c='$c'
+package='$package'
+registers='$registers'
+reg1='$reg1'
+reg2='$reg2'
+reg3='$reg3'
+reg4='$reg4'
+reg5='$reg5'
+reg6='$reg6'
+reg7='$reg7'
+reg8='$reg8'
+reg9='$reg9'
+reg10='$reg10'
+reg11='$reg11'
+reg12='$reg12'
+reg13='$reg13'
+reg14='$reg14'
+reg15='$reg15'
+reg16='$reg16'
+spitshell='$spitshell'
+shsharp='$shsharp'
+sharpbang='$sharpbang'
+startsh='$startsh'
+voidflags='$voidflags'
+defvoidused='$defvoidused'
+CONFIG=true
+EOT
+
+CONFIG=true
+
+echo " "
+dflt=''
+fastread=''
+echo "If you didn't make any mistakes, then just type a carriage return here."
+rp="If you need to edit config.sh, do it as a shell escape here:"
+$echo $n "$rp $c"
+. UU/myread
+case "$ans" in
+'') ;;
+*) : in case they cannot read
+ eval $ans;;
+esac
+. ./config.sh
+
+echo " "
+echo "Doing variable substitutions on .SH files..."
+set x `awk '{print $1}' <MANIFEST | $grep '\.SH'`
+shift
+case $# in
+0) set x *.SH; shift;;
+esac
+if test ! -f $1; then
+ shift
+fi
+for file in $*; do
+ case "$file" in
+ */*)
+ dir=`$expr X$file : 'X\(.*\)/'`
+ file=`$expr X$file : 'X.*/\(.*\)'`
+ (cd $dir && . $file)
+ ;;
+ *)
+ . $file
+ ;;
+ esac
+done
+if test -f config.h.SH; then
+ if test ! -f config.h; then
+ : oops, they left it out of MANIFEST, probably, so do it anyway.
+ . config.h.SH
+ fi
+fi
+
+if $contains '^depend:' Makefile >/dev/null 2>&1; then
+ dflt=n
+ $cat <<EOM
+
+Now you need to generate make dependencies by running "make depend".
+You might prefer to run it in background: "make depend > makedepend.out &"
+It can take a while, so you might not want to run it right now.
+
+EOM
+ rp="Run make depend now? [$dflt]"
+ $echo $n "$rp $c"
+ . UU/myread
+ case "$ans" in
+ y*) make depend
+ echo "Now you must run a make."
+ ;;
+ *) echo "You must run 'make depend' then 'make'."
+ ;;
+ esac
+elif test -f Makefile; then
+ echo " "
+ echo "Now you must run a make."
+else
+ echo "Done."
+fi
+
+$rm -f kit*isdone
+: the following is currently useless
+cd UU && $rm -f $rmlist
+: since this removes it all anyway
+cd .. && $rm -rf UU
+: end of Configure
diff --git a/xc/util/patch/EXTERN.h b/xc/util/patch/EXTERN.h
new file mode 100644
index 000000000..1f0a6da23
--- /dev/null
+++ b/xc/util/patch/EXTERN.h
@@ -0,0 +1,21 @@
+/* oldHeader: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
+ * $XConsortium: EXTERN.h,v 2.1 94/09/09 20:04:44 gildea Exp $
+ *
+ * Revision 2.0 86/09/17 15:35:37 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#ifdef EXT
+#undef EXT
+#endif
+#define EXT extern
+
+#ifdef INIT
+#undef INIT
+#endif
+#define INIT(x)
+
+#ifdef DOINIT
+#undef DOINIT
+#endif
diff --git a/xc/util/patch/INTERN.h b/xc/util/patch/INTERN.h
new file mode 100644
index 000000000..abaa57adf
--- /dev/null
+++ b/xc/util/patch/INTERN.h
@@ -0,0 +1,19 @@
+/* oldHeader: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $
+ * $XConsortium: INTERN.h,v 2.1 94/09/09 20:08:54 gildea Exp $
+ *
+ * Revision 2.0 86/09/17 15:35:58 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#ifdef EXT
+#undef EXT
+#endif
+#define EXT
+
+#ifdef INIT
+#undef INIT
+#endif
+#define INIT(x) = x
+
+#define DOINIT
diff --git a/xc/util/patch/MANIFEST b/xc/util/patch/MANIFEST
new file mode 100644
index 000000000..05fc9417c
--- /dev/null
+++ b/xc/util/patch/MANIFEST
@@ -0,0 +1,27 @@
+After all the patch kits are run you should have the following files:
+
+Filename Kit Description
+-------- --- -----------
+Configure 1 A shell script that installs everything system dependent.
+EXTERN.h 4 Toggle .h files to look foreign.
+INTERN.h 4 Toggle .h files to look domestic.
+MANIFEST 2 This list of files.
+Makefile.SH 2 The makefile.
+README 1 Installation instructions.
+backupfile.c 4 Make Emacs style backup file names.
+backupfile.h 4 Declarations to make Emacs style backup file names.
+common.h 3 Common definitions.
+config.H 4 Sample config.h, in case Configure won't run.
+config.h.SH 3 Produces config.h.
+inp.c 3 Input file abstract data type routines.
+inp.h 3 Public defs for above.
+malloc.c 1 An optional malloc package.
+patch.c 3 The patch program.
+patch.man 2 Manual page for patch.
+patchlevel.h 4 The patch level of the patch program.
+pch.c 2 Patch abstract data type routines.
+pch.h 3 Public defs for above.
+util.c 3 Utility routines.
+util.h 3 Public defs for above.
+version.c 1 Version number routine.
+version.h 4 Public defs for above.
diff --git a/xc/util/patch/Makefile.SH b/xc/util/patch/Makefile.SH
new file mode 100644
index 000000000..ab5d049fd
--- /dev/null
+++ b/xc/util/patch/Makefile.SH
@@ -0,0 +1,116 @@
+case $CONFIG in
+ '') . config.sh ;;
+esac
+echo "Extracting Makefile (with variable substitutions)"
+cat >Makefile <<!GROK!THIS!
+# oldHeader: Makefile.SH,v 2.0.1.2 88/06/22 20:43:40 lwall Locked $
+# $XConsortium: Makefile.SH,v 3.1 94/09/09 20:04:28 gildea Exp $
+#
+# Revision 2.0.1.2 88/06/22 20:43:40 lwall
+# patch12: config.h now depends on config.h.SH
+#
+# Revision 2.0.1.1 88/06/03 15:00:48 lwall
+# patch10: upgraded to match some new metaconfig stuff
+#
+# Revision 2.0 86/09/17 15:36:15 lwall
+# Baseline for netwide release.
+#
+# Revision 1.2 86/09/08 14:07:42 lwall
+# Split up patch.c.
+#
+# Revision 1.1 86/08/01 20:18:35 lwall
+# Initial revision
+#
+
+CC = $cc
+bin = $bin
+mansrc = $mansrc
+manext = $manext
+CFLAGS = $ccflags -O
+LDFLAGS = $ldflags
+SMALL = $small
+LARGE = $large $split
+
+!GROK!THIS!
+cat >>Makefile <<'!NO!SUBS!'
+
+public = patch
+private =
+manpages = patch.man
+util = Makefile
+
+c = patch.c pch.c inp.c util.c version.c backupfile.c
+
+obj = patch.o pch.o inp.o util.o version.o backupfile.o
+
+lintflags = -phbvxac
+
+addedbyconf = Makefile Makefile.old bsd config.h config.sh eunice loc pdp11 usg v7
+
+# grrr
+SHELL = /bin/sh
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(LARGE) $*.c
+
+all: $(public) $(private) $(util)
+ @echo Done.
+
+patch: $(obj)
+ $(CC) $(LDFLAGS) $(obj) $(libs) -o patch
+
+config.h: config.h.SH
+ sh config.h.SH
+
+# won't work with csh
+install: patch
+ export PATH || exit 1
+ -mv $(bin)/patch $(bin)/patch.old
+ cp patch $(bin)/patch
+ chmod 755 $(bin)/patch
+ -cp patch.man $(mansrc)/patch.$(manext)
+
+uninstall:
+ rm -f $(bin)/patch $(mansrc)/patch.$(manext)
+ test ! -f $(bin)/patch.old || mv $(bin)/patch.old $(bin)/patch
+
+clean:
+ rm -f patch *.o core
+
+mostlyclean: clean
+
+distclean: clean
+ rm -f $(addedbyconf)
+
+realclean: distclean
+
+DISTFILES=ChangeLog Configure EXTERN.h INTERN.h MANIFEST Makefile.SH \
+README common.h config.H config.h.SH inp.c inp.h malloc.c patch.c patch.man \
+patchlevel.h pch.c pch.h util.c util.h version.c version.h backupfile.c \
+backupfile.h
+
+dist: $(DISTFILES)
+ echo patch-2.0.`sed -e '/PATCHLEVEL/!d' -e 's/[^0-9]*\([0-9a-z.]*\).*/\1/' -e q patchlevel.h` > .fname
+ rm -rf `cat .fname`
+ mkdir `cat .fname`
+ ln $(DISTFILES) `cat .fname`
+ tar chZf `cat .fname`.tar.Z `cat .fname`
+ rm -rf `cat .fname` .fname
+
+# The following lint has practically everything turned on. Unfortunately,
+# you have to wade through a lot of mumbo jumbo that can't be suppressed.
+# If the source file has a /*NOSTRICT*/ somewhere, ignore the lint message
+# for that spot.
+
+lint:
+ lint $(lintflags) $(defs) $(c) > patch.fuzz
+
+patch.o: config.h common.h patch.c inp.h pch.h util.h version.h backupfile.h
+pch.o: config.h common.h pch.c pch.h util.h
+inp.o: config.h common.h inp.c inp.h util.h
+util.o: config.h common.h util.c util.h backupfile.h
+version.o: config.h common.h version.c version.h patchlevel.h util.h
+backupfile.o: config.h backupfile.c backupfile.h
+
+!NO!SUBS!
+$eunicefix Makefile
diff --git a/xc/util/patch/Makefile.nt b/xc/util/patch/Makefile.nt
new file mode 100644
index 000000000..34c9df897
--- /dev/null
+++ b/xc/util/patch/Makefile.nt
@@ -0,0 +1,41 @@
+# $XConsortium: Makefile.nt,v 1.2 94/09/12 20:19:31 kaleb Exp $
+
+# Simple Makefile for MS Windows NT.
+
+CC = cl
+
+LIBS = crtdll.lib kernel32.lib
+
+CFLAGS = -Zi -Od -DWIN32 -D_DLL -D_MT -D__STDC__ -DX_86_ -nologo
+LDFLAGS = -link -debug:full -debugtype:cv
+
+SRCS = backupfile.c getopt.c getopt1.c inp.c patch.c pch.c util.c \
+ version.c
+
+OBJS = backupfile.obj getopt.obj getopt1.obj inp.obj patch.obj pch.obj \
+ util.obj version.obj
+
+HDRS = EXTERN.h INTERN.h backupfile.h common.h getopt.h \
+ inp.h patchlevel.h pch.h util.h version.h
+
+all: patch.exe
+
+patch.exe: $(OBJS)
+ $(CC) $(OBJS) $(LIBS) -o $@ $(LDFLAGS)
+
+.c.obj:
+ if exist $@ del $@
+ $(CC) -c -DHAVE_CONFIG_H -I. $(CPPFLAGS) $(CFLAGS) $<
+
+clean:
+ rm -f patch.exe *.obj
+
+backupfile.obj: $(HDRS)
+getopt.obj: $(HDRS)
+getopt1.obj: $(HDRS)
+inp.obj: $(HDRS)
+patch.obj: $(HDRS)
+pch.obj: $(HDRS)
+util.obj: $(HDRS)
+version.obj: $(HDRS)
+
diff --git a/xc/util/patch/README b/xc/util/patch/README
new file mode 100644
index 000000000..c8bd0e9c4
--- /dev/null
+++ b/xc/util/patch/README
@@ -0,0 +1,98 @@
+This version of patch contains modifications made by the Free Software
+Foundation, summarized in the file ChangeLog. Primarily they are to
+support the unified context diff format that GNU diff can produce, and
+to support making GNU Emacs-style backup files. They also include
+fixes for some bugs.
+
+There are two GNU variants of patch: this one, which retains Larry
+Wall's interactive Configure script and has patchlevels starting with
+`12u'; and another one that has a GNU-style non-interactive configure
+script and accepts long-named options, and has patchlevels starting
+with `12g'. Unlike the 12g variant, the 12u variant contains no
+copylefted code, for the paranoid. The two variants are otherwise the
+same. They should be available from the same places.
+
+The FSF is distributing this version of patch independently because as
+of this writing, Larry Wall has not released a new version of patch
+since mid-1988. I have heard that he has been too busy working on
+other things, like Perl.
+
+Here is a wish list of some projects to improve patch:
+
+1. Correctly handle files and patchfiles that contain NUL characters.
+This is hard to do straightforwardly; it would be less work to
+adopt a kind of escape encoding internally.
+Let ESC be a "control prefix". ESC @ stands for NUL. ESC [ stands for ESC.
+You need to crunch this when reading input (replace fgets),
+and when writing the output file (replace fputs),
+but otherwise everything can go along as it does now.
+Be careful to handle reject files correctly;
+I think they are currently created using `write', not `fputs'.
+
+2. Correctly handle patches produced by GNU diff for files that do
+not end with a newline.
+
+Please send bug reports for this version of patch to
+bug-gnu-utils@prep.ai.mit.edu as well as to Larry Wall (lwall@netlabs.com).
+ --djm@gnu.ai.mit.edu (David MacKenzie)
+
+ Patch Kit, Version 2.0
+
+ Copyright (c) 1988, Larry Wall
+
+You may copy the patch kit in whole or in part as long as you don't try to
+make money off it, or pretend that you wrote it.
+--------------------------------------------------------------------------
+
+Please read all the directions below before you proceed any further, and
+then follow them carefully. Failure to do so may void your warranty. :-)
+
+After you have unpacked your kit, you should have all the files listed
+in MANIFEST.
+
+Installation
+
+1) Run Configure. This will figure out various things about your system.
+ Some things Configure will figure out for itself, other things it will
+ ask you about. It will then proceed to make config.h, config.sh, and
+ Makefile.
+
+ You might possibly have to trim # comments from the front of Configure
+ if your sh doesn't handle them, but all other # comments will be taken
+ care of.
+
+ If you don't have sh, you'll have to rip the prototype of config.h out
+ of Configure and generate the defines by hand.
+
+2) Glance through config.h to make sure system dependencies are correct.
+ Most of them should have been taken care of by running the
+ Configure script.
+
+ If you have any additional changes to make to the C definitions, they
+ can be done in the Makefile, or in config.h. Bear in mind that they may
+ get undone next time you run Configure.
+
+3) make
+
+ This will attempt to make patch in the current directory.
+
+4) make install
+
+ This will put patch into a public directory (normally /usr/local/bin).
+ It will also try to put the man pages in a reasonable place. It will not
+ nroff the man page, however.
+
+5) Read the manual entry before running patch.
+
+6) IMPORTANT! Help save the world! Communicate any problems and
+ suggested patches to me, lwall@netlabs.com (Larry Wall),
+ so we can keep the world in sync. If you have a problem, there's
+ someone else out there who either has had or will have the same problem.
+
+ If possible, send in patches such that the patch program will apply them.
+ Context diffs are the best, then normal diffs. Don't send ed scripts--
+ I've probably changed my copy since the version you have.
+
+ Watch for patch patches in comp.sources.bugs. Patches will generally be
+ in a form usable by the patch program. Your current patch level
+ is shown in patchlevel.h.
diff --git a/xc/util/patch/backupfile.c b/xc/util/patch/backupfile.c
new file mode 100644
index 000000000..d3862e336
--- /dev/null
+++ b/xc/util/patch/backupfile.c
@@ -0,0 +1,340 @@
+/* backupfile.c -- make Emacs style backup file names
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it without restriction.
+
+ 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. */
+
+/* $XConsortium: backupfile.c,v 3.1 94/09/09 20:33:43 kaleb Exp $ */
+
+/* David MacKenzie <djm@ai.mit.edu>.
+ Some algorithms adapted from GNU Emacs. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "backupfile.h"
+#include "config.h"
+char *index ();
+char *rindex ();
+char *malloc ();
+
+#ifdef DIRENT
+#include <dirent.h>
+#ifdef direct
+#undef direct
+#endif
+#define direct dirent
+#define NLENGTH(direct) (strlen((direct)->d_name))
+#else /* !DIRENT */
+#define NLENGTH(direct) ((direct)->d_namlen)
+#ifdef USG
+#ifdef SYSNDIR
+#include <sys/ndir.h>
+#else /* !SYSNDIR */
+#include <ndir.h>
+#endif /* !SYSNDIR */
+#else /* !USG */
+#ifdef SYSDIR
+#include <sys/dir.h>
+#endif /* SYSDIR */
+#endif /* !USG */
+#endif /* !DIRENT */
+
+#ifndef isascii
+#define ISDIGIT(c) (isdigit ((unsigned char) (c)))
+#else
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#if defined (_POSIX_VERSION)
+/* POSIX does not require that the d_ino field be present, and some
+ systems do not provide it. */
+#define REAL_DIR_ENTRY(dp) 1
+#else
+#define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
+#endif
+
+/* Which type of backup file names are generated. */
+enum backup_type backup_type = none;
+
+/* The extension added to file names to produce a simple (as opposed
+ to numbered) backup file name. */
+char *simple_backup_suffix = "~";
+
+char *basename ();
+char *dirname ();
+static char *concat ();
+char *find_backup_file_name ();
+static char *make_version_name ();
+static int max_backup_version ();
+static int version_number ();
+
+/* Return NAME with any leading path stripped off. */
+
+char *
+basename (name)
+ char *name;
+{
+ char *base;
+
+ base = rindex (name, '/');
+ return base ? base + 1 : name;
+}
+
+#ifndef NODIR
+/* Return the name of the new backup file for file FILE,
+ allocated with malloc. Return 0 if out of memory.
+ FILE must not end with a '/' unless it is the root directory.
+ Do not call this function if backup_type == none. */
+
+char *
+find_backup_file_name (file)
+ char *file;
+{
+ char *dir;
+ char *base_versions;
+ int highest_backup;
+
+ if (backup_type == simple)
+ return concat (file, simple_backup_suffix);
+ base_versions = concat (basename (file), ".~");
+ if (base_versions == 0)
+ return 0;
+ dir = dirname (file);
+ if (dir == 0)
+ {
+ free (base_versions);
+ return 0;
+ }
+ highest_backup = max_backup_version (base_versions, dir);
+ free (base_versions);
+ free (dir);
+ if (backup_type == numbered_existing && highest_backup == 0)
+ return concat (file, simple_backup_suffix);
+ return make_version_name (file, highest_backup + 1);
+}
+
+/* Return the number of the highest-numbered backup file for file
+ FILE in directory DIR. If there are no numbered backups
+ of FILE in DIR, or an error occurs reading DIR, return 0.
+ FILE should already have ".~" appended to it. */
+
+static int
+max_backup_version (file, dir)
+ char *file, *dir;
+{
+ DIR *dirp;
+ struct direct *dp;
+ int highest_version;
+ int this_version;
+ int file_name_length;
+
+ dirp = opendir (dir);
+ if (!dirp)
+ return 0;
+
+ highest_version = 0;
+ file_name_length = strlen (file);
+
+ while ((dp = readdir (dirp)) != 0)
+ {
+ if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= file_name_length)
+ continue;
+
+ this_version = version_number (file, dp->d_name, file_name_length);
+ if (this_version > highest_version)
+ highest_version = this_version;
+ }
+ closedir (dirp);
+ return highest_version;
+}
+
+/* Return a string, allocated with malloc, containing
+ "FILE.~VERSION~". Return 0 if out of memory. */
+
+static char *
+make_version_name (file, version)
+ char *file;
+ int version;
+{
+ char *backup_name;
+
+ backup_name = malloc (strlen (file) + 16);
+ if (backup_name == 0)
+ return 0;
+ sprintf (backup_name, "%s.~%d~", file, version);
+ return backup_name;
+}
+
+/* If BACKUP is a numbered backup of BASE, return its version number;
+ otherwise return 0. BASE_LENGTH is the length of BASE.
+ BASE should already have ".~" appended to it. */
+
+static int
+version_number (base, backup, base_length)
+ char *base;
+ char *backup;
+ int base_length;
+{
+ int version;
+ char *p;
+
+ version = 0;
+ if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
+ {
+ for (p = &backup[base_length]; ISDIGIT (*p); ++p)
+ version = version * 10 + *p - '0';
+ if (p[0] != '~' || p[1])
+ version = 0;
+ }
+ return version;
+}
+
+/* Return the newly-allocated concatenation of STR1 and STR2.
+ If out of memory, return 0. */
+
+static char *
+concat (str1, str2)
+ char *str1, *str2;
+{
+ char *newstr;
+ char str1_length = strlen (str1);
+
+ newstr = malloc (str1_length + strlen (str2) + 1);
+ if (newstr == 0)
+ return 0;
+ strcpy (newstr, str1);
+ strcpy (newstr + str1_length, str2);
+ return newstr;
+}
+
+/* Return the leading directories part of PATH,
+ allocated with malloc. If out of memory, return 0.
+ Assumes that trailing slashes have already been
+ removed. */
+
+char *
+dirname (path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int length; /* Length of result, not including NUL. */
+
+ slash = rindex (path, '/');
+ if (slash == 0)
+ {
+ /* File is in the current directory. */
+ path = ".";
+ length = 1;
+ }
+ else
+ {
+ /* Remove any trailing slashes from result. */
+ while (slash > path && *slash == '/')
+ --slash;
+
+ length = slash - path + 1;
+ }
+ newpath = malloc (length + 1);
+ if (newpath == 0)
+ return 0;
+ strncpy (newpath, path, length);
+ newpath[length] = 0;
+ return newpath;
+}
+
+/* If ARG is an unambiguous match for an element of the
+ null-terminated array OPTLIST, return the index in OPTLIST
+ of the matched element, else -1 if it does not match any element
+ or -2 if it is ambiguous (is a prefix of more than one element). */
+
+int
+argmatch (arg, optlist)
+ char *arg;
+ char **optlist;
+{
+ int i; /* Temporary index in OPTLIST. */
+ int arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen (arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; optlist[i]; i++)
+ {
+ if (!strncmp (optlist[i], arg, arglen))
+ {
+ if (strlen (optlist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ /* Second nonexact match found. */
+ ambiguous = 1;
+ }
+ }
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
+}
+
+/* Error reporting for argmatch.
+ KIND is a description of the type of entity that was being matched.
+ VALUE is the invalid value that was given.
+ PROBLEM is the return value from argmatch. */
+
+void
+invalid_arg (kind, value, problem)
+ char *kind;
+ char *value;
+ int problem;
+{
+ fprintf (stderr, "patch: ");
+ if (problem == -1)
+ fprintf (stderr, "invalid");
+ else /* Assume -2. */
+ fprintf (stderr, "ambiguous");
+ fprintf (stderr, " %s `%s'\n", kind, value);
+}
+
+static char *backup_args[] =
+{
+ "never", "simple", "nil", "existing", "t", "numbered", 0
+};
+
+static enum backup_type backup_types[] =
+{
+ simple, simple, numbered_existing, numbered_existing, numbered, numbered
+};
+
+/* Return the type of backup indicated by VERSION.
+ Unique abbreviations are accepted. */
+
+enum backup_type
+get_version (version)
+ char *version;
+{
+ int i;
+
+ if (version == 0 || *version == 0)
+ return numbered_existing;
+ i = argmatch (version, backup_args);
+ if (i >= 0)
+ return backup_types[i];
+ invalid_arg ("version control type", version, i);
+ exit (1);
+}
+#endif /* NODIR */
diff --git a/xc/util/patch/backupfile.h b/xc/util/patch/backupfile.h
new file mode 100644
index 000000000..43240a130
--- /dev/null
+++ b/xc/util/patch/backupfile.h
@@ -0,0 +1,37 @@
+/* backupfile.h -- declarations for making Emacs style backup file names
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it without restriction.
+
+ 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. */
+
+/* When to make backup files. */
+enum backup_type
+{
+ /* Never make backups. */
+ none,
+
+ /* Make simple backups of every file. */
+ simple,
+
+ /* Make numbered backups of files that already have numbered backups,
+ and simple backups of the others. */
+ numbered_existing,
+
+ /* Make numbered backups of every file. */
+ numbered
+};
+
+extern enum backup_type backup_type;
+extern char *simple_backup_suffix;
+
+#ifdef __STDC__
+char *find_backup_file_name (char *file);
+enum backup_type get_version (char *version);
+#else
+char *find_backup_file_name ();
+enum backup_type get_version ();
+#endif
diff --git a/xc/util/patch/common.h b/xc/util/patch/common.h
new file mode 100644
index 000000000..7209d6f90
--- /dev/null
+++ b/xc/util/patch/common.h
@@ -0,0 +1,214 @@
+/* oldHeader: common.h,v 2.0.1.2 88/06/22 20:44:53 lwall Locked $
+ * $XConsortium: common.h,v 3.3 94/09/14 21:13:08 gildea Exp $
+ *
+ * Revision 2.0.1.2 88/06/22 20:44:53 lwall
+ * patch12: sprintf was declared wrong
+ *
+ * Revision 2.0.1.1 88/06/03 15:01:56 lwall
+ * patch10: support for shorter extensions.
+ *
+ * Revision 2.0 86/09/17 15:36:39 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#define DEBUGGING
+
+#define VOIDUSED 7
+#include "config.h"
+
+/* shut lint up about the following when return value ignored */
+
+#define Signal (void)signal
+#define Unlink (void)unlink
+#define Lseek (void)lseek
+#define Fseek (void)fseek
+#define Fstat (void)fstat
+#define Pclose (void)pclose
+#define Close (void)close
+#define Fclose (void)fclose
+#define Fflush (void)fflush
+#define Sprintf (void)sprintf
+#define Mktemp (void)mktemp
+#define Strcpy (void)strcpy
+#define Strcat (void)strcat
+
+/* NeXT declares malloc and realloc incompatibly from us in some of
+ these files. Temporarily redefine them to prevent errors. */
+#define malloc system_malloc
+#define realloc system_realloc
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <signal.h>
+#include <fcntl.h>
+#undef malloc
+#undef realloc
+
+#ifdef WIN32
+#include "winnt.h"
+#endif
+
+/* constants */
+
+/* AIX predefines these. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define TRUE (1)
+#define FALSE (0)
+
+#define MAXHUNKSIZE 100000 /* is this enough lines? */
+#define INITHUNKMAX 125 /* initial dynamic allocation size */
+#define MAXLINELEN 1024
+#define BUFFERSIZE 1024
+
+#define SCCSPREFIX "s."
+#define GET "get %s"
+#define GET_LOCKED "get -e %s"
+#define SCCSDIFF "get -p %s | diff - %s >/dev/null"
+
+#define RCSSUFFIX ",v"
+#define CHECKOUT "co %s"
+#define CHECKOUT_LOCKED "co -l %s"
+#define RCSDIFF "rcsdiff %s > /dev/null"
+
+#ifdef FLEXFILENAMES
+#define ORIGEXT ".orig"
+#define REJEXT ".rej"
+#else
+#define ORIGEXT "~"
+#define REJEXT "#"
+#endif
+
+/* handy definitions */
+
+#define Null(t) ((t)0)
+#define Nullch Null(char *)
+#define Nullfp Null(FILE *)
+#define Nulline Null(LINENUM)
+
+#define Ctl(ch) ((ch) & 037)
+
+#define strNE(s1,s2) (strcmp(s1, s2))
+#define strEQ(s1,s2) (!strcmp(s1, s2))
+#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
+#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
+
+/* typedefs */
+
+typedef char bool;
+typedef long LINENUM; /* must be signed */
+typedef unsigned MEM; /* what to feed malloc */
+
+/* globals */
+
+EXT int Argc; /* guess */
+EXT char **Argv;
+EXT int Argc_last; /* for restarting plan_b */
+EXT char **Argv_last;
+
+EXT struct stat filestat; /* file statistics area */
+EXT int filemode INIT(0644);
+
+EXT char buf[MAXLINELEN]; /* general purpose buffer */
+EXT FILE *ofp INIT(Nullfp); /* output file pointer */
+EXT FILE *rejfp INIT(Nullfp); /* reject file pointer */
+
+#ifndef WIN32
+EXT int myuid; /* cache getuid return value */
+#endif
+
+EXT bool using_plan_a INIT(TRUE); /* try to keep everything in memory */
+EXT bool out_of_mem INIT(FALSE); /* ran out of memory in plan a */
+
+#define MAXFILEC 2
+EXT int filec INIT(0); /* how many file arguments? */
+EXT char *filearg[MAXFILEC];
+EXT bool ok_to_create_file INIT(FALSE);
+EXT char *bestguess INIT(Nullch); /* guess at correct filename */
+
+EXT char *outname INIT(Nullch);
+EXT char rejname[128];
+
+EXT char *origprae INIT(Nullch);
+
+EXT char *TMPOUTNAME;
+EXT char *TMPINNAME;
+EXT char *TMPREJNAME;
+EXT char *TMPPATNAME;
+EXT bool toutkeep INIT(FALSE);
+EXT bool trejkeep INIT(FALSE);
+
+EXT LINENUM last_offset INIT(0);
+#ifdef DEBUGGING
+EXT int debug INIT(0);
+#endif
+EXT LINENUM maxfuzz INIT(2);
+EXT bool force INIT(FALSE);
+EXT bool batch INIT(FALSE);
+EXT bool verbose INIT(TRUE);
+EXT bool reverse INIT(FALSE);
+EXT bool noreverse INIT(FALSE);
+EXT bool skip_rest_of_patch INIT(FALSE);
+EXT int strippath INIT(957);
+EXT bool canonicalize INIT(FALSE);
+
+#define CONTEXT_DIFF 1
+#define NORMAL_DIFF 2
+#define ED_DIFF 3
+#define NEW_CONTEXT_DIFF 4
+#define UNI_DIFF 5
+EXT int diff_type INIT(0);
+
+EXT bool do_defines INIT(FALSE); /* patch using ifdef, ifndef, etc. */
+EXT char if_defined[128]; /* #ifdef xyzzy */
+EXT char not_defined[128]; /* #ifndef xyzzy */
+EXT char else_defined[] INIT("#else\n");/* #else */
+EXT char end_defined[128]; /* #endif xyzzy */
+
+EXT char *revision INIT(Nullch); /* prerequisite revision, if any */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+FILE *popen();
+char *malloc();
+char *realloc();
+long atol();
+char *getenv();
+char *strcpy();
+char *strcat();
+char *rindex();
+#if 0
+long lseek();
+#endif
+char *mktemp();
+#if 0 /* This can cause a prototype conflict. */
+#ifdef CHARSPRINTF
+char *sprintf();
+#else
+int sprintf();
+#endif
+#endif
+
+#ifndef WIN32
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#else
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
+#endif
+
+
diff --git a/xc/util/patch/config.H b/xc/util/patch/config.H
new file mode 100644
index 000000000..93cdf0327
--- /dev/null
+++ b/xc/util/patch/config.H
@@ -0,0 +1,33 @@
+/* config.h
+ * This file was produced by running the Configure script.
+ * Feel free to modify any of this as the need arises.
+ */
+
+
+#/*undef EUNICE /* no file linking? */
+#/*undef VMS
+
+#/*undef index strchr /* cultural */
+#/*undef rindex strrchr /* differences? */
+
+#/*undef void int /* is void to be avoided? */
+
+/* How many register declarations are paid attention to? */
+
+#define Reg1 register
+#define Reg2 register
+#define Reg3 register
+#define Reg4 register
+#define Reg5 register
+#define Reg6 register
+#define Reg7
+#define Reg8
+#define Reg9
+#define Reg10
+#define Reg11
+#define Reg12
+#define Reg13
+#define Reg14
+#define Reg15
+#define Reg16
+
diff --git a/xc/util/patch/config.h.SH b/xc/util/patch/config.h.SH
new file mode 100644
index 000000000..e34562fcc
--- /dev/null
+++ b/xc/util/patch/config.h.SH
@@ -0,0 +1,146 @@
+case $CONFIG in
+'')
+ if test ! -f config.sh; then
+ ln ../config.sh . || \
+ ln ../../config.sh . || \
+ ln ../../../config.sh . || \
+ (echo "Can't find config.sh."; exit 1)
+ echo "Using config.sh from above..."
+ fi
+ . ./config.sh
+ ;;
+esac
+echo "Extracting config.h (with variable substitutions)"
+cat <<!GROK!THIS! >config.h
+/* config.h
+ * This file was produced by running the config.h.SH script, which
+ * gets its values from config.sh, which is generally produced by
+ * running Configure.
+ *
+ * Feel free to modify any of this as the need arises. Note, however,
+ * that running config.h.SH again will wipe out any changes you've made.
+ * For a more permanent change edit config.sh and rerun config.h.SH.
+ */
+
+
+/* EUNICE:
+ * This symbol, if defined, indicates that the program is being compiled
+ * under the EUNICE package under VMS. The program will need to handle
+ * things like files that don't go away the first time you unlink them,
+ * due to version numbering. It will also need to compensate for lack
+ * of a respectable link() command.
+ */
+/* VMS:
+ * This symbol, if defined, indicates that the program is running under
+ * VMS. It is currently only set in conjunction with the EUNICE symbol.
+ */
+#$d_eunice EUNICE /**/
+#$d_eunice VMS /**/
+
+/* CPPSTDIN:
+ * This symbol contains the first part of the string which will invoke
+ * the C preprocessor on the standard input and produce to standard
+ * output. Typical value of "cc -E" or "/lib/cpp".
+ */
+/* CPPMINUS:
+ * This symbol contains the second part of the string which will invoke
+ * the C preprocessor on the standard input and produce to standard
+ * output. This symbol will have the value "-" if CPPSTDIN needs a minus
+ * to specify standard input, otherwise the value is "".
+ */
+#define CPPSTDIN "$cppstdin"
+#define CPPMINUS "$cppminus"
+
+/* CHARSPRINTF:
+ * This symbol is defined if this system declares "char *sprintf()" in
+ * stdio.h. The trend seems to be to declare it as "int sprintf()". It
+ * is up to the package author to declare sprintf correctly based on the
+ * symbol.
+ */
+/* #$d_charsprf CHARSPRINTF /**/
+
+/* FLEXFILENAMES:
+ * This symbol, if defined, indicates that the system supports filenames
+ * longer than 14 characters.
+ */
+#$d_flexfnam FLEXFILENAMES /**/
+
+/* index:
+ * This preprocessor symbol is defined, along with rindex, if the system
+ * uses the strchr and strrchr routines instead.
+ */
+/* rindex:
+ * This preprocessor symbol is defined, along with index, if the system
+ * uses the strchr and strrchr routines instead.
+ */
+#$d_index index strchr /* cultural */
+#$d_index rindex strrchr /* differences? */
+
+/* VOIDSIG:
+ * This symbol is defined if this system declares "void (*signal())()" in
+ * signal.h. The old way was to declare it as "int (*signal())()". It
+ * is up to the package author to declare things correctly based on the
+ * symbol.
+ */
+#$d_voidsig VOIDSIG /**/
+
+/* DIRHEADER:
+ * This definition indicates which directory library header to use.
+ */
+$d_dirheader
+
+/* HAVE_UNISTD_H:
+ * This is defined if the system has unistd.h.
+ */
+#$d_unistd HAVE_UNISTD_H /**/
+
+/* Reg1:
+ * This symbol, along with Reg2, Reg3, etc. is either the word "register"
+ * or null, depending on whether the C compiler pays attention to this
+ * many register declarations. The intent is that you don't have to
+ * order your register declarations in the order of importance, so you
+ * can freely declare register variables in sub-blocks of code and as
+ * function parameters. Do not use Reg<n> more than once per routine.
+ */
+
+#define Reg1 $reg1 /**/
+#define Reg2 $reg2 /**/
+#define Reg3 $reg3 /**/
+#define Reg4 $reg4 /**/
+#define Reg5 $reg5 /**/
+#define Reg6 $reg6 /**/
+#define Reg7 $reg7 /**/
+#define Reg8 $reg8 /**/
+#define Reg9 $reg9 /**/
+#define Reg10 $reg10 /**/
+#define Reg11 $reg11 /**/
+#define Reg12 $reg12 /**/
+#define Reg13 $reg13 /**/
+#define Reg14 $reg14 /**/
+#define Reg15 $reg15 /**/
+#define Reg16 $reg16 /**/
+
+/* VOIDFLAGS:
+ * This symbol indicates how much support of the void type is given by this
+ * compiler. What various bits mean:
+ *
+ * 1 = supports declaration of void
+ * 2 = supports arrays of pointers to functions returning void
+ * 4 = supports comparisons between pointers to void functions and
+ * addresses of void functions
+ *
+ * The package designer should define VOIDUSED to indicate the requirements
+ * of the package. This can be done either by #defining VOIDUSED before
+ * including config.h, or by defining defvoidused in Myinit.U. If the
+ * level of void support necessary is not present, defines void to int.
+ */
+#ifndef VOIDUSED
+#define VOIDUSED $defvoidused
+#endif
+#define VOIDFLAGS $voidflags
+#if (VOIDFLAGS & VOIDUSED) != VOIDUSED
+#$define void int /* is void to be avoided? */
+#$define M_VOID /* Xenix strikes again */
+#endif
+
+!GROK!THIS!
diff --git a/xc/util/patch/config.h.nt b/xc/util/patch/config.h.nt
new file mode 100644
index 000000000..b346523b9
--- /dev/null
+++ b/xc/util/patch/config.h.nt
@@ -0,0 +1,82 @@
+
+/* $XConsortium: config.h.nt,v 1.1 94/09/09 20:26:16 kaleb Exp $ */
+
+/* Portability variables. -*- C -*- */
+
+/* Define if the system does not support the `const' keyword. */
+#undef const
+
+/* Define if the system supports file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if the system has pathconf(). */
+#undef HAVE_PATHCONF
+
+/* Define if the system has strerror(). */
+#define HAVE_STRERROR
+
+/* Define if the system has ANSI C header files and library functions. */
+#define STDC_HEADERS
+
+/* Define if the system uses strchr instead of index
+ and strrchr instead of rindex. */
+#define HAVE_STRING_H
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#define index strchr
+#define rindex strrchr
+#endif
+
+/* Define if the system has unistd.h. */
+#undef HAVE_UNISTD_H
+
+/* Define as either int or void -- the type that signal handlers return. */
+#undef RETSIGTYPE
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+/* Which directory library header to use. */
+#undef DIRENT /* dirent.h */
+#undef SYSNDIR /* sys/ndir.h */
+#undef SYSDIR /* sys/dir.h */
+#undef NDIR /* ndir.h */
+#define DIRECT /* Windoze NT direct.h */
+#define NODIR /* none -- don't make numbered backup files */
+
+/* Define if the system lets you pass fewer arguments to a function
+ than the function actually accepts (in the absence of a prototype).
+ Defining it makes I/O calls slightly more efficient.
+ You need not bother defining it unless your C preprocessor chokes on
+ multi-line arguments to macros. */
+#undef CANVARARG
+
+/* Define Reg* as either `register' or nothing, depending on whether
+ the C compiler pays attention to this many register declarations.
+ The intent is that you don't have to order your register declarations
+ in the order of importance, so you can freely declare register variables
+ in sub-blocks of code and as function parameters.
+ Do not use Reg<n> more than once per routine.
+
+ These don't really matter a lot, since most modern C compilers ignore
+ register declarations and often do a better job of allocating
+ registers than people do. */
+
+#define Reg1
+#define Reg2
+#define Reg3
+#define Reg4
+#define Reg5
+#define Reg6
+#define Reg7
+#define Reg8
+#define Reg9
+#define Reg10
+#define Reg11
+#define Reg12
+#define Reg13
+#define Reg14
+#define Reg15
+#define Reg16
+
diff --git a/xc/util/patch/inp.c b/xc/util/patch/inp.c
new file mode 100644
index 000000000..20e5709a7
--- /dev/null
+++ b/xc/util/patch/inp.c
@@ -0,0 +1,387 @@
+/* $XConsortium: inp.c,v 3.4 94/09/14 21:18:35 gildea Exp $
+ *
+ * Revision 3.1 94/03/29 13:39:15 gildea
+ * check that a patch that creates a file has not already been applied.
+ * version "XC1"
+ *
+ * Revision 2.0.1.1 88/06/03 15:06:13 lwall
+ * patch10: made a little smarter about sccs files
+ *
+ * Revision 2.0 86/09/17 15:37:02 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "pch.h"
+#include "INTERN.h"
+#include "inp.h"
+
+/* Input-file-with-indexable-lines abstract type */
+
+static long i_size; /* size of the input file */
+static char *i_womp; /* plan a buffer for entire file */
+static char **i_ptr; /* pointers to lines in i_womp */
+
+static int tifd = -1; /* plan b virtual string array */
+static char *tibuf[2]; /* plan b buffers */
+static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
+static LINENUM lines_per_buf; /* how many lines per buffer */
+static int tireclen; /* length of records in tmp file */
+
+/* New patch--prepare to edit another file. */
+
+void
+re_input()
+{
+ if (using_plan_a) {
+ i_size = 0;
+#ifndef lint
+ if (i_ptr != Null(char**))
+ free((char *)i_ptr);
+#endif
+ if (i_womp != Nullch)
+ free(i_womp);
+ i_womp = Nullch;
+ i_ptr = Null(char **);
+ }
+ else {
+ using_plan_a = TRUE; /* maybe the next one is smaller */
+ Close(tifd);
+ tifd = -1;
+ free(tibuf[0]);
+ free(tibuf[1]);
+ tibuf[0] = tibuf[1] = Nullch;
+ tiline[0] = tiline[1] = -1;
+ tireclen = 0;
+ }
+}
+
+/* Constuct the line index, somehow or other. */
+
+void
+scan_input(filename)
+char *filename;
+{
+ if (!plan_a(filename))
+ plan_b(filename);
+ if (verbose) {
+ say3("Patching file %s using Plan %s...\n", filename,
+ (using_plan_a ? "A" : "B") );
+ }
+}
+
+/* Try keeping everything in memory. */
+
+bool
+plan_a(filename)
+char *filename;
+{
+ int ifd, statfailed;
+ Reg1 char *s;
+ Reg2 LINENUM iline;
+ char lbuf[MAXLINELEN];
+ int output_elsewhere = strcmp(filename, outname);
+
+ statfailed = stat(filename, &filestat);
+ if (statfailed && ok_to_create_file) {
+ if (verbose)
+ say2("(Creating file %s...)\n",filename);
+ makedirs(filename, TRUE);
+ close(creat(filename, 0666));
+ statfailed = stat(filename, &filestat);
+ } else if (!statfailed && ok_to_create_file) {
+ /* ok_to_create_file means the file either doesn't exist
+ or is zero-length. Since there is no context in the patch,
+ avoid doubling the file if the patch has already been applied
+ by bailing out here if these conditions are not met. */
+ if (filestat.st_size != 0)
+ fatal2("supposedly new file \"%s\" already exists\n", filename);
+ }
+#ifndef WIN32
+ /* For nonexistent or read-only files, look for RCS or SCCS versions. */
+ if (statfailed
+ || (! output_elsewhere
+ && (/* No one can write to it. */
+ (filestat.st_mode & 0222) == 0
+ /* I can't write to it. */
+ || ((filestat.st_mode & 0022) == 0
+ && filestat.st_uid != myuid)))) {
+ struct stat cstat;
+ char *cs = Nullch;
+ char *filebase;
+ int pathlen;
+
+ filebase = basename(filename);
+ pathlen = filebase - filename;
+
+ /* Put any leading path into `s'.
+ Leave room in lbuf for the diff command. */
+ s = lbuf + 20;
+ strncpy(s, filename, pathlen);
+
+#define try(f, a1, a2) (Sprintf(s + pathlen, f, a1, a2), stat(s, &cstat) == 0)
+ if ( try("RCS/%s%s", filebase, RCSSUFFIX)
+ || try("RCS/%s" , filebase, 0)
+ || try( "%s%s", filebase, RCSSUFFIX)) {
+ Sprintf(buf, output_elsewhere?CHECKOUT:CHECKOUT_LOCKED, filename);
+ Sprintf(lbuf, RCSDIFF, filename);
+ cs = "RCS";
+ } else if ( try("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try( "%s%s", SCCSPREFIX, filebase)) {
+ Sprintf(buf, output_elsewhere?GET:GET_LOCKED, s);
+ Sprintf(lbuf, SCCSDIFF, s, filename);
+ cs = "SCCS";
+ } else if (statfailed)
+ fatal2("can't find %s\n", filename);
+ /* else we can't write to it but it's not under a version
+ control system, so just proceed. */
+ if (cs) {
+ if (!statfailed) {
+ if ((filestat.st_mode & 0222) != 0)
+ /* The owner can write to it. */
+ fatal3("file %s seems to be locked by somebody else under %s\n",
+ filename, cs);
+ /* It might be checked out unlocked. See if it's safe to
+ check out the default version locked. */
+ if (verbose)
+ say3("Comparing file %s to default %s version...\n",
+ filename, cs);
+ if (system(lbuf))
+ fatal3("can't check out file %s: differs from default %s version\n",
+ filename, cs);
+ }
+ if (verbose)
+ say3("Checking out file %s from %s...\n", filename, cs);
+ if (system(buf) || stat(filename, &filestat))
+ fatal3("can't check out file %s from %s\n", filename, cs);
+ }
+ }
+#endif
+ filemode = filestat.st_mode;
+ if (!S_ISREG(filemode))
+ fatal2("%s is not a normal file--can't patch\n", filename);
+ i_size = filestat.st_size;
+ if (out_of_mem) {
+ set_hunkmax(); /* make sure dynamic arrays are allocated */
+ out_of_mem = FALSE;
+ return FALSE; /* force plan b because plan a bombed */
+ }
+#ifdef lint
+ i_womp = Nullch;
+#else
+ i_womp = malloc((MEM)(i_size+2)); /* lint says this may alloc less than */
+ /* i_size, but that's okay, I think. */
+#endif
+ if (i_womp == Nullch)
+ return FALSE;
+#ifndef WIN32
+ if ((ifd = open(filename, 0)) < 0)
+#else
+ if ((ifd = open(filename, _O_RDONLY | _O_BINARY)) < 0)
+#endif
+ pfatal2("can't open file %s", filename);
+#ifndef lint
+ if (read(ifd, i_womp, (int)i_size) != i_size) {
+ Close(ifd); /* probably means i_size > 15 or 16 bits worth */
+ free(i_womp); /* at this point it doesn't matter if i_womp was */
+ return FALSE; /* undersized. */
+ }
+#endif
+ Close(ifd);
+ if (i_size && i_womp[i_size-1] != '\n')
+ i_womp[i_size++] = '\n';
+ i_womp[i_size] = '\0';
+
+ /* count the lines in the buffer so we know how many pointers we need */
+
+ iline = 0;
+ for (s=i_womp; *s; s++) {
+ if (*s == '\n')
+ iline++;
+ }
+#ifdef lint
+ i_ptr = Null(char**);
+#else
+ i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
+#endif
+ if (i_ptr == Null(char **)) { /* shucks, it was a near thing */
+ free((char *)i_womp);
+ return FALSE;
+ }
+
+ /* now scan the buffer and build pointer array */
+
+ iline = 1;
+ i_ptr[iline] = i_womp;
+ for (s=i_womp; *s; s++) {
+ if (*s == '\n')
+ i_ptr[++iline] = s+1; /* these are NOT null terminated */
+ }
+ input_lines = iline - 1;
+
+ /* now check for revision, if any */
+
+ if (revision != Nullch) {
+ if (!rev_in_string(i_womp)) {
+ if (force) {
+ if (verbose)
+ say2(
+"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
+ revision);
+ }
+ else if (batch) {
+ fatal2(
+"this file doesn't appear to be the %s version--aborting.\n", revision);
+ }
+ else {
+ ask2(
+"This file doesn't appear to be the %s version--patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal1("aborted\n");
+ }
+ }
+ else if (verbose)
+ say2("Good. This file appears to be the %s version.\n",
+ revision);
+ }
+ return TRUE; /* plan a will work */
+}
+
+/* Keep (virtually) nothing in memory. */
+
+void
+plan_b(filename)
+char *filename;
+{
+ Reg3 FILE *ifp;
+ Reg1 int i = 0;
+ Reg2 int maxlen = 1;
+ Reg4 bool found_revision = (revision == Nullch);
+
+ using_plan_a = FALSE;
+#ifndef WIN32
+ if ((ifp = fopen(filename, "r")) == Nullfp)
+#else
+ if ((ifp = fopen(filename, "rb")) == Nullfp)
+#endif
+ pfatal2("can't open file %s", filename);
+#ifndef WIN32
+ if ((tifd = creat(TMPINNAME, 0666)) < 0)
+#else
+ if ((tifd = open(TMPINNAME, _O_CREAT | _O_TRUNC | _O_BINARY, _S_IWRITE)) < 0)
+#endif
+ pfatal2("can't open file %s", TMPINNAME);
+ while (fgets(buf, sizeof buf, ifp) != Nullch) {
+ if (revision != Nullch && !found_revision && rev_in_string(buf))
+ found_revision = TRUE;
+ if ((i = strlen(buf)) > maxlen)
+ maxlen = i; /* find longest line */
+ }
+ if (revision != Nullch) {
+ if (!found_revision) {
+ if (force) {
+ if (verbose)
+ say2(
+"Warning: this file doesn't appear to be the %s version--patching anyway.\n",
+ revision);
+ }
+ else if (batch) {
+ fatal2(
+"this file doesn't appear to be the %s version--aborting.\n", revision);
+ }
+ else {
+ ask2(
+"This file doesn't appear to be the %s version--patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal1("aborted\n");
+ }
+ }
+ else if (verbose)
+ say2("Good. This file appears to be the %s version.\n",
+ revision);
+ }
+ Fseek(ifp, 0L, 0); /* rewind file */
+ lines_per_buf = BUFFERSIZE / maxlen;
+ tireclen = maxlen;
+ tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
+ tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
+ if (tibuf[1] == Nullch)
+ fatal1("out of memory\n");
+ for (i=1; ; i++) {
+ if (! (i % lines_per_buf)) /* new block */
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ pfatal1("can't write temp file");
+ if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
+ == Nullch) {
+ input_lines = i - 1;
+ if (i % lines_per_buf)
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ pfatal1("can't write temp file");
+ break;
+ }
+ }
+ Fclose(ifp);
+ Close(tifd);
+ if ((tifd = open(TMPINNAME, 0)) < 0) {
+ pfatal2("can't reopen file %s", TMPINNAME);
+ }
+}
+
+/* Fetch a line from the input file, \n terminated, not necessarily \0. */
+
+char *
+ifetch(line,whichbuf)
+Reg1 LINENUM line;
+int whichbuf; /* ignored when file in memory */
+{
+ if (line < 1 || line > input_lines)
+ return "";
+ if (using_plan_a)
+ return i_ptr[line];
+ else {
+ LINENUM offline = line % lines_per_buf;
+ LINENUM baseline = line - offline;
+
+ if (tiline[0] == baseline)
+ whichbuf = 0;
+ else if (tiline[1] == baseline)
+ whichbuf = 1;
+ else {
+ tiline[whichbuf] = baseline;
+#ifndef lint /* complains of long accuracy */
+ Lseek(tifd, (long)baseline / lines_per_buf * BUFFERSIZE, 0);
+#endif
+ if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
+ pfatal2("error reading tmp file %s", TMPINNAME);
+ }
+ return tibuf[whichbuf] + (tireclen*offline);
+ }
+}
+
+/* True if the string argument contains the revision number we want. */
+
+bool
+rev_in_string(string)
+char *string;
+{
+ Reg1 char *s;
+ Reg2 int patlen;
+
+ if (revision == Nullch)
+ return TRUE;
+ patlen = strlen(revision);
+ if (strnEQ(string,revision,patlen) && isspace(string[patlen]))
+ return TRUE;
+ for (s = string; *s; s++) {
+ if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
+ isspace(s[patlen+1] )) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/xc/util/patch/inp.h b/xc/util/patch/inp.h
new file mode 100644
index 000000000..6fd4ec8f2
--- /dev/null
+++ b/xc/util/patch/inp.h
@@ -0,0 +1,18 @@
+/* oldHeader: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
+ * $XConsortium: inp.h,v 2.1 94/09/09 20:04:28 gildea Exp $
+ *
+ * Revision 2.0 86/09/17 15:37:25 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+EXT LINENUM input_lines INIT(0); /* how long is input file in lines */
+EXT LINENUM last_frozen_line INIT(0); /* how many input lines have been */
+ /* irretractibly output */
+
+bool rev_in_string();
+void scan_input();
+bool plan_a(); /* returns false if insufficient memory */
+void plan_b();
+char *ifetch();
+
diff --git a/xc/util/patch/malloc.c b/xc/util/patch/malloc.c
new file mode 100644
index 000000000..a8436c440
--- /dev/null
+++ b/xc/util/patch/malloc.c
@@ -0,0 +1,469 @@
+/*
+ * @(#)nmalloc.c 1 (Caltech) 2/21/82
+ *
+ * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs
+ *
+ * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD.
+ *
+ * This is a very fast storage allocator. It allocates blocks of a small
+ * number of different sizes, and keeps free lists of each size. Blocks
+ * that don't exactly fit are passed up to the next larger size. In this
+ * implementation, the available sizes are (2^n)-4 (or -16) bytes long.
+ * This is designed for use in a program that uses vast quantities of
+ * memory, but bombs when it runs out. To make it a little better, it
+ * warns the user when he starts to get near the end.
+ *
+ * June 84, ACT: modified rcheck code to check the range given to malloc,
+ * rather than the range determined by the 2-power used.
+ *
+ * Jan 85, RMS: calls malloc_warning to issue warning on nearly full.
+ * No longer Emacs-specific; can serve as all-purpose malloc for GNU.
+ * You should call malloc_init to reinitialize after loading dumped Emacs.
+ * Call malloc_stats to get info on memory stats if MSTATS turned on.
+ * realloc knows how to return same block given, just changing its size,
+ * if the power of 2 is correct.
+ */
+
+/*
+ * nextf[i] is the pointer to the next free block of size 2^(i+3). The
+ * smallest allocatable block is 8 bytes. The overhead information will
+ * go in the first int of the block, and the returned pointer will point
+ * to the second.
+ *
+#ifdef MSTATS
+ * nmalloc[i] is the difference between the number of mallocs and frees
+ * for a given block size.
+#endif
+ */
+
+#define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */
+#define ISFREE ((char) 0x54) /* magic byte that implies free block */
+ /* this is for error checking only */
+
+extern char etext;
+
+/* end of the program; can be changed by calling init_malloc */
+static char *endofpure = &etext;
+
+#ifdef MSTATS
+static int nmalloc[30];
+static int nmal, nfre;
+#endif /* MSTATS */
+
+/* If range checking is not turned on, all we have is a flag indicating
+ whether memory is allocated, an index in nextf[], and a size field; to
+ realloc() memory we copy either size bytes or 1<<(index+3) bytes depending
+ on whether the former can hold the exact size (given the value of
+ 'index'). If range checking is on, we always need to know how much space
+ is allocated, so the 'size' field is never used. */
+
+struct mhead {
+ char mh_alloc; /* ISALLOC or ISFREE */
+ char mh_index; /* index in nextf[] */
+/* Remainder are valid only when block is allocated */
+ unsigned short mh_size; /* size, if < 0x10000 */
+#ifdef rcheck
+ unsigned mh_nbytes; /* number of bytes allocated */
+ int mh_magic4; /* should be == MAGIC4 */
+#endif /* rcheck */
+ };
+
+/* Access free-list pointer of a block.
+ It is stored at block + 4.
+ This is not a field in the mhead structure
+ because we want sizeof (struct mhead)
+ to describe the overhead for when the block is in use,
+ and we do not want the free-list pointer to count in that. */
+
+#define CHAIN(a) \
+ (*(struct mhead **) (sizeof (char *) + (char *) (a)))
+
+#ifdef rcheck
+
+/* To implement range checking, we write magic values in at the beginning and
+ end of each allocated block, and make sure they are undisturbed whenever a
+ free or a realloc occurs. */
+/* Written in each of the 4 bytes following the block's real space */
+#define MAGIC1 0x55
+/* Written in the 4 bytes before the block's real space */
+#define MAGIC4 0x55555555
+#define ASSERT(p) if (!(p)) botch("p"); else
+static
+botch(s)
+ char *s;
+{
+
+ printf("assertion botched: %s\n", s);
+ abort();
+}
+#define EXTRA 4 /* 4 bytes extra for MAGIC1s */
+#else
+#define ASSERT(p)
+#define EXTRA 0
+#endif /* rcheck */
+
+/* nextf[i] is free list of blocks of size 2**(i + 3) */
+
+static struct mhead *nextf[30];
+
+#ifdef M_WARN
+/* Number of bytes of writable memory we can expect to be able to get */
+static int lim_data;
+/* Level number of warnings already issued.
+ 0 -- no warnings issued.
+ 1 -- 75% warning already issued.
+ 2 -- 85% warning already issued.
+*/
+static int warnlevel;
+#endif /* M_WARN */
+
+/* nonzero once initial bunch of free blocks made */
+static int gotpool;
+
+/* Cause reinitialization based on job parameters;
+ also declare where the end of pure storage is. */
+malloc_init (end)
+ char *end; {
+ endofpure = end;
+#ifdef M_WARN
+ lim_data = 0;
+ warnlevel = 0;
+#endif /* M_WARN */
+ }
+
+static
+morecore (nu) /* ask system for more memory */
+ register int nu; { /* size index to get more of */
+ char *sbrk ();
+ register char *cp;
+ register int nblks;
+ register int siz;
+
+#ifdef M_WARN
+#ifndef BSD42
+#ifdef USG
+ extern long ulimit ();
+ if (lim_data == 0) /* find out how much we can get */
+ lim_data = ulimit (3, 0) - TEXT_START;
+#else /*HMS: was endif */
+ if (lim_data == 0) /* find out how much we can get */
+ lim_data = vlimit (LIM_DATA, -1);
+#endif /* USG */ /HMS:* was not here */
+#else
+ if (lim_data == 0) {
+ struct rlimit XXrlimit;
+
+ getrlimit (RLIMIT_DATA, &XXrlimit);
+ lim_data = XXrlimit.rlim_cur;} /* soft limit */
+#endif /* BSD42 */
+#endif /* M_WARN */
+
+ /* On initial startup, get two blocks of each size up to 1k bytes */
+ if (!gotpool)
+ getpool (), getpool (), gotpool = 1;
+
+ /* Find current end of memory and issue warning if getting near max */
+
+ cp = sbrk (0);
+ siz = cp - endofpure;
+#ifdef M_WARN
+ switch (warnlevel) {
+ case 0:
+ if (siz > (lim_data / 4) * 3) {
+ warnlevel++;
+ malloc_warning ("Warning: past 75% of memory limit");}
+ break;
+ case 1:
+ if (siz > (lim_data / 20) * 17) {
+ warnlevel++;
+ malloc_warning ("Warning: past 85% of memory limit");}
+ break;
+ case 2:
+ if (siz > (lim_data / 20) * 19) {
+ warnlevel++;
+ malloc_warning ("Warning: past 95% of memory limit");}
+ break;}
+#endif /* M_WARN */
+
+ if ((int) cp & 0x3ff) /* land on 1K boundaries */
+ sbrk (1024 - ((int) cp & 0x3ff));
+
+ /* Take at least 2k, and figure out how many blocks of the desired size we're about to get */
+ nblks = 1;
+ if ((siz = nu) < 8)
+ nblks = 1 << ((siz = 8) - nu);
+
+ if ((cp = sbrk (1 << (siz + 3))) == (char *) -1)
+ return; /* no more room! */
+ if ((int) cp & 7) { /* shouldn't happen, but just in case */
+ cp = (char *) (((int) cp + 8) & ~7);
+ nblks--;}
+
+ /* save new header and link the nblks blocks together */
+ nextf[nu] = (struct mhead *) cp;
+ siz = 1 << (nu + 3);
+ while (1) {
+ ((struct mhead *) cp) -> mh_alloc = ISFREE;
+ ((struct mhead *) cp) -> mh_index = nu;
+ if (--nblks <= 0) break;
+ CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz);
+ cp += siz;}
+#if 0
+ CHAIN ((struct mhead *) cp) = 0; /* since sbrk() returns cleared core, this is already set */
+#endif
+ }
+
+static
+getpool () {
+ register int nu;
+ register char *cp = sbrk (0);
+
+ if ((int) cp & 0x3ff) /* land on 1K boundaries */
+ sbrk (1024 - ((int) cp & 0x3ff));
+
+ /* Get 2k of storage */
+
+ cp = sbrk (04000);
+ if (cp == (char *) -1)
+ return;
+
+ /* Divide it into an initial 8-word block
+ plus one block of size 2**nu for nu = 3 ... 10. */
+
+ CHAIN (cp) = nextf[0];
+ nextf[0] = (struct mhead *) cp;
+ ((struct mhead *) cp) -> mh_alloc = ISFREE;
+ ((struct mhead *) cp) -> mh_index = 0;
+ cp += 8;
+
+ for (nu = 0; nu < 7; nu++) {
+ CHAIN (cp) = nextf[nu];
+ nextf[nu] = (struct mhead *) cp;
+ ((struct mhead *) cp) -> mh_alloc = ISFREE;
+ ((struct mhead *) cp) -> mh_index = nu;
+ cp += 8 << nu;}}
+
+char *
+malloc (n) /* get a block */
+ unsigned n; {
+ register struct mhead *p;
+ register unsigned int nbytes;
+ register int nunits = 0;
+
+ /* Figure out how many bytes are required, rounding up to the nearest
+ multiple of 4, then figure out which nextf[] area to use */
+ nbytes = (n + sizeof *p + EXTRA + 3) & ~3;
+ {
+ register unsigned int shiftr = (nbytes - 1) >> 2;
+
+ while (shiftr >>= 1)
+ nunits++;
+ }
+
+ /* If there are no blocks of the appropriate size, go get some */
+ /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */
+ if (nextf[nunits] == 0)
+ morecore (nunits);
+
+ /* Get one block off the list, and set the new list head */
+ if ((p = nextf[nunits]) == 0)
+ return 0;
+ nextf[nunits] = CHAIN (p);
+
+ /* Check for free block clobbered */
+ /* If not for this check, we would gobble a clobbered free chain ptr */
+ /* and bomb out on the NEXT allocate of this size block */
+ if (p -> mh_alloc != ISFREE || p -> mh_index != nunits)
+#ifdef rcheck
+ botch ("block on free list clobbered");
+#else
+ abort ();
+#endif /* rcheck */
+
+ /* Fill in the info, and if range checking, set up the magic numbers */
+ p -> mh_alloc = ISALLOC;
+#ifdef rcheck
+ p -> mh_nbytes = n;
+ p -> mh_magic4 = MAGIC4;
+ {
+ register char *m = (char *) (p + 1) + n;
+
+ *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1;
+ }
+#else
+ p -> mh_size = n;
+#endif /* rcheck */
+#ifdef MSTATS
+ nmalloc[nunits]++;
+ nmal++;
+#endif /* MSTATS */
+ return (char *) (p + 1);}
+
+free (mem)
+ char *mem; {
+ register struct mhead *p;
+ {
+ register char *ap = mem;
+
+ ASSERT (ap != 0);
+ p = (struct mhead *) ap - 1;
+ ASSERT (p -> mh_alloc == ISALLOC);
+#ifdef rcheck
+ ASSERT (p -> mh_magic4 == MAGIC4);
+ ap += p -> mh_nbytes;
+ ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1);
+ ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1);
+#endif /* rcheck */
+ }
+ {
+ register int nunits = p -> mh_index;
+
+ ASSERT (nunits <= 29);
+ p -> mh_alloc = ISFREE;
+ CHAIN (p) = nextf[nunits];
+ nextf[nunits] = p;
+#ifdef MSTATS
+ nmalloc[nunits]--;
+ nfre++;
+#endif /* MSTATS */
+ }
+ }
+
+char *
+realloc (mem, n)
+ char *mem;
+ register unsigned n; {
+ register struct mhead *p;
+ register unsigned int tocopy;
+ register int nbytes;
+ register int nunits;
+
+ if ((p = (struct mhead *) mem) == 0)
+ return malloc (n);
+ p--;
+ nunits = p -> mh_index;
+ ASSERT (p -> mh_alloc == ISALLOC);
+#ifdef rcheck
+ ASSERT (p -> mh_magic4 == MAGIC4);
+ {
+ register char *m = mem + (tocopy = p -> mh_nbytes);
+ ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1);
+ ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1);
+ }
+#else
+ if (p -> mh_index >= 13)
+ tocopy = (1 << (p -> mh_index + 3)) - sizeof *p;
+ else
+ tocopy = p -> mh_size;
+#endif /* rcheck */
+
+ /* See if desired size rounds to same power of 2 as actual size. */
+ nbytes = (n + sizeof *p + EXTRA + 7) & ~7;
+
+ /* If ok, use the same block, just marking its size as changed. */
+ if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) {
+#ifdef rcheck
+ register char *m = mem + tocopy;
+ *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0;
+ p-> mh_nbytes = n;
+ m = mem + n;
+ *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1;
+#else
+ p -> mh_size = n;
+#endif /* rcheck */
+ return mem;}
+
+ if (n < tocopy)
+ tocopy = n;
+ {
+ register char *new;
+ void bcopy(); /*HMS: here? */
+
+ if ((new = malloc (n)) == 0)
+ return 0;
+ bcopy (mem, new, tocopy);
+ free (mem);
+ return new;
+ }
+ }
+
+#ifdef MSTATS
+/* Return statistics describing allocation of blocks of size 2**n. */
+
+struct mstats_value {
+ int blocksize;
+ int nfree;
+ int nused;
+ };
+
+struct mstats_value
+malloc_stats (size)
+ int size; {
+ struct mstats_value v;
+ register int i;
+ register struct mhead *p;
+
+ v.nfree = 0;
+
+ if (size < 0 || size >= 30) {
+ v.blocksize = 0;
+ v.nused = 0;
+ return v;}
+
+ v.blocksize = 1 << (size + 3);
+ v.nused = nmalloc[size];
+
+ for (p = nextf[size]; p; p = CHAIN (p))
+ v.nfree++;
+
+ return v;}
+#endif
+
+/* how much space is available? */
+
+unsigned freespace() {
+ register int i, j;
+ register struct mhead *p;
+ register unsigned space = 0;
+ int local; /* address only is used */
+
+ space = (char *)&local - sbrk(0); /* stack space */
+
+ for (i = 0; i < 30; i++) {
+ for (j = 0, p = nextf[i]; p; p = CHAIN (p), j++) ;
+ space += j * (1 << (i + 3));}
+
+ return(space);}
+
+/* How big is this cell? */
+
+unsigned mc_size(cp)
+ char *cp;{
+ register struct mhead *p;
+
+ if ((p = (struct mhead *) cp) == 0) {
+ /*HMS? */
+ }
+ p--;
+#ifdef rcheck
+ return p -> mh_nbytes;
+#else
+ return (1 << (p -> mh_index + 3)) - sizeof *p;
+#if 0
+ if (p -> mh_index >= 13)
+ return (1 << (p -> mh_index + 3)) - sizeof *p;
+ else
+ return p -> mh_size;
+#endif
+#endif /* rcheck */
+ }
+
+/*HMS: Really should use memcpy, if available... */
+
+void bcopy(source, dest, len)
+ register char *source, *dest;
+ register len; {
+ register i;
+
+ for (i = 0; i < len; i++)
+ *dest++ = *source++;}
diff --git a/xc/util/patch/patch.c b/xc/util/patch/patch.c
new file mode 100644
index 000000000..28048be97
--- /dev/null
+++ b/xc/util/patch/patch.c
@@ -0,0 +1,941 @@
+char rcsid[] =
+ "$XConsortium: patch.c,v 3.3 94/09/14 21:21:33 gildea Exp $";
+/* "oldHeader: patch.c,v 2.0.2.0 90/05/01 22:17:50 davison Locked $"; */
+
+/* patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * This program may be copied as long as you don't try to make any
+ * money off of it, or pretend that you wrote it.
+ *
+ * Revision 2.0.2.0 90/05/01 22:17:50 davison
+ * patch12u: unidiff support added
+ *
+ * Revision 2.0.1.6 88/06/22 20:46:39 lwall
+ * patch12: rindex() wasn't declared
+ *
+ * Revision 2.0.1.5 88/06/03 15:09:37 lwall
+ * patch10: exit code improved.
+ * patch10: better support for non-flexfilenames.
+ *
+ * Revision 2.0.1.4 87/02/16 14:00:04 lwall
+ * Short replacement caused spurious "Out of sync" message.
+ *
+ * Revision 2.0.1.3 87/01/30 22:45:50 lwall
+ * Improved diagnostic on sync error.
+ * Moved do_ed_script() to pch.c.
+ *
+ * Revision 2.0.1.2 86/11/21 09:39:15 lwall
+ * Fuzz factor caused offset of installed lines.
+ *
+ * Revision 2.0.1.1 86/10/29 13:10:22 lwall
+ * Backwards search could terminate prematurely.
+ *
+ * Revision 2.0 86/09/17 15:37:32 lwall
+ * Baseline for netwide release.
+ *
+ * Revision 1.5 86/08/01 20:53:24 lwall
+ * Changed some %d's to %ld's.
+ * Linted.
+ *
+ * Revision 1.4 86/08/01 19:17:29 lwall
+ * Fixes for machines that can't vararg.
+ * Added fuzz factor.
+ * Generalized -p.
+ * General cleanup.
+ *
+ * 85/08/15 van%ucbmonet@berkeley
+ * Changes for 4.3bsd diff -c.
+ *
+ * Revision 1.3 85/03/26 15:07:43 lwall
+ * Frozen.
+ *
+ * Revision 1.2.1.9 85/03/12 17:03:35 lwall
+ * Changed pfp->_file to fileno(pfp).
+ *
+ * Revision 1.2.1.8 85/03/12 16:30:43 lwall
+ * Check i_ptr and i_womp to make sure they aren't null before freeing.
+ * Also allow ed output to be suppressed.
+ *
+ * Revision 1.2.1.7 85/03/12 15:56:13 lwall
+ * Added -p option from jromine@uci-750a.
+ *
+ * Revision 1.2.1.6 85/03/12 12:12:51 lwall
+ * Now checks for normalness of file to patch.
+ *
+ * Revision 1.2.1.5 85/03/12 11:52:12 lwall
+ * Added -D (#ifdef) option from joe@fluke.
+ *
+ * Revision 1.2.1.4 84/12/06 11:14:15 lwall
+ * Made smarter about SCCS subdirectories.
+ *
+ * Revision 1.2.1.3 84/12/05 11:18:43 lwall
+ * Added -l switch to do loose string comparison.
+ *
+ * Revision 1.2.1.2 84/12/04 09:47:13 lwall
+ * Failed hunk count not reset on multiple patch file.
+ *
+ * Revision 1.2.1.1 84/12/04 09:42:37 lwall
+ * Branch for sdcrdcf changes.
+ *
+ * Revision 1.2 84/11/29 13:29:51 lwall
+ * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed
+ * multiple calls to mktemp(). Will now work on machines that can only
+ * read 32767 chars. Added -R option for diffs with new and old swapped.
+ * Various cosmetic changes.
+ *
+ * Revision 1.1 84/11/09 17:03:58 lwall
+ * Initial revision
+ *
+ */
+
+#include "INTERN.h"
+#include "common.h"
+#include "EXTERN.h"
+#include "version.h"
+#include "util.h"
+#include "pch.h"
+#include "inp.h"
+#include "backupfile.h"
+
+/* procedures */
+
+void reinitialize_almost_everything();
+void get_some_switches();
+LINENUM locate_hunk();
+void abort_hunk();
+void apply_hunk();
+void init_output();
+void init_reject();
+void copy_till();
+void spew_output();
+void dump_line();
+bool patch_match();
+bool similar();
+void re_input();
+void my_exit();
+
+/* TRUE if -E was specified on command line. */
+static int remove_empty_files = FALSE;
+
+/* TRUE if -R was specified on command line. */
+static int reverse_flag_specified = FALSE;
+
+/* Apply a set of diffs as appropriate. */
+
+int
+main(argc,argv)
+int argc;
+char **argv;
+{
+ LINENUM where;
+ LINENUM newwhere;
+ LINENUM fuzz;
+ LINENUM mymaxfuzz;
+ int hunk = 0;
+ int failed = 0;
+ int failtotal = 0;
+ bool rev_okayed = 0;
+ int i;
+
+ setbuf(stderr, serrbuf);
+ for (i = 0; i<MAXFILEC; i++)
+ filearg[i] = Nullch;
+
+#ifndef WIN32
+ myuid = getuid();
+#endif
+
+ /* Cons up the names of the temporary files. */
+ {
+ /* Directory for temporary files. */
+ char *tmpdir;
+ int tmpname_len;
+
+ tmpdir = getenv ("TMPDIR");
+ if (tmpdir == NULL) {
+ tmpdir = "/tmp";
+ }
+ tmpname_len = strlen (tmpdir) + 20;
+
+ TMPOUTNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPOUTNAME, tmpdir);
+ strcat (TMPOUTNAME, "/patchoXXXXXX");
+ Mktemp(TMPOUTNAME);
+
+ TMPINNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPINNAME, tmpdir);
+ strcat (TMPINNAME, "/patchiXXXXXX");
+ Mktemp(TMPINNAME);
+
+ TMPREJNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPREJNAME, tmpdir);
+ strcat (TMPREJNAME, "/patchrXXXXXX");
+ Mktemp(TMPREJNAME);
+
+ TMPPATNAME = (char *) malloc (tmpname_len);
+ strcpy (TMPPATNAME, tmpdir);
+ strcat (TMPPATNAME, "/patchpXXXXXX");
+ Mktemp(TMPPATNAME);
+ }
+
+ {
+ char *v;
+
+ v = getenv ("SIMPLE_BACKUP_SUFFIX");
+ if (v)
+ simple_backup_suffix = v;
+ else
+ simple_backup_suffix = ORIGEXT;
+#ifndef NODIR
+ v = getenv ("VERSION_CONTROL");
+ backup_type = get_version (v); /* OK to pass NULL. */
+#endif
+ }
+
+ /* parse switches */
+ Argc = argc;
+ Argv = argv;
+ get_some_switches();
+
+ /* make sure we clean up /tmp in case of disaster */
+ set_signals(0);
+
+ for (
+ open_patch_file(filearg[1]);
+ there_is_another_patch();
+ reinitialize_almost_everything()
+ ) { /* for each patch in patch file */
+
+ if (outname == Nullch)
+ outname = savestr(filearg[0]);
+
+#ifndef WIN32
+ /* for ed script just up and do it and exit */
+ if (diff_type == ED_DIFF) {
+ do_ed_script();
+ continue;
+ }
+#endif
+
+ /* initialize the patched file */
+ if (!skip_rest_of_patch)
+ init_output(TMPOUTNAME);
+
+ /* initialize reject file */
+ init_reject(TMPREJNAME);
+
+ /* find out where all the lines are */
+ if (!skip_rest_of_patch)
+ scan_input(filearg[0]);
+
+ /* from here on, open no standard i/o files, because malloc */
+ /* might misfire and we can't catch it easily */
+
+ /* apply each hunk of patch */
+ hunk = 0;
+ failed = 0;
+ rev_okayed = FALSE;
+ out_of_mem = FALSE;
+ while (another_hunk()) {
+ hunk++;
+ fuzz = Nulline;
+ mymaxfuzz = pch_context();
+ if (maxfuzz < mymaxfuzz)
+ mymaxfuzz = maxfuzz;
+ if (!skip_rest_of_patch) {
+ do {
+ where = locate_hunk(fuzz);
+ if (hunk == 1 && where == Nulline && !(force|rev_okayed)) {
+ /* dwim for reversed patch? */
+ if (!pch_swap()) {
+ if (fuzz == Nulline)
+ say1(
+"Not enough memory to try swapped hunk! Assuming unswapped.\n");
+ continue;
+ }
+ reverse = !reverse;
+ where = locate_hunk(fuzz); /* try again */
+ if (where == Nulline) { /* didn't find it swapped */
+ if (!pch_swap()) /* put it back to normal */
+ fatal1("lost hunk on alloc error!\n");
+ reverse = !reverse;
+ }
+ else if (noreverse) {
+ if (!pch_swap()) /* put it back to normal */
+ fatal1("lost hunk on alloc error!\n");
+ reverse = !reverse;
+ say1(
+"Ignoring previously applied (or reversed) patch.\n");
+ skip_rest_of_patch = TRUE;
+ }
+ else if (batch) {
+ if (verbose)
+ say3(
+"%seversed (or previously applied) patch detected! %s -R.",
+ reverse ? "R" : "Unr",
+ reverse ? "Assuming" : "Ignoring");
+ }
+ else {
+ ask3(
+"%seversed (or previously applied) patch detected! %s -R? [y] ",
+ reverse ? "R" : "Unr",
+ reverse ? "Assume" : "Ignore");
+ if (*buf == 'n') {
+ ask1("Apply anyway? [n] ");
+ if (*buf == 'y')
+ rev_okayed = TRUE;
+ else
+ skip_rest_of_patch = TRUE;
+ where = Nulline;
+ reverse = !reverse;
+ if (!pch_swap()) /* put it back to normal */
+ fatal1("lost hunk on alloc error!\n");
+ }
+ }
+ }
+ } while (!skip_rest_of_patch && where == Nulline &&
+ ++fuzz <= mymaxfuzz);
+
+ if (skip_rest_of_patch) { /* just got decided */
+ Fclose(ofp);
+ ofp = Nullfp;
+ }
+ }
+
+ newwhere = pch_newfirst() + last_offset;
+ if (skip_rest_of_patch) {
+ abort_hunk();
+ failed++;
+ if (verbose)
+ say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
+ }
+ else if (where == Nulline) {
+ abort_hunk();
+ failed++;
+ if (verbose)
+ say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
+ }
+ else {
+ apply_hunk(where);
+ if (verbose) {
+ say3("Hunk #%d succeeded at %ld", hunk, newwhere);
+ if (fuzz)
+ say2(" with fuzz %ld", fuzz);
+ if (last_offset)
+ say3(" (offset %ld line%s)",
+ last_offset, last_offset==1L?"":"s");
+ say1(".\n");
+ }
+ }
+ }
+
+ if (out_of_mem && using_plan_a) {
+ Argc = Argc_last;
+ Argv = Argv_last;
+ say1("\n\nRan out of memory using Plan A--trying again...\n\n");
+ if (ofp)
+ Fclose(ofp);
+ ofp = Nullfp;
+ if (rejfp)
+ Fclose(rejfp);
+ rejfp = Nullfp;
+ continue;
+ }
+
+ assert(hunk);
+
+ /* finish spewing out the new file */
+ if (!skip_rest_of_patch)
+ spew_output();
+
+ /* and put the output where desired */
+ ignore_signals();
+ if (!skip_rest_of_patch) {
+ struct stat statbuf;
+ char *realout = outname;
+
+ if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = TRUE;
+ realout = TMPOUTNAME;
+ chmod(TMPOUTNAME, filemode);
+ }
+ else
+ chmod(outname, filemode);
+
+ if (remove_empty_files && stat(realout, &statbuf) == 0
+ && statbuf.st_size == 0) {
+ if (verbose)
+ say2("Removing %s (empty after patching).\n", realout);
+ while (unlink(realout) >= 0) ; /* while is for Eunice. */
+ }
+ }
+ Fclose(rejfp);
+ rejfp = Nullfp;
+ if (failed) {
+ failtotal += failed;
+ if (!*rejname) {
+ Strcpy(rejname, outname);
+#ifndef FLEXFILENAMES
+ {
+ char *s = rindex(rejname,'/');
+
+ if (!s)
+ s = rejname;
+ if (strlen(s) > 13)
+ if (s[12] == '.') /* try to preserve difference */
+ s[12] = s[13]; /* between .h, .c, .y, etc. */
+ s[13] = '\0';
+ }
+#endif
+ Strcat(rejname, REJEXT);
+ }
+ if (skip_rest_of_patch) {
+ say4("%d out of %d hunks ignored--saving rejects to %s\n",
+ failed, hunk, rejname);
+ }
+ else {
+ say4("%d out of %d hunks failed--saving rejects to %s\n",
+ failed, hunk, rejname);
+ }
+ if (move_file(TMPREJNAME, rejname) < 0)
+ trejkeep = TRUE;
+ }
+ set_signals(1);
+ }
+ my_exit(failtotal);
+}
+
+/* Prepare to find the next patch to do in the patch file. */
+
+void
+reinitialize_almost_everything()
+{
+ re_patch();
+ re_input();
+
+ input_lines = 0;
+ last_frozen_line = 0;
+
+ filec = 0;
+ if (filearg[0] != Nullch && !out_of_mem) {
+ free(filearg[0]);
+ filearg[0] = Nullch;
+ }
+
+ if (outname != Nullch) {
+ free(outname);
+ outname = Nullch;
+ }
+
+ last_offset = 0;
+
+ diff_type = 0;
+
+ if (revision != Nullch) {
+ free(revision);
+ revision = Nullch;
+ }
+
+ reverse = reverse_flag_specified;
+ skip_rest_of_patch = FALSE;
+
+ get_some_switches();
+
+ if (filec >= 2)
+ fatal1("you may not change to a different patch file\n");
+}
+
+static char *
+nextarg()
+{
+ if (!--Argc)
+ fatal2("missing argument after `%s'\n", *Argv);
+ return *++Argv;
+}
+
+/* Process switches and filenames up to next '+' or end of list. */
+
+void
+get_some_switches()
+{
+ Reg1 char *s;
+
+ rejname[0] = '\0';
+ Argc_last = Argc;
+ Argv_last = Argv;
+ if (!Argc)
+ return;
+ for (Argc--,Argv++; Argc; Argc--,Argv++) {
+ s = Argv[0];
+ if (strEQ(s, "+")) {
+ return; /* + will be skipped by for loop */
+ }
+ if (*s != '-' || !s[1]) {
+ if (filec == MAXFILEC)
+ fatal1("too many file arguments\n");
+ filearg[filec++] = savestr(s);
+ }
+ else {
+ switch (*++s) {
+ case 'b':
+ simple_backup_suffix = savestr(nextarg());
+ break;
+ case 'B':
+ origprae = savestr(nextarg());
+ break;
+ case 'c':
+ diff_type = CONTEXT_DIFF;
+ break;
+ case 'd':
+ if (!*++s)
+ s = nextarg();
+ if (chdir(s) < 0)
+ pfatal2("can't cd to %s", s);
+ break;
+ case 'D':
+ do_defines = TRUE;
+ if (!*++s)
+ s = nextarg();
+ if (!isalpha(*s) && '_' != *s)
+ fatal1("argument to -D is not an identifier\n");
+ Sprintf(if_defined, "#ifdef %s\n", s);
+ Sprintf(not_defined, "#ifndef %s\n", s);
+ Sprintf(end_defined, "#endif /* %s */\n", s);
+ break;
+#ifndef WIN32
+ case 'e':
+ diff_type = ED_DIFF;
+ break;
+#endif
+ case 'E':
+ remove_empty_files = TRUE;
+ break;
+ case 'f':
+ force = TRUE;
+ break;
+ case 'F':
+ if (*++s == '=')
+ s++;
+ maxfuzz = atoi(s);
+ break;
+ case 'l':
+ canonicalize = TRUE;
+ break;
+ case 'n':
+ diff_type = NORMAL_DIFF;
+ break;
+ case 'N':
+ noreverse = TRUE;
+ break;
+ case 'o':
+ outname = savestr(nextarg());
+ break;
+ case 'p':
+ if (*++s == '=')
+ s++;
+ strippath = atoi(s);
+ break;
+ case 'r':
+ Strcpy(rejname, nextarg());
+ break;
+ case 'R':
+ reverse = TRUE;
+ reverse_flag_specified = TRUE;
+ break;
+ case 's':
+ verbose = FALSE;
+ break;
+ case 'S':
+ skip_rest_of_patch = TRUE;
+ break;
+ case 't':
+ batch = TRUE;
+ break;
+ case 'u':
+ diff_type = UNI_DIFF;
+ break;
+ case 'v':
+ version();
+ break;
+ case 'V':
+#ifndef NODIR
+ backup_type = get_version (nextarg ());
+#endif
+ break;
+#ifdef DEBUGGING
+ case 'x':
+ debug = atoi(s+1);
+ break;
+#endif
+ default:
+ fprintf(stderr, "patch: unrecognized option `%s'\n", Argv[0]);
+ fprintf(stderr, "\
+Usage: patch [options] [origfile [patchfile]] [+ [options] [origfile]]...\n\
+Options:\n\
+ [-ceEflnNRsStuv] [-b backup-ext] [-B backup-prefix] [-d directory]\n\
+ [-D symbol] [-Fmax-fuzz] [-o out-file] [-p[strip-count]]\n\
+ [-r rej-name] [-V {numbered,existing,simple}]\n");
+ my_exit(1);
+ }
+ }
+ }
+}
+
+/* Attempt to find the right place to apply this hunk of patch. */
+
+LINENUM
+locate_hunk(fuzz)
+LINENUM fuzz;
+{
+ Reg1 LINENUM first_guess = pch_first() + last_offset;
+ Reg2 LINENUM offset;
+ LINENUM pat_lines = pch_ptrn_lines();
+ Reg3 LINENUM max_pos_offset = input_lines - first_guess
+ - pat_lines + 1;
+ Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
+ + pch_context();
+
+ if (!pat_lines) /* null range matches always */
+ return first_guess;
+ if (max_neg_offset >= first_guess) /* do not try lines < 0 */
+ max_neg_offset = first_guess - 1;
+ if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
+ return first_guess;
+ for (offset = 1; ; offset++) {
+ Reg5 bool check_after = (offset <= max_pos_offset);
+ Reg6 bool check_before = (offset <= max_neg_offset);
+
+ if (check_after && patch_match(first_guess, offset, fuzz)) {
+#ifdef DEBUGGING
+ if (debug & 1)
+ say3("Offset changing from %ld to %ld\n", last_offset, offset);
+#endif
+ last_offset = offset;
+ return first_guess+offset;
+ }
+ else if (check_before && patch_match(first_guess, -offset, fuzz)) {
+#ifdef DEBUGGING
+ if (debug & 1)
+ say3("Offset changing from %ld to %ld\n", last_offset, -offset);
+#endif
+ last_offset = -offset;
+ return first_guess-offset;
+ }
+ else if (!check_before && !check_after)
+ return Nulline;
+ }
+}
+
+/* We did not find the pattern, dump out the hunk so they can handle it. */
+
+void
+abort_hunk()
+{
+ Reg1 LINENUM i;
+ Reg2 LINENUM pat_end = pch_end();
+ /* add in last_offset to guess the same as the previous successful hunk */
+ LINENUM oldfirst = pch_first() + last_offset;
+ LINENUM newfirst = pch_newfirst() + last_offset;
+ LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
+ LINENUM newlast = newfirst + pch_repl_lines() - 1;
+ char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
+ char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
+
+ fprintf(rejfp, "***************\n");
+ for (i=0; i<=pat_end; i++) {
+ switch (pch_char(i)) {
+ case '*':
+ if (oldlast < oldfirst)
+ fprintf(rejfp, "*** 0%s\n", stars);
+ else if (oldlast == oldfirst)
+ fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
+ else
+ fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
+ break;
+ case '=':
+ if (newlast < newfirst)
+ fprintf(rejfp, "--- 0%s\n", minuses);
+ else if (newlast == newfirst)
+ fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
+ else
+ fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
+ break;
+ case '\n':
+ fprintf(rejfp, "%s", pfetch(i));
+ break;
+ case ' ': case '-': case '+': case '!':
+ fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
+ break;
+ default:
+ fatal1("fatal internal error in abort_hunk\n");
+ }
+ }
+}
+
+/* We found where to apply it (we hope), so do it. */
+
+void
+apply_hunk(where)
+LINENUM where;
+{
+ Reg1 LINENUM old = 1;
+ Reg2 LINENUM lastline = pch_ptrn_lines();
+ Reg3 LINENUM new = lastline+1;
+#define OUTSIDE 0
+#define IN_IFNDEF 1
+#define IN_IFDEF 2
+#define IN_ELSE 3
+ Reg4 int def_state = OUTSIDE;
+ Reg5 bool R_do_defines = do_defines;
+ Reg6 LINENUM pat_end = pch_end();
+
+ where--;
+ while (pch_char(new) == '=' || pch_char(new) == '\n')
+ new++;
+
+ while (old <= lastline) {
+ if (pch_char(old) == '-') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ if (def_state == OUTSIDE) {
+ fputs(not_defined, ofp);
+ def_state = IN_IFNDEF;
+ }
+ else if (def_state == IN_IFDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ fputs(pfetch(old), ofp);
+ }
+ last_frozen_line++;
+ old++;
+ }
+ else if (new > pat_end) {
+ break;
+ }
+ else if (pch_char(new) == '+') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ if (def_state == IN_IFNDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ else if (def_state == OUTSIDE) {
+ fputs(if_defined, ofp);
+ def_state = IN_IFDEF;
+ }
+ }
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ else if (pch_char(new) != pch_char(old)) {
+ say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
+ pch_hunk_beg() + old,
+ pch_hunk_beg() + new);
+#ifdef DEBUGGING
+ say3("oldchar = '%c', newchar = '%c'\n",
+ pch_char(old), pch_char(new));
+#endif
+ my_exit(1);
+ }
+ else if (pch_char(new) == '!') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ fputs(not_defined, ofp);
+ def_state = IN_IFNDEF;
+ }
+ while (pch_char(old) == '!') {
+ if (R_do_defines) {
+ fputs(pfetch(old), ofp);
+ }
+ last_frozen_line++;
+ old++;
+ }
+ if (R_do_defines) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ while (pch_char(new) == '!') {
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ }
+ else {
+ assert(pch_char(new) == ' ');
+ old++;
+ new++;
+ if (R_do_defines && def_state != OUTSIDE) {
+ fputs(end_defined, ofp);
+ def_state = OUTSIDE;
+ }
+ }
+ }
+ if (new <= pat_end && pch_char(new) == '+') {
+ copy_till(where + old - 1);
+ if (R_do_defines) {
+ if (def_state == OUTSIDE) {
+ fputs(if_defined, ofp);
+ def_state = IN_IFDEF;
+ }
+ else if (def_state == IN_IFNDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ }
+ while (new <= pat_end && pch_char(new) == '+') {
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ }
+ if (R_do_defines && def_state != OUTSIDE) {
+ fputs(end_defined, ofp);
+ }
+}
+
+/* Open the new file. */
+
+void
+init_output(name)
+char *name;
+{
+#ifndef WIN32
+ ofp = fopen(name, "w");
+#else
+ ofp = fopen(name, "wb");
+#endif
+ if (ofp == Nullfp)
+ pfatal2("can't create %s", name);
+}
+
+/* Open a file to put hunks we can't locate. */
+
+void
+init_reject(name)
+char *name;
+{
+#ifndef WIN32
+ rejfp = fopen(name, "w");
+#else
+ rejfp = fopen(name, "wb");
+#endif
+ if (rejfp == Nullfp)
+ pfatal2("can't create %s", name);
+}
+
+/* Copy input file to output, up to wherever hunk is to be applied. */
+
+void
+copy_till(lastline)
+Reg1 LINENUM lastline;
+{
+ Reg2 LINENUM R_last_frozen_line = last_frozen_line;
+
+ if (R_last_frozen_line > lastline)
+ fatal1("misordered hunks! output would be garbled\n");
+ while (R_last_frozen_line < lastline) {
+ dump_line(++R_last_frozen_line);
+ }
+ last_frozen_line = R_last_frozen_line;
+}
+
+/* Finish copying the input file to the output file. */
+
+void
+spew_output()
+{
+#ifdef DEBUGGING
+ if (debug & 256)
+ say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
+#endif
+ if (input_lines)
+ copy_till(input_lines); /* dump remainder of file */
+ Fclose(ofp);
+ ofp = Nullfp;
+}
+
+/* Copy one line from input to output. */
+
+void
+dump_line(line)
+LINENUM line;
+{
+ Reg1 char *s;
+ Reg2 char R_newline = '\n';
+
+ /* Note: string is not null terminated. */
+ for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
+}
+
+/* Does the patch pattern match at line base+offset? */
+
+bool
+patch_match(base, offset, fuzz)
+LINENUM base;
+LINENUM offset;
+LINENUM fuzz;
+{
+ Reg1 LINENUM pline = 1 + fuzz;
+ Reg2 LINENUM iline;
+ Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
+
+ for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
+ if (canonicalize) {
+ if (!similar(ifetch(iline, (offset >= 0)),
+ pfetch(pline),
+ pch_line_len(pline) ))
+ return FALSE;
+ }
+ else if (strnNE(ifetch(iline, (offset >= 0)),
+ pfetch(pline),
+ pch_line_len(pline) ))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Do two lines match with canonicalized white space? */
+
+bool
+similar(a,b,len)
+Reg1 char *a;
+Reg2 char *b;
+Reg3 int len;
+{
+ while (len) {
+ if (isspace(*b)) { /* whitespace (or \n) to match? */
+ if (!isspace(*a)) /* no corresponding whitespace? */
+ return FALSE;
+ while (len && isspace(*b) && *b != '\n')
+ b++,len--; /* skip pattern whitespace */
+ while (isspace(*a) && *a != '\n')
+ a++; /* skip target whitespace */
+ if (*a == '\n' || *b == '\n')
+ return (*a == *b); /* should end in sync */
+ }
+ else if (*a++ != *b++) /* match non-whitespace chars */
+ return FALSE;
+ else
+ len--; /* probably not necessary */
+ }
+ return TRUE; /* actually, this is not reached */
+ /* since there is always a \n */
+}
+
+/* Exit with cleanup. */
+
+void
+my_exit(status)
+int status;
+{
+ Unlink(TMPINNAME);
+ if (!toutkeep) {
+ Unlink(TMPOUTNAME);
+ }
+ if (!trejkeep) {
+ Unlink(TMPREJNAME);
+ }
+ Unlink(TMPPATNAME);
+ exit(status);
+}
diff --git a/xc/util/patch/patch.man b/xc/util/patch/patch.man
new file mode 100644
index 000000000..653647b25
--- /dev/null
+++ b/xc/util/patch/patch.man
@@ -0,0 +1,551 @@
+.\" -*- nroff -*-
+.rn '' }`
+'\" $XConsortium: patch.man,v 1.2 94/09/09 20:04:28 gildea Exp $
+'\"
+'\" Revision 2.0.1.2 88/06/22 20:47:18 lwall
+'\" patch12: now avoids Bell System Logo
+'\"
+'\" Revision 2.0.1.1 88/06/03 15:12:51 lwall
+'\" patch10: -B switch was contributed.
+'\"
+'\" Revision 2.0 86/09/17 15:39:09 lwall
+'\" Baseline for netwide release.
+'\"
+'\" Revision 1.4 86/08/01 19:23:22 lwall
+'\" Documented -v, -p, -F.
+'\" Added notes to patch senders.
+'\"
+'\" Revision 1.3 85/03/26 15:11:06 lwall
+'\" Frozen.
+'\"
+'\" Revision 1.2.1.4 85/03/12 16:14:27 lwall
+'\" Documented -p.
+'\"
+'\" Revision 1.2.1.3 85/03/12 16:09:41 lwall
+'\" Documented -D.
+'\"
+'\" Revision 1.2.1.2 84/12/05 11:06:55 lwall
+'\" Added -l switch, and noted bistability bug.
+'\"
+'\" Revision 1.2.1.1 84/12/04 17:23:39 lwall
+'\" Branch for sdcrdcf changes.
+'\"
+'\" Revision 1.2 84/12/04 17:22:02 lwall
+'\" Baseline version.
+'\"
+.de Sh
+.br
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+'\"
+'\" Set up \*(-- to give an unbreakable dash;
+'\" string Tr holds user defined translation string.
+'\" Bell System Logo is used as a dummy character.
+'\"
+'\" Shut up a groff -ww warning.
+.if \n(.g .if !dTr .ds Tr
+.ie n \{\
+.tr \(*W-\*(Tr
+.ds -- \(*W-
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+.ds L' '
+.ds R' '
+'br \}
+.el \{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds L' `
+.ds R' '
+'br\}
+.TH PATCH 1 LOCAL
+.SH NAME
+patch - apply a diff file to an original
+.SH SYNOPSIS
+.B patch
+[options] [origfile [patchfile]] [+ [options] [origfile]]...
+.sp
+but usually just
+.sp
+.B patch
+<patchfile
+.SH DESCRIPTION
+.I Patch
+will take a patch file containing any of the four forms of difference
+listing produced by the
+.I diff
+program and apply those differences to an original file, producing a patched
+version.
+By default, the patched version is put in place of the original, with
+the original file backed up to the same name with the
+extension \*(L".orig\*(R" (\*(L"~\*(R" on systems that do not
+support long filenames), or as specified by the
+.BR -b ,
+.BR -B ,
+or
+.B -V
+switches.
+The extension used for making backup files may also be specified in the
+.B SIMPLE_BACKUP_SUFFIX
+environment variable, which is overridden by above switches.
+.PP
+If the backup file already exists,
+.B patch
+creates a new backup file name by changing the first lowercase letter
+in the last component of the file's name into uppercase. If there are
+no more lowercase letters in the name, it removes the first character
+from the name. It repeats this process until it comes up with a
+backup file that does not already exist.
+.PP
+You may also specify where you want the output to go with a
+.B -o
+switch; if that file already exists, it is backed up first.
+.PP
+If
+.I patchfile
+is omitted, or is a hyphen, the patch will be read from standard input.
+.PP
+Upon startup, patch will attempt to determine the type of the diff listing,
+unless over-ruled by a
+.BR -c ,
+.BR -e ,
+.BR -n ,
+or
+.B -u
+switch.
+Context diffs (old-style, new-style, and unified) and
+normal diffs are applied by the
+.I patch
+program itself, while ed diffs are simply fed to the
+.I ed
+editor via a pipe.
+.PP
+.I Patch
+will try to skip any leading garbage, apply the diff,
+and then skip any trailing garbage.
+Thus you could feed an article or message containing a
+diff listing to
+.IR patch ,
+and it should work.
+If the entire diff is indented by a consistent amount,
+this will be taken into account.
+.PP
+With context diffs, and to a lesser extent with normal diffs,
+.I patch
+can detect when the line numbers mentioned in the patch are incorrect,
+and will attempt to find the correct place to apply each hunk of the patch.
+As a first guess, it takes the line number mentioned for the hunk, plus or
+minus any offset used in applying the previous hunk.
+If that is not the correct place,
+.I patch
+will scan both forwards and backwards for a set of lines matching the context
+given in the hunk.
+First
+.I patch
+looks for a place where all lines of the context match.
+If no such place is found, and it's a context diff, and the maximum fuzz factor
+is set to 1 or more, then another scan takes place ignoring the first and last
+line of context.
+If that fails, and the maximum fuzz factor is set to 2 or more,
+the first two and last two lines of context are ignored,
+and another scan is made.
+(The default maximum fuzz factor is 2.)
+If
+.I patch
+cannot find a place to install that hunk of the patch, it will put the
+hunk out to a reject file, which normally is the name of the output file
+plus \*(L".rej\*(R" (\*(L"#\*(R" on systems that do not support
+long filenames).
+(Note that the rejected hunk will come out in context diff form whether the
+input patch was a context diff or a normal diff.
+If the input was a normal diff, many of the contexts will simply be null.)
+The line numbers on the hunks in the reject file may be different than
+in the patch file: they reflect the approximate location patch thinks the
+failed hunks belong in the new file rather than the old one.
+.PP
+As each hunk is completed, you will be told whether the hunk succeeded or
+failed, and which line (in the new file)
+.I patch
+thought the hunk should go on.
+If this is different from the line number specified in the diff you will
+be told the offset.
+A single large offset MAY be an indication that a hunk was installed in the
+wrong place.
+You will also be told if a fuzz factor was used to make the match, in which
+case you should also be slightly suspicious.
+.PP
+If no original file is specified on the command line,
+.I patch
+will try to figure out from the leading garbage what the name of the file
+to edit is.
+In the header of a context diff, the filename is found from lines beginning
+with \*(L"***\*(R" or \*(L"---\*(R", with the shortest name of an existing
+file winning.
+Only context diffs have lines like that, but if there is an \*(L"Index:\*(R"
+line in the leading garbage,
+.I patch
+will try to use the filename from that line.
+The context diff header takes precedence over an Index line.
+If no filename can be intuited from the leading garbage, you will be asked
+for the name of the file to patch.
+.PP
+If the original file cannot be found or is read-only, but a suitable
+SCCS or RCS file is handy,
+.I patch
+will attempt to get or check out the file.
+.PP
+Additionally, if the leading garbage contains a \*(L"Prereq: \*(R" line,
+.I patch
+will take the first word from the prerequisites line (normally a version
+number) and check the input file to see if that word can be found.
+If not,
+.I patch
+will ask for confirmation before proceeding.
+.PP
+The upshot of all this is that you should be able to say, while in a news
+interface, the following:
+.Sp
+ | patch -d /usr/src/local/blurfl
+.Sp
+and patch a file in the blurfl directory directly from the article containing
+the patch.
+.PP
+If the patch file contains more than one patch,
+.I patch
+will try to apply each of them as if they came from separate patch files.
+This means, among other things, that it is assumed that the name of the file
+to patch must be determined for each diff listing,
+and that the garbage before each diff listing will
+be examined for interesting things such as filenames and revision level, as
+mentioned previously.
+You can give switches (and another original file name) for the second and
+subsequent patches by separating the corresponding argument lists
+by a \*(L'+\*(R'.
+(The argument list for a second or subsequent patch may not specify a new
+patch file, however.)
+.PP
+.I Patch
+recognizes the following switches:
+.TP 5
+.B \-b
+causes the next argument to be interpreted as the backup extension, to be
+used in place of \*(L".orig\*(R" or \*(L"~\*(R".
+.TP 5
+.B \-B
+causes the next argument to be interpreted as a prefix to the backup file
+name. If this argument is specified any argument from -b will be ignored.
+.TP 5
+.B \-c
+forces
+.I patch
+to interpret the patch file as a context diff.
+.TP 5
+.B \-d
+causes
+.I patch
+to interpret the next argument as a directory, and cd to it before doing
+anything else.
+.TP 5
+.B \-D
+causes
+.I patch
+to use the "#ifdef...#endif" construct to mark changes.
+The argument following will be used as the differentiating symbol.
+Note that, unlike the C compiler, there must be a space between the
+.B \-D
+and the argument.
+.TP 5
+.B \-e
+forces
+.I patch
+to interpret the patch file as an ed script.
+.TP 5
+.B \-E
+causes
+.I patch
+to remove output files that are empty after the patches have been applied.
+.TP 5
+.B \-f
+forces
+.I patch
+to assume that the user knows exactly what he or she is doing, and to not
+ask any questions. It assumes the following: skip patches for which a
+file to patch can't be found; patch files even though they have the
+wrong version for the ``Prereq:'' line in the patch; and assume that
+patches are not reversed even if they look like they are.
+This option does not suppress commentary; use
+.B \-s
+for that.
+.TP 5
+.B \-t
+similar to
+.BR \-f ,
+in that it suppresses questions, but makes some different assumptions:
+skip patches for which a file to patch can't be found (the same as \fB\-f\fP);
+skip patches for which the file has the wrong version for the ``Prereq:'' line
+in the patch; and assume that patches are reversed if they look like
+they are.
+.TP 5
+.B \-F<number>
+sets the maximum fuzz factor.
+This switch only applies to context diffs, and causes
+.I patch
+to ignore up to that many lines in looking for places to install a hunk.
+Note that a larger fuzz factor increases the odds of a faulty patch.
+The default fuzz factor is 2, and it may not be set to more than
+the number of lines of context in the context diff, ordinarily 3.
+.TP 5
+.B \-l
+causes the pattern matching to be done loosely, in case the tabs and
+spaces have been munged in your input file.
+Any sequence of whitespace in the pattern line will match any sequence
+in the input file.
+Normal characters must still match exactly.
+Each line of the context must still match a line in the input file.
+.TP 5
+.B \-n
+forces
+.I patch
+to interpret the patch file as a normal diff.
+.TP 5
+.B \-N
+causes
+.I patch
+to ignore patches that it thinks are reversed or already applied.
+See also
+.B \-R .
+.TP 5
+.B \-o
+causes the next argument to be interpreted as the output file name.
+.TP 5
+.B \-p<number>
+sets the pathname strip count,
+which controls how pathnames found in the patch file are treated, in case
+the you keep your files in a different directory than the person who sent
+out the patch.
+The strip count specifies how many slashes are to be stripped from
+the front of the pathname.
+(Any intervening directory names also go away.)
+For example, supposing the filename in the patch file was
+.sp
+ /u/howard/src/blurfl/blurfl.c
+.sp
+setting
+.B \-p
+or
+.B \-p0
+gives the entire pathname unmodified,
+.B \-p1
+gives
+.sp
+ u/howard/src/blurfl/blurfl.c
+.sp
+without the leading slash,
+.B \-p4
+gives
+.sp
+ blurfl/blurfl.c
+.sp
+and not specifying
+.B \-p
+at all just gives you "blurfl.c", unless all of the directories in the
+leading path (u/howard/src/blurfl) exist and that path is relative,
+in which case you get the entire pathname unmodified.
+Whatever you end up with is looked for either in the current directory,
+or the directory specified by the
+.B \-d
+switch.
+.TP 5
+.B \-r
+causes the next argument to be interpreted as the reject file name.
+.TP 5
+.B \-R
+tells
+.I patch
+that this patch was created with the old and new files swapped.
+(Yes, I'm afraid that does happen occasionally, human nature being what it
+is.)
+.I Patch
+will attempt to swap each hunk around before applying it.
+Rejects will come out in the swapped format.
+The
+.B \-R
+switch will not work with ed diff scripts because there is too little
+information to reconstruct the reverse operation.
+.Sp
+If the first hunk of a patch fails,
+.I patch
+will reverse the hunk to see if it can be applied that way.
+If it can, you will be asked if you want to have the
+.B \-R
+switch set.
+If it can't, the patch will continue to be applied normally.
+(Note: this method cannot detect a reversed patch if it is a normal diff
+and if the first command is an append (i.e. it should have been a delete)
+since appends always succeed, due to the fact that a null context will match
+anywhere.
+Luckily, most patches add or change lines rather than delete them, so most
+reversed normal diffs will begin with a delete, which will fail, triggering
+the heuristic.)
+.TP 5
+.B \-s
+makes
+.I patch
+do its work silently, unless an error occurs.
+.TP 5
+.B \-S
+causes
+.I patch
+to ignore this patch from the patch file, but continue on looking
+for the next patch in the file.
+Thus
+.sp
+ patch -S + -S + <patchfile
+.sp
+will ignore the first and second of three patches.
+.TP 5
+.B \-u
+forces
+.I patch
+to interpret the patch file as a unified context diff (a unidiff).
+.TP 5
+.B \-v
+causes
+.I patch
+to print out its revision header and patch level.
+.TP 5
+.B \-V
+causes the next argument to be interpreted as a method for creating
+backup file names. The type of backups made can also be given in the
+.B VERSION_CONTROL
+environment variable, which is overridden by this option.
+The
+.B -B
+option overrides this option, causing the prefix to always be used for
+making backup file names.
+The value of the
+.B VERSION_CONTROL
+environment variable and the argument to the
+.B -V
+option are like the GNU
+Emacs `version-control' variable; they also recognize synonyms that
+are more descriptive. The valid values are (unique abbreviations are
+accepted):
+.RS
+.TP
+`t' or `numbered'
+Always make numbered backups.
+.TP
+`nil' or `existing'
+Make numbered backups of files that already
+have them, simple backups of the others.
+This is the default.
+.TP
+`never' or `simple'
+Always make simple backups.
+.RE
+.TP 5
+.B \-x<number>
+sets internal debugging flags, and is of interest only to
+.I patch
+patchers.
+.SH AUTHOR
+Larry Wall <lwall@netlabs.com>
+.br
+with many other contributors.
+.SH ENVIRONMENT
+.TP
+.B TMPDIR
+Directory to put temporary files in; default is /tmp.
+.TP
+.B SIMPLE_BACKUP_SUFFIX
+Extension to use for backup file names instead of \*(L".orig\*(R" or
+\*(L"~\*(R".
+.TP
+.B VERSION_CONTROL
+Selects when numbered backup files are made.
+.SH FILES
+$TMPDIR/patch*
+.SH SEE ALSO
+diff(1)
+.SH NOTES FOR PATCH SENDERS
+There are several things you should bear in mind if you are going to
+be sending out patches.
+First, you can save people a lot of grief by keeping a patchlevel.h file
+which is patched to increment the patch level as the first diff in the
+patch file you send out.
+If you put a Prereq: line in with the patch, it won't let them apply
+patches out of order without some warning.
+Second, make sure you've specified the filenames right, either in a
+context diff header, or with an Index: line.
+If you are patching something in a subdirectory, be sure to tell the patch
+user to specify a
+.B \-p
+switch as needed.
+Third, you can create a file by sending out a diff that compares a
+null file to the file you want to create.
+This will only work if the file you want to create doesn't exist already in
+the target directory.
+Fourth, take care not to send out reversed patches, since it makes people wonder
+whether they already applied the patch.
+Fifth, while you may be able to get away with putting 582 diff listings into
+one file, it is probably wiser to group related patches into separate files in
+case something goes haywire.
+.SH DIAGNOSTICS
+Too many to list here, but generally indicative that
+.I patch
+couldn't parse your patch file.
+.PP
+The message \*(L"Hmm...\*(R" indicates that there is unprocessed text in
+the patch file and that
+.I patch
+is attempting to intuit whether there is a patch in that text and, if so,
+what kind of patch it is.
+.PP
+.I Patch
+will exit with a non-zero status if any reject files were created.
+When applying a set of patches in a loop it behooves you to check this
+exit status so you don't apply a later patch to a partially patched file.
+.SH CAVEATS
+.I Patch
+cannot tell if the line numbers are off in an ed script, and can only detect
+bad line numbers in a normal diff when it finds a \*(L"change\*(R" or
+a \*(L"delete\*(R" command.
+A context diff using fuzz factor 3 may have the same problem.
+Until a suitable interactive interface is added, you should probably do
+a context diff in these cases to see if the changes made sense.
+Of course, compiling without errors is a pretty good indication that the patch
+worked, but not always.
+.PP
+.I Patch
+usually produces the correct results, even when it has to do a lot of
+guessing.
+However, the results are guaranteed to be correct only when the patch is
+applied to exactly the same version of the file that the patch was
+generated from.
+.SH BUGS
+Could be smarter about partial matches, excessively \&deviant offsets and
+swapped code, but that would take an extra pass.
+.PP
+If code has been duplicated (for instance with #ifdef OLDCODE ... #else ...
+#endif),
+.I patch
+is incapable of patching both versions, and, if it works at all, will likely
+patch the wrong one, and tell you that it succeeded to boot.
+.PP
+If you apply a patch you've already applied,
+.I patch
+will think it is a reversed patch, and offer to un-apply the patch.
+This could be construed as a feature.
+.rn }` ''
diff --git a/xc/util/patch/patchlevel.h b/xc/util/patch/patchlevel.h
new file mode 100644
index 000000000..c1169f19a
--- /dev/null
+++ b/xc/util/patch/patchlevel.h
@@ -0,0 +1,2 @@
+/* $XConsortium: patchlevel.h,v 3.2 94/09/14 21:31:55 gildea Exp $ */
+#define PATCHLEVEL "12u9.XC2"
diff --git a/xc/util/patch/pch.c b/xc/util/patch/pch.c
new file mode 100644
index 000000000..5bb7fd141
--- /dev/null
+++ b/xc/util/patch/pch.c
@@ -0,0 +1,1313 @@
+/* oldHeader: pch.c,v 2.0.1.7 88/06/03 15:13:28 lwall Locked $
+ * $XConsortium: pch.c,v 3.3 94/09/14 21:22:55 gildea Exp $
+ *
+ * Revision 2.0.2.0 90/05/01 22:17:51 davison
+ * patch12u: unidiff support added
+ *
+ * Revision 2.0.1.7 88/06/03 15:13:28 lwall
+ * patch10: Can now find patches in shar scripts.
+ * patch10: Hunks that swapped and then swapped back could core dump.
+ *
+ * Revision 2.0.1.6 87/06/04 16:18:13 lwall
+ * pch_swap didn't swap p_bfake and p_efake.
+ *
+ * Revision 2.0.1.5 87/01/30 22:47:42 lwall
+ * Improved responses to mangled patches.
+ *
+ * Revision 2.0.1.4 87/01/05 16:59:53 lwall
+ * New-style context diffs caused double call to free().
+ *
+ * Revision 2.0.1.3 86/11/14 10:08:33 lwall
+ * Fixed problem where a long pattern wouldn't grow the hunk.
+ * Also restored p_input_line when backtracking so error messages are right.
+ *
+ * Revision 2.0.1.2 86/11/03 17:49:52 lwall
+ * New-style delete triggers spurious assertion error.
+ *
+ * Revision 2.0.1.1 86/10/29 15:52:08 lwall
+ * Could falsely report new-style context diff.
+ *
+ * Revision 2.0 86/09/17 15:39:37 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "INTERN.h"
+#include "pch.h"
+
+/* Patch (diff listing) abstract type. */
+
+static long p_filesize; /* size of the patch file */
+static LINENUM p_first; /* 1st line number */
+static LINENUM p_newfirst; /* 1st line number of replacement */
+static LINENUM p_ptrn_lines; /* # lines in pattern */
+static LINENUM p_repl_lines; /* # lines in replacement text */
+static LINENUM p_end = -1; /* last line in hunk */
+static LINENUM p_max; /* max allowed value of p_end */
+static LINENUM p_context = 3; /* # of context lines */
+static LINENUM p_input_line = 0; /* current line # from patch file */
+static char **p_line = Null(char**); /* the text of the hunk */
+static short *p_len = Null(short*); /* length of each line */
+static char *p_char = Nullch; /* +, -, and ! */
+static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */
+static int p_indent; /* indent to patch */
+static LINENUM p_base; /* where to intuit this time */
+static LINENUM p_bline; /* line # of p_base */
+static LINENUM p_start; /* where intuit found a patch */
+static LINENUM p_sline; /* and the line number for it */
+static LINENUM p_hunk_beg; /* line number of current hunk */
+static LINENUM p_efake = -1; /* end of faked up lines--don't free */
+static LINENUM p_bfake = -1; /* beg of faked up lines */
+
+/* Prepare to look for the next patch in the patch file. */
+
+void
+re_patch()
+{
+ p_first = Nulline;
+ p_newfirst = Nulline;
+ p_ptrn_lines = Nulline;
+ p_repl_lines = Nulline;
+ p_end = (LINENUM)-1;
+ p_max = Nulline;
+ p_indent = 0;
+}
+
+/* Open the patch file at the beginning of time. */
+
+void
+open_patch_file(filename)
+char *filename;
+{
+ if (filename == Nullch || !*filename || strEQ(filename, "-")) {
+ pfp = fopen(TMPPATNAME, "w");
+ if (pfp == Nullfp)
+ pfatal2("can't create %s", TMPPATNAME);
+ while (fgets(buf, sizeof buf, stdin) != Nullch)
+ fputs(buf, pfp);
+ Fclose(pfp);
+ filename = TMPPATNAME;
+ }
+ pfp = fopen(filename, "r");
+ if (pfp == Nullfp)
+ pfatal2("patch file %s not found", filename);
+ Fstat(fileno(pfp), &filestat);
+ p_filesize = filestat.st_size;
+ next_intuit_at(0L,1L); /* start at the beginning */
+ set_hunkmax();
+}
+
+/* Make sure our dynamically realloced tables are malloced to begin with. */
+
+void
+set_hunkmax()
+{
+#ifndef lint
+ if (p_line == Null(char**))
+ p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
+ if (p_len == Null(short*))
+ p_len = (short*) malloc((MEM)hunkmax * sizeof(short));
+#endif
+ if (p_char == Nullch)
+ p_char = (char*) malloc((MEM)hunkmax * sizeof(char));
+}
+
+/* Enlarge the arrays containing the current hunk of patch. */
+
+void
+grow_hunkmax()
+{
+ hunkmax *= 2;
+ /*
+ * Note that on most systems, only the p_line array ever gets fresh memory
+ * since p_len can move into p_line's old space, and p_char can move into
+ * p_len's old space. Not on PDP-11's however. But it doesn't matter.
+ */
+ assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch);
+#ifndef lint
+ p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));
+ p_len = (short*) realloc((char*)p_len, (MEM)hunkmax * sizeof(short));
+ p_char = (char*) realloc((char*)p_char, (MEM)hunkmax * sizeof(char));
+#endif
+ if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch)
+ return;
+ if (!using_plan_a)
+ fatal1("out of memory\n");
+ out_of_mem = TRUE; /* whatever is null will be allocated again */
+ /* from within plan_a(), of all places */
+}
+
+/* True if the remainder of the patch file contains a diff of some sort. */
+
+bool
+there_is_another_patch()
+{
+ if (p_base != 0L && p_base >= p_filesize) {
+ if (verbose)
+ say1("done\n");
+ return FALSE;
+ }
+ if (verbose)
+ say1("Hmm...");
+ diff_type = intuit_diff_type();
+ if (!diff_type) {
+ if (p_base != 0L) {
+ if (verbose)
+ say1(" Ignoring the trailing garbage.\ndone\n");
+ }
+ else
+ say1(" I can't seem to find a patch in there anywhere.\n");
+ return FALSE;
+ }
+ if (verbose)
+ say3(" %sooks like %s to me...\n",
+ (p_base == 0L ? "L" : "The next patch l"),
+ diff_type == UNI_DIFF ? "a unified diff" :
+ diff_type == CONTEXT_DIFF ? "a context diff" :
+ diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
+ diff_type == NORMAL_DIFF ? "a normal diff" :
+ "an ed script" );
+ if (p_indent && verbose)
+ say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");
+ skip_to(p_start,p_sline);
+ while (filearg[0] == Nullch) {
+ if (force || batch) {
+ say1("No file to patch. Skipping...\n");
+ filearg[0] = savestr(bestguess);
+ skip_rest_of_patch = TRUE;
+ return TRUE;
+ }
+ ask1("File to patch: ");
+ if (*buf != '\n') {
+ if (bestguess)
+ free(bestguess);
+ bestguess = savestr(buf);
+ filearg[0] = fetchname(buf, 0, FALSE);
+ }
+ if (filearg[0] == Nullch) {
+#ifndef WIN32
+ ask1("No file found--skip this patch? [n] ");
+ if (*buf != 'y') {
+ continue;
+ }
+ if (verbose)
+ say1("Skipping patch...\n");
+#else
+ if (verbose)
+ say1("File not found--skipping patch...\n");
+#endif
+ filearg[0] = fetchname(bestguess, 0, TRUE);
+ skip_rest_of_patch = TRUE;
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
+/* Determine what kind of diff is in the remaining part of the patch file. */
+
+int
+intuit_diff_type()
+{
+ Reg4 long this_line = 0;
+ Reg5 long previous_line;
+ Reg6 long first_command_line = -1;
+ long fcl_line;
+ Reg7 bool last_line_was_command = FALSE;
+ Reg8 bool this_is_a_command = FALSE;
+ Reg9 bool stars_last_line = FALSE;
+ Reg10 bool stars_this_line = FALSE;
+ Reg3 int indent;
+ Reg1 char *s;
+ Reg2 char *t;
+ char *indtmp = Nullch;
+ char *oldtmp = Nullch;
+ char *newtmp = Nullch;
+ char *indname = Nullch;
+ char *oldname = Nullch;
+ char *newname = Nullch;
+ Reg11 int retval;
+ bool no_filearg = (filearg[0] == Nullch);
+
+ ok_to_create_file = FALSE;
+ Fseek(pfp, p_base, 0);
+ p_input_line = p_bline - 1;
+ for (;;) {
+ previous_line = this_line;
+ last_line_was_command = this_is_a_command;
+ stars_last_line = stars_this_line;
+ this_line = ftell(pfp);
+ indent = 0;
+ p_input_line++;
+ if (fgets(buf, sizeof buf, pfp) == Nullch) {
+ if (first_command_line >= 0L) {
+ /* nothing but deletes!? */
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ else {
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = 0;
+ goto scan_exit;
+ }
+ }
+ for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
+ if (*s == '\t')
+ indent += 8 - (indent % 8);
+ else
+ indent++;
+ }
+ for (t=s; isdigit(*t) || *t == ','; t++) ;
+ this_is_a_command = (isdigit(*s) &&
+ (*t == 'd' || *t == 'c' || *t == 'a') );
+ if (first_command_line < 0L && this_is_a_command) {
+ first_command_line = this_line;
+ fcl_line = p_input_line;
+ p_indent = indent; /* assume this for now */
+ }
+ if (!stars_last_line && strnEQ(s, "*** ", 4))
+ oldtmp = savestr(s+4);
+ else if (strnEQ(s, "--- ", 4))
+ newtmp = savestr(s+4);
+ else if (strnEQ(s, "+++ ", 4))
+ oldtmp = savestr(s+4); /* pretend it is the old name */
+ else if (strnEQ(s, "Index:", 6))
+ indtmp = savestr(s+6);
+ else if (strnEQ(s, "Prereq:", 7)) {
+ for (t=s+7; isspace(*t); t++) ;
+ revision = savestr(t);
+ for (t=revision; *t && !isspace(*t); t++) ;
+ *t = '\0';
+ if (!*revision) {
+ free(revision);
+ revision = Nullch;
+ }
+ }
+ if ((!diff_type || diff_type == ED_DIFF) &&
+ first_command_line >= 0L &&
+ strEQ(s, ".\n") ) {
+ p_indent = indent;
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
+ if (!atol(s+3))
+ ok_to_create_file = TRUE;
+ p_indent = indent;
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = UNI_DIFF;
+ goto scan_exit;
+ }
+ stars_this_line = strnEQ(s, "********", 8);
+ if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
+ strnEQ(s, "*** ", 4)) {
+ if (!atol(s+4))
+ ok_to_create_file = TRUE;
+ /* if this is a new context diff the character just before */
+ /* the newline is a '*'. */
+ while (*s != '\n')
+ s++;
+ p_indent = indent;
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
+ goto scan_exit;
+ }
+ if ((!diff_type || diff_type == NORMAL_DIFF) &&
+ last_line_was_command &&
+ (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ p_indent = indent;
+ retval = NORMAL_DIFF;
+ goto scan_exit;
+ }
+ }
+ scan_exit:
+ if (no_filearg) {
+ if (indtmp != Nullch)
+ indname = fetchname(indtmp, strippath, ok_to_create_file);
+ if (oldtmp != Nullch)
+ oldname = fetchname(oldtmp, strippath, ok_to_create_file);
+ if (newtmp != Nullch)
+ newname = fetchname(newtmp, strippath, ok_to_create_file);
+ if (oldname && newname) {
+ if (strlen(oldname) < strlen(newname))
+ filearg[0] = savestr(oldname);
+ else
+ filearg[0] = savestr(newname);
+ }
+ else if (oldname)
+ filearg[0] = savestr(oldname);
+ else if (newname)
+ filearg[0] = savestr(newname);
+ else if (indname)
+ filearg[0] = savestr(indname);
+ }
+ if (bestguess) {
+ free(bestguess);
+ bestguess = Nullch;
+ }
+ if (filearg[0] != Nullch)
+ bestguess = savestr(filearg[0]);
+ else if (indtmp != Nullch)
+ bestguess = fetchname(indtmp, strippath, TRUE);
+ else {
+ if (oldtmp != Nullch)
+ oldname = fetchname(oldtmp, strippath, TRUE);
+ if (newtmp != Nullch)
+ newname = fetchname(newtmp, strippath, TRUE);
+ if (oldname && newname) {
+ if (strlen(oldname) < strlen(newname))
+ bestguess = savestr(oldname);
+ else
+ bestguess = savestr(newname);
+ }
+ else if (oldname)
+ bestguess = savestr(oldname);
+ else if (newname)
+ bestguess = savestr(newname);
+ }
+ if (indtmp != Nullch)
+ free(indtmp);
+ if (oldtmp != Nullch)
+ free(oldtmp);
+ if (newtmp != Nullch)
+ free(newtmp);
+ if (indname != Nullch)
+ free(indname);
+ if (oldname != Nullch)
+ free(oldname);
+ if (newname != Nullch)
+ free(newname);
+ return retval;
+}
+
+/* Remember where this patch ends so we know where to start up again. */
+
+void
+next_intuit_at(file_pos,file_line)
+long file_pos;
+long file_line;
+{
+ p_base = file_pos;
+ p_bline = file_line;
+}
+
+/* Basically a verbose fseek() to the actual diff listing. */
+
+void
+skip_to(file_pos,file_line)
+long file_pos;
+long file_line;
+{
+ char *ret;
+
+ assert(p_base <= file_pos);
+ if (verbose && p_base < file_pos) {
+ Fseek(pfp, p_base, 0);
+ say1("The text leading up to this was:\n--------------------------\n");
+ while (ftell(pfp) < file_pos) {
+ ret = fgets(buf, sizeof buf, pfp);
+ assert(ret != Nullch);
+ say2("|%s", buf);
+ }
+ say1("--------------------------\n");
+ }
+ else
+ Fseek(pfp, file_pos, 0);
+ p_input_line = file_line - 1;
+}
+
+/* Make this a function for better debugging. */
+static void
+malformed ()
+{
+ fatal3("malformed patch at line %ld: %s", p_input_line, buf);
+ /* about as informative as "Syntax error" in C */
+}
+
+/* True if there is more of the current diff listing to process. */
+
+bool
+another_hunk()
+{
+ Reg1 char *s;
+ Reg8 char *ret;
+ Reg2 int context = 0;
+
+ while (p_end >= 0) {
+ if (p_end == p_efake)
+ p_end = p_bfake; /* don't free twice */
+ else
+ free(p_line[p_end]);
+ p_end--;
+ }
+ assert(p_end == -1);
+ p_efake = -1;
+
+ p_max = hunkmax; /* gets reduced when --- found */
+ if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
+ long line_beginning = ftell(pfp);
+ /* file pos of the current line */
+ LINENUM repl_beginning = 0; /* index of --- line */
+ Reg4 LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */
+ Reg5 LINENUM fillsrc; /* index of first line to copy */
+ Reg6 LINENUM filldst; /* index of first missing line */
+ bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */
+ Reg9 bool repl_could_be_missing = TRUE;
+ /* no + or ! lines in this hunk */
+ bool repl_missing = FALSE; /* we are now backtracking */
+ long repl_backtrack_position = 0;
+ /* file pos of first repl line */
+ LINENUM repl_patch_line; /* input line number for same */
+ Reg7 LINENUM ptrn_copiable = 0;
+ /* # of copiable lines in ptrn */
+
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch || strnNE(buf, "********", 8)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return FALSE;
+ }
+ p_context = 100;
+ p_hunk_beg = p_input_line + 1;
+ while (p_end < p_max) {
+ line_beginning = ftell(pfp);
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch) {
+ if (p_max - p_end < 4)
+ Strcpy(buf, " \n"); /* assume blank lines got chopped */
+ else {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal1("unexpected end of file in patch\n");
+ }
+ }
+ p_end++;
+ assert(p_end < hunkmax);
+ p_char[p_end] = *buf;
+#ifdef zilog
+ p_line[(short)p_end] = Nullch;
+#else
+ p_line[p_end] = Nullch;
+#endif
+ switch (*buf) {
+ case '*':
+ if (strnEQ(buf, "********", 8)) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ else
+ fatal2("unexpected end of hunk at line %ld\n",
+ p_input_line);
+ }
+ if (p_end != 0) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal3("unexpected *** at line %ld: %s", p_input_line, buf);
+ }
+ context = 0;
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ for (s=buf; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ malformed ();
+ if (strnEQ(s,"0,0",3))
+ strcpy(s,s+2);
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ malformed ();
+ p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
+ }
+ else if (p_first)
+ p_ptrn_lines = 1;
+ else {
+ p_ptrn_lines = 0;
+ p_first = 1;
+ }
+ p_max = p_ptrn_lines + 6; /* we need this much at least */
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ p_max = hunkmax;
+ break;
+ case '-':
+ if (buf[1] == '-') {
+ if (repl_beginning ||
+ (p_end != p_ptrn_lines + 1 + (p_char[p_end-1] == '\n')))
+ {
+ if (p_end == 1) {
+ /* `old' lines were omitted - set up to fill */
+ /* them in from 'new' context lines. */
+ p_end = p_ptrn_lines + 1;
+ fillsrc = p_end + 1;
+ filldst = 1;
+ fillcnt = p_ptrn_lines;
+ }
+ else {
+ if (repl_beginning) {
+ if (repl_could_be_missing){
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ fatal3(
+"duplicate \"---\" at line %ld--check line numbers at line %ld\n",
+ p_input_line, p_hunk_beg + repl_beginning);
+ }
+ else {
+ fatal4(
+"%s \"---\" at line %ld--check line numbers at line %ld\n",
+ (p_end <= p_ptrn_lines
+ ? "Premature"
+ : "Overdue" ),
+ p_input_line, p_hunk_beg);
+ }
+ }
+ }
+ repl_beginning = p_end;
+ repl_backtrack_position = ftell(pfp);
+ repl_patch_line = p_input_line;
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ p_char[p_end] = '=';
+ for (s=buf; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ malformed ();
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++) ;
+ if (!*s)
+ malformed ();
+ p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;
+ }
+ else if (p_newfirst)
+ p_repl_lines = 1;
+ else {
+ p_repl_lines = 0;
+ p_newfirst = 1;
+ }
+ p_max = p_repl_lines + p_end;
+ if (p_max > MAXHUNKSIZE)
+ fatal4("hunk too large (%ld lines) at line %ld: %s",
+ p_max, p_input_line, buf);
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ if (p_repl_lines != ptrn_copiable
+ && (p_context != 0 || p_repl_lines != 1))
+ repl_could_be_missing = FALSE;
+ break;
+ }
+ goto change_line;
+ case '+': case '!':
+ repl_could_be_missing = FALSE;
+ change_line:
+ if (buf[1] == '\n' && canonicalize)
+ strcpy(buf+1," \n");
+ if (!isspace(buf[1]) && buf[1] != '>' && buf[1] != '<' &&
+ repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ if (context >= 0) {
+ if (context < p_context)
+ p_context = context;
+ context = -1000;
+ }
+ p_line[p_end] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ break;
+ case '\t': case '\n': /* assume the 2 spaces got eaten */
+ if (repl_beginning && repl_could_be_missing &&
+ (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ if (p_end != p_ptrn_lines + 1) {
+ ptrn_spaces_eaten |= (repl_beginning != 0);
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_char[p_end] = ' ';
+ }
+ break;
+ case ' ':
+ if (!isspace(buf[1]) &&
+ repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_line[p_end] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end--;
+ return FALSE;
+ }
+ break;
+ default:
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = TRUE;
+ goto hunk_done;
+ }
+ malformed ();
+ }
+ /* set up p_len for strncmp() so we don't have to */
+ /* assume null termination */
+ if (p_line[p_end])
+ p_len[p_end] = strlen(p_line[p_end]);
+ else
+ p_len[p_end] = 0;
+ }
+
+ hunk_done:
+ if (p_end >=0 && !repl_beginning)
+ fatal2("no --- found in patch at line %ld\n", pch_hunk_beg());
+
+ if (repl_missing) {
+
+ /* reset state back to just after --- */
+ p_input_line = repl_patch_line;
+ for (p_end--; p_end > repl_beginning; p_end--)
+ free(p_line[p_end]);
+ Fseek(pfp, repl_backtrack_position, 0);
+
+ /* redundant 'new' context lines were omitted - set */
+ /* up to fill them in from the old file context */
+ if (!p_context && p_repl_lines == 1) {
+ p_repl_lines = 0;
+ p_max--;
+ }
+ fillsrc = 1;
+ filldst = repl_beginning+1;
+ fillcnt = p_repl_lines;
+ p_end = p_max;
+ }
+ else if (!p_context && fillcnt == 1) {
+ /* the first hunk was a null hunk with no context */
+ /* and we were expecting one line -- fix it up. */
+ while (filldst < p_end) {
+ p_line[filldst] = p_line[filldst+1];
+ p_char[filldst] = p_char[filldst+1];
+ p_len[filldst] = p_len[filldst+1];
+ filldst++;
+ }
+#if 0
+ repl_beginning--; /* this doesn't need to be fixed */
+#endif
+ p_end--;
+ p_first++; /* do append rather than insert */
+ fillcnt = 0;
+ p_ptrn_lines = 0;
+ }
+
+ if (diff_type == CONTEXT_DIFF &&
+ (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) {
+ if (verbose)
+ say4("%s\n%s\n%s\n",
+"(Fascinating--this is really a new-style context diff but without",
+"the telltale extra asterisks on the *** line that usually indicate",
+"the new style...)");
+ diff_type = NEW_CONTEXT_DIFF;
+ }
+
+ /* if there were omitted context lines, fill them in now */
+ if (fillcnt) {
+ p_bfake = filldst; /* remember where not to free() */
+ p_efake = filldst + fillcnt - 1;
+ while (fillcnt-- > 0) {
+ while (fillsrc <= p_end && p_char[fillsrc] != ' ')
+ fillsrc++;
+ if (fillsrc > p_end)
+ fatal2("replacement text or line numbers mangled in hunk at line %ld\n",
+ p_hunk_beg);
+ p_line[filldst] = p_line[fillsrc];
+ p_char[filldst] = p_char[fillsrc];
+ p_len[filldst] = p_len[fillsrc];
+ fillsrc++; filldst++;
+ }
+ while (fillsrc <= p_end && fillsrc != repl_beginning &&
+ p_char[fillsrc] != ' ')
+ fillsrc++;
+#ifdef DEBUGGING
+ if (debug & 64)
+ printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
+ fillsrc,filldst,repl_beginning,p_end+1);
+#endif
+ assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
+ assert(filldst==p_end+1 || filldst==repl_beginning);
+ }
+ }
+ else if (diff_type == UNI_DIFF) {
+ long line_beginning = ftell(pfp);
+ /* file pos of the current line */
+ Reg4 LINENUM fillsrc; /* index of old lines */
+ Reg5 LINENUM filldst; /* index of new lines */
+ char ch;
+
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch || strnNE(buf, "@@ -", 4)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return FALSE;
+ }
+ s = buf+4;
+ if (!*s)
+ malformed ();
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM) atol(++s);
+ while (isdigit(*s)) s++;
+ } else
+ p_ptrn_lines = 1;
+ if (*s == ' ') s++;
+ if (*s != '+' || !*++s)
+ malformed ();
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s)) s++;
+ if (*s == ',') {
+ p_repl_lines = (LINENUM) atol(++s);
+ while (isdigit(*s)) s++;
+ } else
+ p_repl_lines = 1;
+ if (*s == ' ') s++;
+ if (*s != '@')
+ malformed ();
+ if (!p_ptrn_lines)
+ p_first++; /* do append rather than insert */
+ p_max = p_ptrn_lines + p_repl_lines + 1;
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ fillsrc = 1;
+ filldst = fillsrc + p_ptrn_lines;
+ p_end = filldst + p_repl_lines;
+ Sprintf(buf,"*** %ld,%ld ****\n",p_first,p_first + p_ptrn_lines - 1);
+ p_line[0] = savestr(buf);
+ if (out_of_mem) {
+ p_end = -1;
+ return FALSE;
+ }
+ p_char[0] = '*';
+ Sprintf(buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1);
+ p_line[filldst] = savestr(buf);
+ if (out_of_mem) {
+ p_end = 0;
+ return FALSE;
+ }
+ p_char[filldst++] = '=';
+ p_context = 100;
+ context = 0;
+ p_hunk_beg = p_input_line + 1;
+ while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
+ line_beginning = ftell(pfp);
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch) {
+ if (p_max - filldst < 3)
+ Strcpy(buf, " \n"); /* assume blank lines got chopped */
+ else {
+ fatal1("unexpected end of file in patch\n");
+ }
+ }
+ if (*buf == '\t' || *buf == '\n') {
+ ch = ' '; /* assume the space got eaten */
+ s = savestr(buf);
+ }
+ else {
+ ch = *buf;
+ s = savestr(buf+1);
+ }
+ if (out_of_mem) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ return FALSE;
+ }
+ switch (ch) {
+ case '-':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ p_end = filldst-1;
+ malformed ();
+ }
+ p_char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = strlen(s);
+ break;
+ case '=':
+ ch = ' ';
+ /* FALL THROUGH */
+ case ' ':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ malformed ();
+ }
+ context++;
+ p_char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = strlen(s);
+ s = savestr(s);
+ if (out_of_mem) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ return FALSE;
+ }
+ /* FALL THROUGH */
+ case '+':
+ if (filldst > p_end) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc-1;
+ malformed ();
+ }
+ p_char[filldst] = ch;
+ p_line[filldst] = s;
+ p_len[filldst++] = strlen(s);
+ break;
+ default:
+ p_end = filldst;
+ malformed ();
+ }
+ if (ch != ' ' && context > 0) {
+ if (context < p_context)
+ p_context = context;
+ context = -1000;
+ }
+ }/* while */
+ }
+ else { /* normal diff--fake it up */
+ char hunk_type;
+ Reg3 int i;
+ LINENUM min, max;
+ long line_beginning = ftell(pfp);
+
+ p_context = 0;
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch || !isdigit(*buf)) {
+ next_intuit_at(line_beginning,p_input_line);
+ return FALSE;
+ }
+ p_first = (LINENUM)atol(buf);
+ for (s=buf; isdigit(*s); s++) ;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
+ while (isdigit(*s)) s++;
+ }
+ else
+ p_ptrn_lines = (*s != 'a');
+ hunk_type = *s;
+ if (hunk_type == 'a')
+ p_first++; /* do append rather than insert */
+ min = (LINENUM)atol(++s);
+ for (; isdigit(*s); s++) ;
+ if (*s == ',')
+ max = (LINENUM)atol(++s);
+ else
+ max = min;
+ if (hunk_type == 'd')
+ min++;
+ p_end = p_ptrn_lines + 1 + max - min + 1;
+ if (p_end > MAXHUNKSIZE)
+ fatal4("hunk too large (%ld lines) at line %ld: %s",
+ p_end, p_input_line, buf);
+ while (p_end >= hunkmax)
+ grow_hunkmax();
+ p_newfirst = min;
+ p_repl_lines = max - min + 1;
+ Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1);
+ p_line[0] = savestr(buf);
+ if (out_of_mem) {
+ p_end = -1;
+ return FALSE;
+ }
+ p_char[0] = '*';
+ for (i=1; i<=p_ptrn_lines; i++) {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch)
+ fatal2("unexpected end of file in patch at line %ld\n",
+ p_input_line);
+ if (*buf != '<')
+ fatal2("< expected at line %ld of patch\n", p_input_line);
+ p_line[i] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end = i-1;
+ return FALSE;
+ }
+ p_len[i] = strlen(p_line[i]);
+ p_char[i] = '-';
+ }
+ if (hunk_type == 'c') {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch)
+ fatal2("unexpected end of file in patch at line %ld\n",
+ p_input_line);
+ if (*buf != '-')
+ fatal2("--- expected at line %ld of patch\n", p_input_line);
+ }
+ Sprintf(buf, "--- %ld,%ld\n", min, max);
+ p_line[i] = savestr(buf);
+ if (out_of_mem) {
+ p_end = i-1;
+ return FALSE;
+ }
+ p_char[i] = '=';
+ for (i++; i<=p_end; i++) {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == Nullch)
+ fatal2("unexpected end of file in patch at line %ld\n",
+ p_input_line);
+ if (*buf != '>')
+ fatal2("> expected at line %ld of patch\n", p_input_line);
+ p_line[i] = savestr(buf+2);
+ if (out_of_mem) {
+ p_end = i-1;
+ return FALSE;
+ }
+ p_len[i] = strlen(p_line[i]);
+ p_char[i] = '+';
+ }
+ }
+ if (reverse) /* backwards patch? */
+ if (!pch_swap())
+ say1("Not enough memory to swap next hunk!\n");
+#ifdef DEBUGGING
+ if (debug & 2) {
+ int i;
+ char special;
+
+ for (i=0; i <= p_end; i++) {
+ if (i == p_ptrn_lines)
+ special = '^';
+ else
+ special = ' ';
+ fprintf(stderr, "%3d %c %c %s", i, p_char[i], special, p_line[i]);
+ Fflush(stderr);
+ }
+ }
+#endif
+ if (p_end+1 < hunkmax) /* paranoia reigns supreme... */
+ p_char[p_end+1] = '^'; /* add a stopper for apply_hunk */
+ return TRUE;
+}
+
+/* Input a line from the patch file, worrying about indentation. */
+
+char *
+pgets(bf,sz,fp)
+char *bf;
+int sz;
+FILE *fp;
+{
+ char *ret = fgets(bf, sz, fp);
+ Reg1 char *s;
+ Reg2 int indent = 0;
+
+ if (p_indent && ret != Nullch) {
+ for (s=buf;
+ indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); s++) {
+ if (*s == '\t')
+ indent += 8 - (indent % 7);
+ else
+ indent++;
+ }
+ if (buf != s)
+ Strcpy(buf, s);
+ }
+ return ret;
+}
+
+/* Reverse the old and new portions of the current hunk. */
+
+bool
+pch_swap()
+{
+ char **tp_line; /* the text of the hunk */
+ short *tp_len; /* length of each line */
+ char *tp_char; /* +, -, and ! */
+ Reg1 LINENUM i;
+ Reg2 LINENUM n;
+ bool blankline = FALSE;
+ Reg3 char *s;
+
+ i = p_first;
+ p_first = p_newfirst;
+ p_newfirst = i;
+
+ /* make a scratch copy */
+
+ tp_line = p_line;
+ tp_len = p_len;
+ tp_char = p_char;
+ p_line = Null(char**); /* force set_hunkmax to allocate again */
+ p_len = Null(short*);
+ p_char = Nullch;
+ set_hunkmax();
+ if (p_line == Null(char**) || p_len == Null(short*) || p_char == Nullch) {
+#ifndef lint
+ if (p_line == Null(char**))
+ free((char*)p_line);
+ p_line = tp_line;
+ if (p_len == Null(short*))
+ free((char*)p_len);
+ p_len = tp_len;
+#endif
+ if (p_char == Nullch)
+ free((char*)p_char);
+ p_char = tp_char;
+ return FALSE; /* not enough memory to swap hunk! */
+ }
+
+ /* now turn the new into the old */
+
+ i = p_ptrn_lines + 1;
+ if (tp_char[i] == '\n') { /* account for possible blank line */
+ blankline = TRUE;
+ i++;
+ }
+ if (p_efake >= 0) { /* fix non-freeable ptr range */
+ if (p_efake <= i)
+ n = p_end - i + 1;
+ else
+ n = -i;
+ p_efake += n;
+ p_bfake += n;
+ }
+ for (n=0; i <= p_end; i++,n++) {
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ if (p_char[n] == '+')
+ p_char[n] = '-';
+ p_len[n] = tp_len[i];
+ }
+ if (blankline) {
+ i = p_ptrn_lines + 1;
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ p_len[n] = tp_len[i];
+ n++;
+ }
+ assert(p_char[0] == '=');
+ p_char[0] = '*';
+ for (s=p_line[0]; *s; s++)
+ if (*s == '-')
+ *s = '*';
+
+ /* now turn the old into the new */
+
+ assert(tp_char[0] == '*');
+ tp_char[0] = '=';
+ for (s=tp_line[0]; *s; s++)
+ if (*s == '*')
+ *s = '-';
+ for (i=0; n <= p_end; i++,n++) {
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ if (p_char[n] == '-')
+ p_char[n] = '+';
+ p_len[n] = tp_len[i];
+ }
+ assert(i == p_ptrn_lines + 1);
+ i = p_ptrn_lines;
+ p_ptrn_lines = p_repl_lines;
+ p_repl_lines = i;
+#ifndef lint
+ if (tp_line == Null(char**))
+ free((char*)tp_line);
+ if (tp_len == Null(short*))
+ free((char*)tp_len);
+#endif
+ if (tp_char == Nullch)
+ free((char*)tp_char);
+ return TRUE;
+}
+
+/* Return the specified line position in the old file of the old context. */
+
+LINENUM
+pch_first()
+{
+ return p_first;
+}
+
+/* Return the number of lines of old context. */
+
+LINENUM
+pch_ptrn_lines()
+{
+ return p_ptrn_lines;
+}
+
+/* Return the probable line position in the new file of the first line. */
+
+LINENUM
+pch_newfirst()
+{
+ return p_newfirst;
+}
+
+/* Return the number of lines in the replacement text including context. */
+
+LINENUM
+pch_repl_lines()
+{
+ return p_repl_lines;
+}
+
+/* Return the number of lines in the whole hunk. */
+
+LINENUM
+pch_end()
+{
+ return p_end;
+}
+
+/* Return the number of context lines before the first changed line. */
+
+LINENUM
+pch_context()
+{
+ return p_context;
+}
+
+/* Return the length of a particular patch line. */
+
+short
+pch_line_len(line)
+LINENUM line;
+{
+ return p_len[line];
+}
+
+/* Return the control character (+, -, *, !, etc) for a patch line. */
+
+char
+pch_char(line)
+LINENUM line;
+{
+ return p_char[line];
+}
+
+/* Return a pointer to a particular patch line. */
+
+char *
+pfetch(line)
+LINENUM line;
+{
+ return p_line[line];
+}
+
+/* Return where in the patch file this hunk began, for error messages. */
+
+LINENUM
+pch_hunk_beg()
+{
+ return p_hunk_beg;
+}
+
+/* Apply an ed script by feeding ed itself. */
+
+#ifndef WIN32
+void
+do_ed_script()
+{
+ Reg1 char *t;
+ Reg2 long beginning_of_this_line;
+ Reg3 bool this_line_is_command = FALSE;
+ Reg4 FILE *pipefp;
+
+ if (!skip_rest_of_patch) {
+ Unlink(TMPOUTNAME);
+ copy_file(filearg[0], TMPOUTNAME);
+ if (verbose)
+ Sprintf(buf, "/bin/ed %s", TMPOUTNAME);
+ else
+ Sprintf(buf, "/bin/ed - %s", TMPOUTNAME);
+ pipefp = popen(buf, "w");
+ }
+ for (;;) {
+ beginning_of_this_line = ftell(pfp);
+ if (pgets(buf, sizeof buf, pfp) == Nullch) {
+ next_intuit_at(beginning_of_this_line,p_input_line);
+ break;
+ }
+ p_input_line++;
+ for (t=buf; isdigit(*t) || *t == ','; t++) ;
+ this_line_is_command = (isdigit(*buf) &&
+ (*t == 'd' || *t == 'c' || *t == 'a') );
+ if (this_line_is_command) {
+ if (!skip_rest_of_patch)
+ fputs(buf, pipefp);
+ if (*t != 'd') {
+ while (pgets(buf, sizeof buf, pfp) != Nullch) {
+ p_input_line++;
+ if (!skip_rest_of_patch)
+ fputs(buf, pipefp);
+ if (strEQ(buf, ".\n"))
+ break;
+ }
+ }
+ }
+ else {
+ next_intuit_at(beginning_of_this_line,p_input_line);
+ break;
+ }
+ }
+ if (skip_rest_of_patch)
+ return;
+ fprintf(pipefp, "w\n");
+ fprintf(pipefp, "q\n");
+ Fflush(pipefp);
+ Pclose(pipefp);
+ ignore_signals();
+ if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = TRUE;
+ chmod(TMPOUTNAME, filemode);
+ }
+ else
+ chmod(outname, filemode);
+ set_signals(1);
+}
+#endif
diff --git a/xc/util/patch/pch.h b/xc/util/patch/pch.h
new file mode 100644
index 000000000..3873f28a5
--- /dev/null
+++ b/xc/util/patch/pch.h
@@ -0,0 +1,38 @@
+/* oldHeader: pch.h,v 2.0.1.1 87/01/30 22:47:16 lwall Exp $
+ * $XConsortium: pch.h,v 3.3 94/09/14 21:24:15 gildea Exp $
+ *
+ * Revision 2.0.1.1 87/01/30 22:47:16 lwall
+ * Added do_ed_script().
+ *
+ * Revision 2.0 86/09/17 15:39:57 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+EXT FILE *pfp INIT(Nullfp); /* patch file pointer */
+
+void re_patch();
+void open_patch_file();
+void set_hunkmax();
+void grow_hunkmax();
+bool there_is_another_patch();
+int intuit_diff_type();
+void next_intuit_at();
+void skip_to();
+bool another_hunk();
+bool pch_swap();
+char *pfetch();
+short pch_line_len();
+LINENUM pch_first();
+LINENUM pch_ptrn_lines();
+LINENUM pch_newfirst();
+LINENUM pch_repl_lines();
+LINENUM pch_end();
+LINENUM pch_context();
+LINENUM pch_hunk_beg();
+char pch_char();
+char *pfetch();
+char *pgets();
+#ifndef WIN32
+void do_ed_script();
+#endif
diff --git a/xc/util/patch/util.c b/xc/util/patch/util.c
new file mode 100644
index 000000000..ef70642a9
--- /dev/null
+++ b/xc/util/patch/util.c
@@ -0,0 +1,474 @@
+/* $XConsortium: util.c,v 3.3 94/09/14 21:26:09 gildea Exp $ */
+
+#define const /*nothing*/
+
+#include "EXTERN.h"
+#include "common.h"
+#include "INTERN.h"
+#include "util.h"
+#include "backupfile.h"
+
+void my_exit();
+
+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
+
+/* Rename a file, copying it if necessary. */
+
+int
+move_file(from,to)
+char *from, *to;
+{
+ char bakname[512];
+ Reg1 char *s;
+ Reg2 int i;
+ Reg3 int fromfd;
+
+ /* to stdout? */
+
+ if (strEQ(to, "-")) {
+#ifdef DEBUGGING
+ if (debug & 4)
+ say2("Moving %s to stdout.\n", from);
+#endif
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(1, buf, i) != 1)
+ pfatal1("write failed");
+ Close(fromfd);
+ return 0;
+ }
+
+ if (origprae) {
+ Strcpy(bakname, origprae);
+ Strcat(bakname, to);
+ } else {
+#ifndef NODIR
+ char *backupname = find_backup_file_name(to);
+ if (backupname == (char *) 0)
+ fatal1("out of memory\n");
+ Strcpy(bakname, backupname);
+ free(backupname);
+#else /* NODIR */
+ Strcpy(bakname, to);
+ Strcat(bakname, simple_backup_suffix);
+#endif /* NODIR */
+ }
+
+ if (stat(to, &filestat) == 0) { /* output file exists */
+ dev_t to_device = filestat.st_dev;
+ ino_t to_inode = filestat.st_ino;
+ char *simplename = bakname;
+
+ for (s=bakname; *s; s++) {
+ if (*s == '/')
+ simplename = s+1;
+ }
+ /* Find a backup name that is not the same file.
+ Change the first lowercase char into uppercase;
+ if that isn't sufficient, chop off the first char and try again. */
+ while (stat(bakname, &filestat) == 0 &&
+ to_device == filestat.st_dev && to_inode == filestat.st_ino) {
+ /* Skip initial non-lowercase chars. */
+ for (s=simplename; *s && !islower(*s); s++) ;
+ if (*s)
+ *s = toupper(*s);
+ else
+ Strcpy(simplename, simplename+1);
+ }
+ while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
+#ifdef DEBUGGING
+ if (debug & 4)
+ say3("Moving %s to %s.\n", to, bakname);
+#endif
+#ifndef WIN32
+ if (link(to, bakname) < 0) {
+ /* Maybe `to' is a symlink into a different file system.
+ Copying replaces the symlink with a file; using rename
+ would be better. */
+ Reg4 int tofd;
+ Reg5 int bakfd;
+
+ bakfd = creat(bakname, 0666);
+ if (bakfd < 0) {
+ say4("Can't backup %s, output is in %s: %s\n", to, from,
+ strerror(errno));
+ return -1;
+ }
+ tofd = open(to, 0);
+ if (tofd < 0)
+ pfatal2("internal error, can't open %s", to);
+ while ((i=read(tofd, buf, sizeof buf)) > 0)
+ if (write(bakfd, buf, i) != i)
+ pfatal1("write failed");
+ Close(tofd);
+ Close(bakfd);
+ }
+#endif
+ while (unlink(to) >= 0) ;
+ }
+#ifdef DEBUGGING
+ if (debug & 4)
+ say3("Moving %s to %s.\n", from, to);
+#endif
+#ifndef WIN32
+ if (link(from, to) < 0) { /* different file system? */
+ Reg4 int tofd;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0) {
+ say4("Can't create %s, output is in %s: %s\n",
+ to, from, strerror(errno));
+ return -1;
+ }
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal1("write failed");
+ Close(fromfd);
+ Close(tofd);
+ }
+ Unlink(from);
+#else
+ rename (from, to);
+#endif
+ return 0;
+}
+
+/* Copy a file. */
+
+void
+copy_file(from,to)
+char *from, *to;
+{
+ Reg3 int tofd;
+ Reg2 int fromfd;
+ Reg1 int i;
+
+ tofd = creat(to, 0666);
+ if (tofd < 0)
+ pfatal2("can't create %s", to);
+ fromfd = open(from, 0);
+ if (fromfd < 0)
+ pfatal2("internal error, can't reopen %s", from);
+ while ((i=read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal2("write to %s failed", to);
+ Close(fromfd);
+ Close(tofd);
+}
+
+/* Allocate a unique area for a string. */
+
+char *
+savestr(s)
+Reg1 char *s;
+{
+ Reg3 char *rv;
+ Reg2 char *t;
+
+ if (!s)
+ s = "Oops";
+ t = s;
+ while (*t++);
+ rv = malloc((MEM) (t - s));
+ if (rv == Nullch) {
+ if (using_plan_a)
+ out_of_mem = TRUE;
+ else
+ fatal1("out of memory\n");
+ }
+ else {
+ t = rv;
+ while (*t++ = *s++);
+ }
+ return rv;
+}
+
+#if defined(lint) && defined(CANVARARG)
+
+/*VARARGS ARGSUSED*/
+say(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+fatal(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+pfatal(pat) char *pat; { ; }
+/*VARARGS ARGSUSED*/
+ask(pat) char *pat; { ; }
+
+#else
+
+/* Vanilla terminal output (buffered). */
+
+void
+say(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ Fflush(stderr);
+}
+
+/* Terminal output, pun intended. */
+
+void /* very void */
+fatal(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ fprintf(stderr, "patch: **** ");
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ my_exit(1);
+}
+
+/* Say something from patch, something from the system, then silence . . . */
+
+void /* very void */
+pfatal(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+ int errnum = errno;
+
+ fprintf(stderr, "patch: **** ");
+ fprintf(stderr, pat, arg1, arg2, arg3);
+ fprintf(stderr, ": %s\n", strerror(errnum));
+ my_exit(1);
+}
+
+/* Get a response from the user, somehow or other. */
+
+void
+ask(pat,arg1,arg2,arg3)
+char *pat;
+long arg1,arg2,arg3;
+{
+#ifndef WIN32
+ int ttyfd;
+ int r;
+ bool tty2 = isatty(2);
+
+ Sprintf(buf, pat, arg1, arg2, arg3);
+ Fflush(stderr);
+ write(2, buf, strlen(buf));
+ if (tty2) { /* might be redirected to a file */
+ r = read(2, buf, sizeof buf);
+ }
+ else if (isatty(1)) { /* this may be new file output */
+ Fflush(stdout);
+ write(1, buf, strlen(buf));
+ r = read(1, buf, sizeof buf);
+ }
+ else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
+ /* might be deleted or unwriteable */
+ write(ttyfd, buf, strlen(buf));
+ r = read(ttyfd, buf, sizeof buf);
+ Close(ttyfd);
+ }
+ else if (isatty(0)) { /* this is probably patch input */
+ Fflush(stdin);
+ write(0, buf, strlen(buf));
+ r = read(0, buf, sizeof buf);
+ }
+ else { /* no terminal at all--default it */
+ buf[0] = '\n';
+ r = 1;
+ }
+ if (r <= 0)
+ buf[0] = 0;
+ else
+ buf[r] = '\0';
+ if (!tty2)
+ say1(buf);
+#else
+ buf[0] = '\n'; buf[1] = '\0';
+#endif
+}
+#endif /* lint */
+
+/* How to handle certain events when not in a critical region. */
+
+void
+set_signals(reset)
+int reset;
+{
+#ifndef lint
+#ifdef VOIDSIG
+ static void (*hupval)(),(*intval)();
+#else
+ static int (*hupval)(),(*intval)();
+#endif
+
+ if (!reset) {
+#ifndef WIN32
+ hupval = signal(SIGHUP, SIG_IGN);
+ if (hupval != SIG_IGN)
+#ifdef VOIDSIG
+ hupval = my_exit;
+#else
+ hupval = (int(*)())my_exit;
+#endif
+#endif
+ intval = signal(SIGINT, SIG_IGN);
+ if (intval != SIG_IGN)
+#ifdef VOIDSIG
+ intval = my_exit;
+#else
+ intval = (int(*)())my_exit;
+#endif
+ }
+#ifndef WIN32
+ Signal(SIGHUP, hupval);
+#endif
+ Signal(SIGINT, intval);
+#endif
+}
+
+/* How to handle certain events when in a critical region. */
+
+void
+ignore_signals()
+{
+#ifndef lint
+#ifndef WIN32
+ Signal(SIGHUP, SIG_IGN);
+#endif
+ Signal(SIGINT, SIG_IGN);
+#endif
+}
+
+/* Make sure we'll have the directories to create a file.
+ If `striplast' is TRUE, ignore the last element of `filename'. */
+
+void
+makedirs(filename,striplast)
+Reg1 char *filename;
+bool striplast;
+{
+ char tmpbuf[256];
+ Reg2 char *s = tmpbuf;
+ char *dirv[20]; /* Point to the NULs between elements. */
+ Reg3 int i;
+ Reg4 int dirvp = 0; /* Number of finished entries in dirv. */
+
+ /* Copy `filename' into `tmpbuf' with a NUL instead of a slash
+ between the directories. */
+ while (*filename) {
+ if (*filename == '/') {
+ filename++;
+ dirv[dirvp++] = s;
+ *s++ = '\0';
+ }
+ else {
+ *s++ = *filename++;
+ }
+ }
+ *s = '\0';
+ dirv[dirvp] = s;
+ if (striplast)
+ dirvp--;
+ if (dirvp < 0)
+ return;
+
+ strcpy(buf, "mkdir");
+ s = buf;
+ for (i=0; i<=dirvp; i++) {
+ struct stat sbuf;
+
+ if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
+ while (*s) s++;
+ *s++ = ' ';
+ strcpy(s, tmpbuf);
+ }
+#ifndef WIN32
+ *dirv[i] = '/';
+#else
+ *dirv[i] = '\\';
+#endif
+ }
+ if (s != buf)
+ system(buf);
+}
+
+/* Make filenames more reasonable. */
+
+char *
+fetchname(at,strip_leading,assume_exists)
+char *at;
+int strip_leading;
+int assume_exists;
+{
+ char *fullname;
+ char *name;
+ Reg1 char *t;
+ char tmpbuf[200];
+ int sleading = strip_leading;
+
+ if (!at)
+ return Nullch;
+ while (isspace(*at))
+ at++;
+#ifdef DEBUGGING
+ if (debug & 128)
+ say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
+#endif
+ if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
+ return Nullch; /* against /dev/null. */
+ name = fullname = t = savestr(at);
+
+ /* Strip off up to `sleading' leading slashes and null terminate. */
+ for (; *t && !isspace(*t); t++)
+ if (*t == '/')
+ if (--sleading >= 0)
+ name = t+1;
+ *t = '\0';
+
+ /* If no -p option was given (957 is the default value!),
+ we were given a relative pathname,
+ and the leading directories that we just stripped off all exist,
+ put them back on. */
+ if (strip_leading == 957 && name != fullname && *fullname != '/') {
+ name[-1] = '\0';
+ if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
+ name[-1] = '/';
+ name=fullname;
+ }
+ }
+
+ name = savestr(name);
+ free(fullname);
+
+ if (stat(name, &filestat) && !assume_exists) {
+ char *filebase = basename(name);
+ int pathlen = filebase - name;
+
+ /* Put any leading path into `tmpbuf'. */
+ strncpy(tmpbuf, name, pathlen);
+
+#define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
+ if ( try("RCS/%s%s", filebase, RCSSUFFIX)
+ || try("RCS/%s" , filebase, 0)
+ || try( "%s%s", filebase, RCSSUFFIX)
+ || try("SCCS/%s%s", SCCSPREFIX, filebase)
+ || try( "%s%s", SCCSPREFIX, filebase))
+ return name;
+ free(name);
+ name = Nullch;
+ }
+
+ return name;
+}
diff --git a/xc/util/patch/util.h b/xc/util/patch/util.h
new file mode 100644
index 000000000..ad385c30c
--- /dev/null
+++ b/xc/util/patch/util.h
@@ -0,0 +1,88 @@
+/* oldHeader: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $
+ * $XConsortium: util.h,v 2.1 94/09/09 20:04:28 gildea Exp $
+ *
+ * Revision 2.0 86/09/17 15:40:06 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+/* and for those machine that can't handle a variable argument list */
+
+#ifdef CANVARARG
+
+#define say1 say
+#define say2 say
+#define say3 say
+#define say4 say
+#define ask1 ask
+#define ask2 ask
+#define ask3 ask
+#define ask4 ask
+#define fatal1 fatal
+#define fatal2 fatal
+#define fatal3 fatal
+#define fatal4 fatal
+#define pfatal1 pfatal
+#define pfatal2 pfatal
+#define pfatal3 pfatal
+#define pfatal4 pfatal
+
+#else /* hope they allow multi-line macro actual arguments */
+
+#ifdef lint
+
+#define say1(a) say(a, 0, 0, 0)
+#define say2(a,b) say(a, (b)==(b), 0, 0)
+#define say3(a,b,c) say(a, (b)==(b), (c)==(c), 0)
+#define say4(a,b,c,d) say(a, (b)==(b), (c)==(c), (d)==(d))
+#define ask1(a) ask(a, 0, 0, 0)
+#define ask2(a,b) ask(a, (b)==(b), 0, 0)
+#define ask3(a,b,c) ask(a, (b)==(b), (c)==(c), 0)
+#define ask4(a,b,c,d) ask(a, (b)==(b), (c)==(c), (d)==(d))
+#define fatal1(a) fatal(a, 0, 0, 0)
+#define fatal2(a,b) fatal(a, (b)==(b), 0, 0)
+#define fatal3(a,b,c) fatal(a, (b)==(b), (c)==(c), 0)
+#define fatal4(a,b,c,d) fatal(a, (b)==(b), (c)==(c), (d)==(d))
+#define pfatal1(a) pfatal(a, 0, 0, 0)
+#define pfatal2(a,b) pfatal(a, (b)==(b), 0, 0)
+#define pfatal3(a,b,c) pfatal(a, (b)==(b), (c)==(c), 0)
+#define pfatal4(a,b,c,d) pfatal(a, (b)==(b), (c)==(c), (d)==(d))
+
+#else /* lint */
+ /* if this doesn't work, try defining CANVARARG above */
+#define say1(a) say(a, Nullch, Nullch, Nullch)
+#define say2(a,b) say(a, b, Nullch, Nullch)
+#define say3(a,b,c) say(a, b, c, Nullch)
+#define say4 say
+#define ask1(a) ask(a, Nullch, Nullch, Nullch)
+#define ask2(a,b) ask(a, b, Nullch, Nullch)
+#define ask3(a,b,c) ask(a, b, c, Nullch)
+#define ask4 ask
+#define fatal1(a) fatal(a, Nullch, Nullch, Nullch)
+#define fatal2(a,b) fatal(a, b, Nullch, Nullch)
+#define fatal3(a,b,c) fatal(a, b, c, Nullch)
+#define fatal4 fatal
+#define pfatal1(a) pfatal(a, Nullch, Nullch, Nullch)
+#define pfatal2(a,b) pfatal(a, b, Nullch, Nullch)
+#define pfatal3(a,b,c) pfatal(a, b, c, Nullch)
+#define pfatal4 pfatal
+
+#endif /* lint */
+
+/* if neither of the above work, join all multi-line macro calls. */
+#endif
+
+EXT char serrbuf[BUFSIZ]; /* buffer for stderr */
+
+char *fetchname();
+int move_file();
+void copy_file();
+void say();
+void fatal();
+void pfatal();
+void ask();
+char *savestr();
+void set_signals();
+void ignore_signals();
+void makedirs();
+char *basename();
diff --git a/xc/util/patch/version.c b/xc/util/patch/version.c
new file mode 100644
index 000000000..86e86842a
--- /dev/null
+++ b/xc/util/patch/version.c
@@ -0,0 +1,25 @@
+/* oldHeader: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $
+ * $XConsortium: version.c,v 2.1 94/09/09 20:04:28 gildea Exp $
+ *
+ * Revision 2.0 86/09/17 15:40:11 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "INTERN.h"
+#include "patchlevel.h"
+#include "version.h"
+
+void my_exit();
+
+/* Print out the version number and die. */
+
+void
+version()
+{
+ fprintf(stderr, "Patch version 2.0, patch level %s\n", PATCHLEVEL);
+ my_exit(0);
+}
diff --git a/xc/util/patch/version.h b/xc/util/patch/version.h
new file mode 100644
index 000000000..bc249e0f8
--- /dev/null
+++ b/xc/util/patch/version.h
@@ -0,0 +1,9 @@
+/* oldHeader: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $
+ * $XConsortium: version.h,v 2.1 94/09/09 20:04:28 gildea Exp $
+ *
+ * Revision 2.0 86/09/17 15:40:14 lwall
+ * Baseline for netwide release.
+ *
+ */
+
+void version();
diff --git a/xc/util/patch/winnt.h b/xc/util/patch/winnt.h
new file mode 100644
index 000000000..3f45159f0
--- /dev/null
+++ b/xc/util/patch/winnt.h
@@ -0,0 +1,25 @@
+
+/* $XConsortium: winnt.h,v 1.1 94/09/09 20:27:49 kaleb Exp $ */
+
+
+#define stat _stat
+#define dev_t _dev_t
+#define ino_t _ino_t
+#define chdir _chdir
+#define chmod(p1,p2) _chmod(p1,_S_IWRITE)
+#define open _open
+#define close _close
+#define creat(p1,p2) _creat(p1,_S_IWRITE)
+#define fileno _fileno
+#define fstat _fstat
+#define isatty _isatty
+#define lseek _lseek
+#define mktemp _mktemp
+#define pclose _pclose
+#define popen _popen
+#define read _read
+#define write _write
+#define unlink _unlink
+#define sys_errlist _sys_errlist
+#define sys_nerr (*_sys_nerr_dll)
+